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:
commit
00ef48ff0d
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
BIN
tests/data/acpi/microvm/APIC.ioapic2
Normal file
BIN
tests/data/acpi/microvm/APIC.ioapic2
Normal file
Binary file not shown.
BIN
tests/data/acpi/microvm/DSDT.ioapic2
Normal file
BIN
tests/data/acpi/microvm/DSDT.ioapic2
Normal file
Binary file not shown.
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user