microvm: add support for second ioapic

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABCgAGBQJf0hD2AAoJEEy22O7T6HE4YR4QAKclgGrNwtnKaRRmkqzM1Neo
 R+vfbRlghZ5Uj7qt6i8B/WJ+BmDOOgOUXq+xUODPl7Bc03sBJBKoBJmjtbEKfQFu
 Vm1+gIrSEMsWT7t8KoHYj+piGJnUMu46G1iaQDURHVGTfRZoNyMHLw9+bTHLsznp
 jNAp5XnBgyFTvwn61whaXW57Zw3jm0OPtjxqd6PxCWgvLB7MEogO4P1+S8RpTWu3
 8h2J2kLFDY3iPBeENrxq33Ui2/3yQV19iVke0KzOhu0ncQ6QEHaQeAxXuiZBfplW
 8ZxxujbJnJgcsnZm6EOdDPlbqW/KkDtqztnz+B/yXrQU1R6esu535gtXFSyrGOVa
 n+EuVqDfTlfSUp4RVnk1qZqwC6Y/ZPyj940DGgWA1E+FNyjuuxkr+n72ZUzFkvT/
 epWsIbStvSjV222wAQ9+f061wd9dqj58Nm/X4MEY+Omg+6Poq3CBafIKh7lTz6cr
 4nMuqZ1MReONc52Cgz/6amo7wTJ8+wl68+WnxxXPqdoSz1y9NzqXbF/8bnEtUhMz
 UAtZHGAtVP+MiNJf3bpXMDwBVcDedyIT0Jied/NWJ3yv0+OcekGCBOc6+gJsSS61
 mJc5t0kJim2dE0Vkzi5+95HeGyCPoPqdDf56gU123TJLJAOAw/htenVpMr+O9znV
 MfmgjNYMeDKDr9dyDdcN
 =u8Kq
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kraxel/tags/microvm-20201210-pull-request' into staging

microvm: add support for second ioapic

# gpg: Signature made Thu 10 Dec 2020 12:13:42 GMT
# gpg:                using RSA key 4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full]
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>" [full]
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full]
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* remotes/kraxel/tags/microvm-20201210-pull-request:
  tests/acpi: disallow updates for expected data files
  tests/acpi: update expected data files
  tests/acpi: add ioapic2=on test for microvm
  tests/acpi: add data files for ioapic2 test variant
  tests/acpi: allow updates for expected data files
  microvm: add second ioapic
  microvm: drop microvm_gsi_handler()
  microvm: make pcie irq base runtime changeable
  microvm: make number of virtio transports runtime changeable
  x86: add support for second ioapic
  x86: rewrite gsi_handler()

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-12-10 12:53:01 +00:00
commit 00ef48ff0d
10 changed files with 128 additions and 32 deletions

View File

@ -103,6 +103,16 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker,
io_apic->address = cpu_to_le32(IO_APIC_DEFAULT_ADDRESS);
io_apic->interrupt = cpu_to_le32(0);
if (x86ms->ioapic2) {
AcpiMadtIoApic *io_apic2;
io_apic2 = acpi_data_push(table_data, sizeof *io_apic);
io_apic2->type = ACPI_APIC_IO;
io_apic2->length = sizeof(*io_apic);
io_apic2->io_apic_id = ACPI_BUILD_IOAPIC_ID + 1;
io_apic2->address = cpu_to_le32(IO_APIC_SECONDARY_ADDRESS);
io_apic2->interrupt = cpu_to_le32(IO_APIC_SECONDARY_IRQBASE);
}
if (x86ms->apic_xrupt_override) {
intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr);
intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE;

View File

@ -96,13 +96,6 @@ static void microvm_set_rtc(MicrovmMachineState *mms, ISADevice *s)
rtc_set_memory(s, 0x5d, val >> 16);
}
static void microvm_gsi_handler(void *opaque, int n, int level)
{
GSIState *s = opaque;
qemu_set_irq(s->ioapic_irq[n], level);
}
static void create_gpex(MicrovmMachineState *mms)
{
X86MachineState *x86ms = X86_MACHINE(mms);
@ -152,34 +145,56 @@ static void create_gpex(MicrovmMachineState *mms)
}
}
static int microvm_ioapics(MicrovmMachineState *mms)
{
if (!x86_machine_is_acpi_enabled(X86_MACHINE(mms))) {
return 1;
}
if (mms->ioapic2 == ON_OFF_AUTO_OFF) {
return 1;
}
return 2;
}
static void microvm_devices_init(MicrovmMachineState *mms)
{
X86MachineState *x86ms = X86_MACHINE(mms);
ISABus *isa_bus;
ISADevice *rtc_state;
GSIState *gsi_state;
int ioapics;
int i;
/* Core components */
ioapics = microvm_ioapics(mms);
gsi_state = g_malloc0(sizeof(*gsi_state));
if (mms->pic == ON_OFF_AUTO_ON || mms->pic == ON_OFF_AUTO_AUTO) {
x86ms->gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
} else {
x86ms->gsi = qemu_allocate_irqs(microvm_gsi_handler,
gsi_state, GSI_NUM_PINS);
}
x86ms->gsi = qemu_allocate_irqs(gsi_handler, gsi_state,
IOAPIC_NUM_PINS * ioapics);
isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(),
&error_abort);
isa_bus_irqs(isa_bus, x86ms->gsi);
ioapic_init_gsi(gsi_state, "machine");
if (ioapics > 1) {
x86ms->ioapic2 = ioapic_init_secondary(gsi_state);
}
kvmclock_create(true);
mms->virtio_irq_base = x86_machine_is_acpi_enabled(x86ms) ? 16 : 5;
for (i = 0; i < VIRTIO_NUM_TRANSPORTS; i++) {
mms->virtio_irq_base = 5;
mms->virtio_num_transports = 8;
if (x86ms->ioapic2) {
mms->pcie_irq_base = 16; /* 16 -> 19 */
/* use second ioapic (24 -> 47) for virtio-mmio irq lines */
mms->virtio_irq_base = IO_APIC_SECONDARY_IRQBASE;
mms->virtio_num_transports = IOAPIC_NUM_PINS;
} else if (x86_machine_is_acpi_enabled(x86ms)) {
mms->pcie_irq_base = 12; /* 12 -> 15 */
mms->virtio_irq_base = 16; /* 16 -> 23 */
}
for (i = 0; i < mms->virtio_num_transports; i++) {
sysbus_create_simple("virtio-mmio",
VIRTIO_MMIO_BASE + i * 512,
x86ms->gsi[mms->virtio_irq_base + i]);
@ -221,12 +236,12 @@ static void microvm_devices_init(MicrovmMachineState *mms)
mms->gpex.mmio32.size = PCIE_MMIO_SIZE;
mms->gpex.ecam.base = PCIE_ECAM_BASE;
mms->gpex.ecam.size = PCIE_ECAM_SIZE;
mms->gpex.irq = PCIE_IRQ_BASE;
mms->gpex.irq = mms->pcie_irq_base;
create_gpex(mms);
x86ms->pci_irq_mask = ((1 << (PCIE_IRQ_BASE + 0)) |
(1 << (PCIE_IRQ_BASE + 1)) |
(1 << (PCIE_IRQ_BASE + 2)) |
(1 << (PCIE_IRQ_BASE + 3)));
x86ms->pci_irq_mask = ((1 << (mms->pcie_irq_base + 0)) |
(1 << (mms->pcie_irq_base + 1)) |
(1 << (mms->pcie_irq_base + 2)) |
(1 << (mms->pcie_irq_base + 3)));
} else {
x86ms->pci_irq_mask = 0;
}
@ -550,6 +565,23 @@ static void microvm_machine_set_pcie(Object *obj, Visitor *v, const char *name,
visit_type_OnOffAuto(v, name, &mms->pcie, errp);
}
static void microvm_machine_get_ioapic2(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
MicrovmMachineState *mms = MICROVM_MACHINE(obj);
OnOffAuto ioapic2 = mms->ioapic2;
visit_type_OnOffAuto(v, name, &ioapic2, errp);
}
static void microvm_machine_set_ioapic2(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
MicrovmMachineState *mms = MICROVM_MACHINE(obj);
visit_type_OnOffAuto(v, name, &mms->ioapic2, errp);
}
static bool microvm_machine_get_isa_serial(Object *obj, Error **errp)
{
MicrovmMachineState *mms = MICROVM_MACHINE(obj);
@ -626,6 +658,7 @@ static void microvm_machine_initfn(Object *obj)
mms->pit = ON_OFF_AUTO_AUTO;
mms->rtc = ON_OFF_AUTO_AUTO;
mms->pcie = ON_OFF_AUTO_AUTO;
mms->ioapic2 = ON_OFF_AUTO_AUTO;
mms->isa_serial = true;
mms->option_roms = true;
mms->auto_kernel_cmdline = true;
@ -699,6 +732,13 @@ static void microvm_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, MICROVM_MACHINE_PCIE,
"Enable PCIe");
object_class_property_add(oc, MICROVM_MACHINE_IOAPIC2, "OnOffAuto",
microvm_machine_get_ioapic2,
microvm_machine_set_ioapic2,
NULL, NULL);
object_class_property_set_description(oc, MICROVM_MACHINE_IOAPIC2,
"Enable second IO-APIC");
object_class_property_add_bool(oc, MICROVM_MACHINE_ISA_SERIAL,
microvm_machine_get_isa_serial,
microvm_machine_set_isa_serial);

View File

@ -588,11 +588,21 @@ void gsi_handler(void *opaque, int n, int level)
GSIState *s = opaque;
trace_x86_gsi_interrupt(n, level);
if (n < ISA_NUM_IRQS) {
/* Under KVM, Kernel will forward to both PIC and IOAPIC */
qemu_set_irq(s->i8259_irq[n], level);
switch (n) {
case 0 ... ISA_NUM_IRQS - 1:
if (s->i8259_irq[n]) {
/* Under KVM, Kernel will forward to both PIC and IOAPIC */
qemu_set_irq(s->i8259_irq[n], level);
}
/* fall through */
case ISA_NUM_IRQS ... IOAPIC_NUM_PINS - 1:
qemu_set_irq(s->ioapic_irq[n], level);
break;
case IO_APIC_SECONDARY_IRQBASE
... IO_APIC_SECONDARY_IRQBASE + IOAPIC_NUM_PINS - 1:
qemu_set_irq(s->ioapic2_irq[n - IO_APIC_SECONDARY_IRQBASE], level);
break;
}
qemu_set_irq(s->ioapic_irq[n], level);
}
void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name)
@ -618,6 +628,23 @@ void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name)
}
}
DeviceState *ioapic_init_secondary(GSIState *gsi_state)
{
DeviceState *dev;
SysBusDevice *d;
unsigned int i;
dev = qdev_new(TYPE_IOAPIC);
d = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(d, &error_fatal);
sysbus_mmio_map(d, 0, IO_APIC_SECONDARY_ADDRESS);
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
gsi_state->ioapic2_irq[i] = qdev_get_gpio_in(dev, i);
}
return dev;
}
struct setup_data {
uint64_t next;
uint32_t type;

View File

@ -22,6 +22,8 @@
#define IOAPIC_NUM_PINS 24
#define IO_APIC_DEFAULT_ADDRESS 0xfec00000
#define IO_APIC_SECONDARY_ADDRESS (IO_APIC_DEFAULT_ADDRESS + 0x10000)
#define IO_APIC_SECONDARY_IRQBASE 24 /* primary 0 -> 23, secondary 24 -> 47 */
#define TYPE_KVM_IOAPIC "kvm-ioapic"
#define TYPE_IOAPIC "ioapic"

View File

@ -27,7 +27,7 @@
#include "qemu/notify.h"
#include "qom/object.h"
#define MAX_IOAPICS 1
#define MAX_IOAPICS 2
#define IOAPIC_LVT_DEST_SHIFT 56
#define IOAPIC_LVT_DEST_IDX_SHIFT 48

View File

@ -52,7 +52,6 @@
/* Platform virtio definitions */
#define VIRTIO_MMIO_BASE 0xfeb00000
#define VIRTIO_NUM_TRANSPORTS 8
#define VIRTIO_CMDLINE_MAXLEN 64
#define GED_MMIO_BASE 0xfea00000
@ -67,13 +66,13 @@
#define PCIE_MMIO_SIZE 0x20000000
#define PCIE_ECAM_BASE 0xe0000000
#define PCIE_ECAM_SIZE 0x10000000
#define PCIE_IRQ_BASE 12
/* Machine type options */
#define MICROVM_MACHINE_PIT "pit"
#define MICROVM_MACHINE_PIC "pic"
#define MICROVM_MACHINE_RTC "rtc"
#define MICROVM_MACHINE_PCIE "pcie"
#define MICROVM_MACHINE_IOAPIC2 "ioapic2"
#define MICROVM_MACHINE_ISA_SERIAL "isa-serial"
#define MICROVM_MACHINE_OPTION_ROMS "x-option-roms"
#define MICROVM_MACHINE_AUTO_KERNEL_CMDLINE "auto-kernel-cmdline"
@ -92,12 +91,15 @@ struct MicrovmMachineState {
OnOffAuto pit;
OnOffAuto rtc;
OnOffAuto pcie;
OnOffAuto ioapic2;
bool isa_serial;
bool option_roms;
bool auto_kernel_cmdline;
/* Machine state */
uint32_t pcie_irq_base;
uint32_t virtio_irq_base;
uint32_t virtio_num_transports;
bool kernel_cmdline_fixed;
Notifier machine_done;
Notifier powerdown_req;

View File

@ -50,6 +50,7 @@ struct X86MachineState {
ISADevice *rtc;
FWCfgState *fw_cfg;
qemu_irq *gsi;
DeviceState *ioapic2;
GMappedFile *initrd_mapped_file;
HotplugHandler *acpi_dev;
@ -120,10 +121,12 @@ bool x86_machine_is_acpi_enabled(const X86MachineState *x86ms);
typedef struct GSIState {
qemu_irq i8259_irq[ISA_NUM_IRQS];
qemu_irq ioapic_irq[IOAPIC_NUM_PINS];
qemu_irq ioapic2_irq[IOAPIC_NUM_PINS];
} GSIState;
qemu_irq x86_allocate_cpu_irq(void);
void gsi_handler(void *opaque, int n, int level);
void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name);
DeviceState *ioapic_init_secondary(GSIState *gsi_state);
#endif

Binary file not shown.

Binary file not shown.

View File

@ -1124,7 +1124,7 @@ static void test_acpi_microvm_tcg(void)
test_data data;
test_acpi_microvm_prepare(&data);
test_acpi_one(" -machine microvm,acpi=on,rtc=off",
test_acpi_one(" -machine microvm,acpi=on,ioapic2=off,rtc=off",
&data);
free_test_data(&data);
}
@ -1135,7 +1135,7 @@ static void test_acpi_microvm_usb_tcg(void)
test_acpi_microvm_prepare(&data);
data.variant = ".usb";
test_acpi_one(" -machine microvm,acpi=on,usb=on,rtc=off",
test_acpi_one(" -machine microvm,acpi=on,ioapic2=off,usb=on,rtc=off",
&data);
free_test_data(&data);
}
@ -1146,7 +1146,7 @@ static void test_acpi_microvm_rtc_tcg(void)
test_acpi_microvm_prepare(&data);
data.variant = ".rtc";
test_acpi_one(" -machine microvm,acpi=on,rtc=on",
test_acpi_one(" -machine microvm,acpi=on,ioapic2=off,rtc=on",
&data);
free_test_data(&data);
}
@ -1158,7 +1158,18 @@ static void test_acpi_microvm_pcie_tcg(void)
test_acpi_microvm_prepare(&data);
data.variant = ".pcie";
data.tcg_only = true; /* need constant host-phys-bits */
test_acpi_one(" -machine microvm,acpi=on,rtc=off,pcie=on",
test_acpi_one(" -machine microvm,acpi=on,ioapic2=off,rtc=off,pcie=on",
&data);
free_test_data(&data);
}
static void test_acpi_microvm_ioapic2_tcg(void)
{
test_data data;
test_acpi_microvm_prepare(&data);
data.variant = ".ioapic2";
test_acpi_one(" -machine microvm,acpi=on,ioapic2=on,rtc=off",
&data);
free_test_data(&data);
}
@ -1323,6 +1334,7 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/microvm", test_acpi_microvm_tcg);
qtest_add_func("acpi/microvm/usb", test_acpi_microvm_usb_tcg);
qtest_add_func("acpi/microvm/rtc", test_acpi_microvm_rtc_tcg);
qtest_add_func("acpi/microvm/ioapic2", test_acpi_microvm_ioapic2_tcg);
if (strcmp(arch, "x86_64") == 0) {
qtest_add_func("acpi/microvm/pcie", test_acpi_microvm_pcie_tcg);
}