qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

microvm.c (24843B)


      1 /*
      2  * Copyright (c) 2018 Intel Corporation
      3  * Copyright (c) 2019 Red Hat, Inc.
      4  *
      5  * This program is free software; you can redistribute it and/or modify it
      6  * under the terms and conditions of the GNU General Public License,
      7  * version 2 or later, as published by the Free Software Foundation.
      8  *
      9  * This program is distributed in the hope it will be useful, but WITHOUT
     10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     12  * more details.
     13  *
     14  * You should have received a copy of the GNU General Public License along with
     15  * this program.  If not, see <http://www.gnu.org/licenses/>.
     16  */
     17 
     18 #include "qemu/osdep.h"
     19 #include "qemu/error-report.h"
     20 #include "qemu/cutils.h"
     21 #include "qemu/units.h"
     22 #include "qapi/error.h"
     23 #include "qapi/visitor.h"
     24 #include "qapi/qapi-visit-common.h"
     25 #include "sysemu/sysemu.h"
     26 #include "sysemu/cpus.h"
     27 #include "sysemu/numa.h"
     28 #include "sysemu/reset.h"
     29 #include "sysemu/runstate.h"
     30 #include "acpi-microvm.h"
     31 #include "microvm-dt.h"
     32 
     33 #include "hw/loader.h"
     34 #include "hw/irq.h"
     35 #include "hw/kvm/clock.h"
     36 #include "hw/i386/microvm.h"
     37 #include "hw/i386/x86.h"
     38 #include "target/i386/cpu.h"
     39 #include "hw/intc/i8259.h"
     40 #include "hw/timer/i8254.h"
     41 #include "hw/rtc/mc146818rtc.h"
     42 #include "hw/char/serial.h"
     43 #include "hw/display/ramfb.h"
     44 #include "hw/i386/topology.h"
     45 #include "hw/i386/e820_memory_layout.h"
     46 #include "hw/i386/fw_cfg.h"
     47 #include "hw/virtio/virtio-mmio.h"
     48 #include "hw/acpi/acpi.h"
     49 #include "hw/acpi/generic_event_device.h"
     50 #include "hw/pci-host/gpex.h"
     51 #include "hw/usb/xhci.h"
     52 
     53 #include "elf.h"
     54 #include "kvm/kvm_i386.h"
     55 #include "hw/xen/start_info.h"
     56 
     57 #define MICROVM_QBOOT_FILENAME "qboot.rom"
     58 #define MICROVM_BIOS_FILENAME  "bios-microvm.bin"
     59 
     60 static void microvm_set_rtc(MicrovmMachineState *mms, ISADevice *s)
     61 {
     62     X86MachineState *x86ms = X86_MACHINE(mms);
     63     int val;
     64 
     65     val = MIN(x86ms->below_4g_mem_size / KiB, 640);
     66     rtc_set_memory(s, 0x15, val);
     67     rtc_set_memory(s, 0x16, val >> 8);
     68     /* extended memory (next 64MiB) */
     69     if (x86ms->below_4g_mem_size > 1 * MiB) {
     70         val = (x86ms->below_4g_mem_size - 1 * MiB) / KiB;
     71     } else {
     72         val = 0;
     73     }
     74     if (val > 65535) {
     75         val = 65535;
     76     }
     77     rtc_set_memory(s, 0x17, val);
     78     rtc_set_memory(s, 0x18, val >> 8);
     79     rtc_set_memory(s, 0x30, val);
     80     rtc_set_memory(s, 0x31, val >> 8);
     81     /* memory between 16MiB and 4GiB */
     82     if (x86ms->below_4g_mem_size > 16 * MiB) {
     83         val = (x86ms->below_4g_mem_size - 16 * MiB) / (64 * KiB);
     84     } else {
     85         val = 0;
     86     }
     87     if (val > 65535) {
     88         val = 65535;
     89     }
     90     rtc_set_memory(s, 0x34, val);
     91     rtc_set_memory(s, 0x35, val >> 8);
     92     /* memory above 4GiB */
     93     val = x86ms->above_4g_mem_size / 65536;
     94     rtc_set_memory(s, 0x5b, val);
     95     rtc_set_memory(s, 0x5c, val >> 8);
     96     rtc_set_memory(s, 0x5d, val >> 16);
     97 }
     98 
     99 static void create_gpex(MicrovmMachineState *mms)
    100 {
    101     X86MachineState *x86ms = X86_MACHINE(mms);
    102     MemoryRegion *mmio32_alias;
    103     MemoryRegion *mmio64_alias;
    104     MemoryRegion *mmio_reg;
    105     MemoryRegion *ecam_alias;
    106     MemoryRegion *ecam_reg;
    107     DeviceState *dev;
    108     int i;
    109 
    110     dev = qdev_new(TYPE_GPEX_HOST);
    111     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
    112 
    113     /* Map only the first size_ecam bytes of ECAM space */
    114     ecam_alias = g_new0(MemoryRegion, 1);
    115     ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
    116     memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
    117                              ecam_reg, 0, mms->gpex.ecam.size);
    118     memory_region_add_subregion(get_system_memory(),
    119                                 mms->gpex.ecam.base, ecam_alias);
    120 
    121     /* Map the MMIO window into system address space so as to expose
    122      * the section of PCI MMIO space which starts at the same base address
    123      * (ie 1:1 mapping for that part of PCI MMIO space visible through
    124      * the window).
    125      */
    126     mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
    127     if (mms->gpex.mmio32.size) {
    128         mmio32_alias = g_new0(MemoryRegion, 1);
    129         memory_region_init_alias(mmio32_alias, OBJECT(dev), "pcie-mmio32", mmio_reg,
    130                                  mms->gpex.mmio32.base, mms->gpex.mmio32.size);
    131         memory_region_add_subregion(get_system_memory(),
    132                                     mms->gpex.mmio32.base, mmio32_alias);
    133     }
    134     if (mms->gpex.mmio64.size) {
    135         mmio64_alias = g_new0(MemoryRegion, 1);
    136         memory_region_init_alias(mmio64_alias, OBJECT(dev), "pcie-mmio64", mmio_reg,
    137                                  mms->gpex.mmio64.base, mms->gpex.mmio64.size);
    138         memory_region_add_subregion(get_system_memory(),
    139                                     mms->gpex.mmio64.base, mmio64_alias);
    140     }
    141 
    142     for (i = 0; i < GPEX_NUM_IRQS; i++) {
    143         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
    144                            x86ms->gsi[mms->gpex.irq + i]);
    145     }
    146 }
    147 
    148 static int microvm_ioapics(MicrovmMachineState *mms)
    149 {
    150     if (!x86_machine_is_acpi_enabled(X86_MACHINE(mms))) {
    151         return 1;
    152     }
    153     if (mms->ioapic2 == ON_OFF_AUTO_OFF) {
    154         return 1;
    155     }
    156     return 2;
    157 }
    158 
    159 static void microvm_devices_init(MicrovmMachineState *mms)
    160 {
    161     const char *default_firmware;
    162     X86MachineState *x86ms = X86_MACHINE(mms);
    163     ISABus *isa_bus;
    164     ISADevice *rtc_state;
    165     GSIState *gsi_state;
    166     int ioapics;
    167     int i;
    168 
    169     /* Core components */
    170     ioapics = microvm_ioapics(mms);
    171     gsi_state = g_malloc0(sizeof(*gsi_state));
    172     x86ms->gsi = qemu_allocate_irqs(gsi_handler, gsi_state,
    173                                     IOAPIC_NUM_PINS * ioapics);
    174 
    175     isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(),
    176                           &error_abort);
    177     isa_bus_irqs(isa_bus, x86ms->gsi);
    178 
    179     ioapic_init_gsi(gsi_state, "machine");
    180     if (ioapics > 1) {
    181         x86ms->ioapic2 = ioapic_init_secondary(gsi_state);
    182     }
    183 
    184     kvmclock_create(true);
    185 
    186     mms->virtio_irq_base = 5;
    187     mms->virtio_num_transports = 8;
    188     if (x86ms->ioapic2) {
    189         mms->pcie_irq_base = 16;    /* 16 -> 19 */
    190         /* use second ioapic (24 -> 47) for virtio-mmio irq lines */
    191         mms->virtio_irq_base = IO_APIC_SECONDARY_IRQBASE;
    192         mms->virtio_num_transports = IOAPIC_NUM_PINS;
    193     } else if (x86_machine_is_acpi_enabled(x86ms)) {
    194         mms->pcie_irq_base = 12;    /* 12 -> 15 */
    195         mms->virtio_irq_base = 16;  /* 16 -> 23 */
    196     }
    197 
    198     for (i = 0; i < mms->virtio_num_transports; i++) {
    199         sysbus_create_simple("virtio-mmio",
    200                              VIRTIO_MMIO_BASE + i * 512,
    201                              x86ms->gsi[mms->virtio_irq_base + i]);
    202     }
    203 
    204     /* Optional and legacy devices */
    205     if (x86_machine_is_acpi_enabled(x86ms)) {
    206         DeviceState *dev = qdev_new(TYPE_ACPI_GED_X86);
    207         qdev_prop_set_uint32(dev, "ged-event", ACPI_GED_PWR_DOWN_EVT);
    208         sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, GED_MMIO_BASE);
    209         /* sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, GED_MMIO_BASE_MEMHP); */
    210         sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, GED_MMIO_BASE_REGS);
    211         sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
    212                            x86ms->gsi[GED_MMIO_IRQ]);
    213         sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
    214         x86ms->acpi_dev = HOTPLUG_HANDLER(dev);
    215     }
    216 
    217     if (x86_machine_is_acpi_enabled(x86ms) && machine_usb(MACHINE(mms))) {
    218         DeviceState *dev = qdev_new(TYPE_XHCI_SYSBUS);
    219         qdev_prop_set_uint32(dev, "intrs", 1);
    220         qdev_prop_set_uint32(dev, "slots", XHCI_MAXSLOTS);
    221         qdev_prop_set_uint32(dev, "p2", 8);
    222         qdev_prop_set_uint32(dev, "p3", 8);
    223         sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
    224         sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MICROVM_XHCI_BASE);
    225         sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
    226                            x86ms->gsi[MICROVM_XHCI_IRQ]);
    227     }
    228 
    229     if (x86_machine_is_acpi_enabled(x86ms) && mms->pcie == ON_OFF_AUTO_ON) {
    230         /* use topmost 25% of the address space available */
    231         hwaddr phys_size = (hwaddr)1 << X86_CPU(first_cpu)->phys_bits;
    232         if (phys_size > 0x1000000ll) {
    233             mms->gpex.mmio64.size = phys_size / 4;
    234             mms->gpex.mmio64.base = phys_size - mms->gpex.mmio64.size;
    235         }
    236         mms->gpex.mmio32.base = PCIE_MMIO_BASE;
    237         mms->gpex.mmio32.size = PCIE_MMIO_SIZE;
    238         mms->gpex.ecam.base   = PCIE_ECAM_BASE;
    239         mms->gpex.ecam.size   = PCIE_ECAM_SIZE;
    240         mms->gpex.irq         = mms->pcie_irq_base;
    241         create_gpex(mms);
    242         x86ms->pci_irq_mask = ((1 << (mms->pcie_irq_base + 0)) |
    243                                (1 << (mms->pcie_irq_base + 1)) |
    244                                (1 << (mms->pcie_irq_base + 2)) |
    245                                (1 << (mms->pcie_irq_base + 3)));
    246     } else {
    247         x86ms->pci_irq_mask = 0;
    248     }
    249 
    250     if (x86ms->pic == ON_OFF_AUTO_ON || x86ms->pic == ON_OFF_AUTO_AUTO) {
    251         qemu_irq *i8259;
    252 
    253         i8259 = i8259_init(isa_bus, x86_allocate_cpu_irq());
    254         for (i = 0; i < ISA_NUM_IRQS; i++) {
    255             gsi_state->i8259_irq[i] = i8259[i];
    256         }
    257         g_free(i8259);
    258     }
    259 
    260     if (x86ms->pit == ON_OFF_AUTO_ON || x86ms->pit == ON_OFF_AUTO_AUTO) {
    261         if (kvm_pit_in_kernel()) {
    262             kvm_pit_init(isa_bus, 0x40);
    263         } else {
    264             i8254_pit_init(isa_bus, 0x40, 0, NULL);
    265         }
    266     }
    267 
    268     if (mms->rtc == ON_OFF_AUTO_ON ||
    269         (mms->rtc == ON_OFF_AUTO_AUTO && !kvm_enabled())) {
    270         rtc_state = mc146818_rtc_init(isa_bus, 2000, NULL);
    271         microvm_set_rtc(mms, rtc_state);
    272     }
    273 
    274     if (mms->isa_serial) {
    275         serial_hds_isa_init(isa_bus, 0, 1);
    276     }
    277 
    278     default_firmware = x86_machine_is_acpi_enabled(x86ms)
    279             ? MICROVM_BIOS_FILENAME
    280             : MICROVM_QBOOT_FILENAME;
    281     x86_bios_rom_init(MACHINE(mms), default_firmware, get_system_memory(), true);
    282 }
    283 
    284 static void microvm_memory_init(MicrovmMachineState *mms)
    285 {
    286     MachineState *machine = MACHINE(mms);
    287     X86MachineState *x86ms = X86_MACHINE(mms);
    288     MemoryRegion *ram_below_4g, *ram_above_4g;
    289     MemoryRegion *system_memory = get_system_memory();
    290     FWCfgState *fw_cfg;
    291     ram_addr_t lowmem = 0xc0000000; /* 3G */
    292     int i;
    293 
    294     if (machine->ram_size > lowmem) {
    295         x86ms->above_4g_mem_size = machine->ram_size - lowmem;
    296         x86ms->below_4g_mem_size = lowmem;
    297     } else {
    298         x86ms->above_4g_mem_size = 0;
    299         x86ms->below_4g_mem_size = machine->ram_size;
    300     }
    301 
    302     ram_below_4g = g_malloc(sizeof(*ram_below_4g));
    303     memory_region_init_alias(ram_below_4g, NULL, "ram-below-4g", machine->ram,
    304                              0, x86ms->below_4g_mem_size);
    305     memory_region_add_subregion(system_memory, 0, ram_below_4g);
    306 
    307     e820_add_entry(0, x86ms->below_4g_mem_size, E820_RAM);
    308 
    309     if (x86ms->above_4g_mem_size > 0) {
    310         ram_above_4g = g_malloc(sizeof(*ram_above_4g));
    311         memory_region_init_alias(ram_above_4g, NULL, "ram-above-4g",
    312                                  machine->ram,
    313                                  x86ms->below_4g_mem_size,
    314                                  x86ms->above_4g_mem_size);
    315         memory_region_add_subregion(system_memory, 0x100000000ULL,
    316                                     ram_above_4g);
    317         e820_add_entry(0x100000000ULL, x86ms->above_4g_mem_size, E820_RAM);
    318     }
    319 
    320     fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4,
    321                                 &address_space_memory);
    322 
    323     fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, machine->smp.cpus);
    324     fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, machine->smp.max_cpus);
    325     fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)machine->ram_size);
    326     fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, 1);
    327     fw_cfg_add_file(fw_cfg, "etc/e820", e820_table,
    328                     sizeof(struct e820_entry) * e820_get_num_entries());
    329 
    330     rom_set_fw(fw_cfg);
    331 
    332     if (machine->kernel_filename != NULL) {
    333         x86_load_linux(x86ms, fw_cfg, 0, true, false);
    334     }
    335 
    336     if (mms->option_roms) {
    337         for (i = 0; i < nb_option_roms; i++) {
    338             rom_add_option(option_rom[i].name, option_rom[i].bootindex);
    339         }
    340     }
    341 
    342     x86ms->fw_cfg = fw_cfg;
    343     x86ms->ioapic_as = &address_space_memory;
    344 }
    345 
    346 static gchar *microvm_get_mmio_cmdline(gchar *name, uint32_t virtio_irq_base)
    347 {
    348     gchar *cmdline;
    349     gchar *separator;
    350     long int index;
    351     int ret;
    352 
    353     separator = g_strrstr(name, ".");
    354     if (!separator) {
    355         return NULL;
    356     }
    357 
    358     if (qemu_strtol(separator + 1, NULL, 10, &index) != 0) {
    359         return NULL;
    360     }
    361 
    362     cmdline = g_malloc0(VIRTIO_CMDLINE_MAXLEN);
    363     ret = g_snprintf(cmdline, VIRTIO_CMDLINE_MAXLEN,
    364                      " virtio_mmio.device=512@0x%lx:%ld",
    365                      VIRTIO_MMIO_BASE + index * 512,
    366                      virtio_irq_base + index);
    367     if (ret < 0 || ret >= VIRTIO_CMDLINE_MAXLEN) {
    368         g_free(cmdline);
    369         return NULL;
    370     }
    371 
    372     return cmdline;
    373 }
    374 
    375 static void microvm_fix_kernel_cmdline(MachineState *machine)
    376 {
    377     X86MachineState *x86ms = X86_MACHINE(machine);
    378     MicrovmMachineState *mms = MICROVM_MACHINE(machine);
    379     BusState *bus;
    380     BusChild *kid;
    381     char *cmdline;
    382 
    383     /*
    384      * Find MMIO transports with attached devices, and add them to the kernel
    385      * command line.
    386      *
    387      * Yes, this is a hack, but one that heavily improves the UX without
    388      * introducing any significant issues.
    389      */
    390     cmdline = g_strdup(machine->kernel_cmdline);
    391     bus = sysbus_get_default();
    392     QTAILQ_FOREACH(kid, &bus->children, sibling) {
    393         DeviceState *dev = kid->child;
    394         ObjectClass *class = object_get_class(OBJECT(dev));
    395 
    396         if (class == object_class_by_name(TYPE_VIRTIO_MMIO)) {
    397             VirtIOMMIOProxy *mmio = VIRTIO_MMIO(OBJECT(dev));
    398             VirtioBusState *mmio_virtio_bus = &mmio->bus;
    399             BusState *mmio_bus = &mmio_virtio_bus->parent_obj;
    400 
    401             if (!QTAILQ_EMPTY(&mmio_bus->children)) {
    402                 gchar *mmio_cmdline = microvm_get_mmio_cmdline
    403                     (mmio_bus->name, mms->virtio_irq_base);
    404                 if (mmio_cmdline) {
    405                     char *newcmd = g_strjoin(NULL, cmdline, mmio_cmdline, NULL);
    406                     g_free(mmio_cmdline);
    407                     g_free(cmdline);
    408                     cmdline = newcmd;
    409                 }
    410             }
    411         }
    412     }
    413 
    414     fw_cfg_modify_i32(x86ms->fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(cmdline) + 1);
    415     fw_cfg_modify_string(x86ms->fw_cfg, FW_CFG_CMDLINE_DATA, cmdline);
    416 
    417     g_free(cmdline);
    418 }
    419 
    420 static void microvm_device_pre_plug_cb(HotplugHandler *hotplug_dev,
    421                                        DeviceState *dev, Error **errp)
    422 {
    423     X86CPU *cpu = X86_CPU(dev);
    424 
    425     cpu->host_phys_bits = true; /* need reliable phys-bits */
    426     x86_cpu_pre_plug(hotplug_dev, dev, errp);
    427 }
    428 
    429 static void microvm_device_plug_cb(HotplugHandler *hotplug_dev,
    430                                    DeviceState *dev, Error **errp)
    431 {
    432     x86_cpu_plug(hotplug_dev, dev, errp);
    433 }
    434 
    435 static void microvm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
    436                                              DeviceState *dev, Error **errp)
    437 {
    438     error_setg(errp, "unplug not supported by microvm");
    439 }
    440 
    441 static void microvm_device_unplug_cb(HotplugHandler *hotplug_dev,
    442                                      DeviceState *dev, Error **errp)
    443 {
    444     error_setg(errp, "unplug not supported by microvm");
    445 }
    446 
    447 static HotplugHandler *microvm_get_hotplug_handler(MachineState *machine,
    448                                                    DeviceState *dev)
    449 {
    450     if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
    451         return HOTPLUG_HANDLER(machine);
    452     }
    453     return NULL;
    454 }
    455 
    456 static void microvm_machine_state_init(MachineState *machine)
    457 {
    458     MicrovmMachineState *mms = MICROVM_MACHINE(machine);
    459     X86MachineState *x86ms = X86_MACHINE(machine);
    460 
    461     microvm_memory_init(mms);
    462 
    463     x86_cpus_init(x86ms, CPU_VERSION_LATEST);
    464 
    465     microvm_devices_init(mms);
    466 }
    467 
    468 static void microvm_machine_reset(MachineState *machine, ShutdownCause reason)
    469 {
    470     MicrovmMachineState *mms = MICROVM_MACHINE(machine);
    471     CPUState *cs;
    472     X86CPU *cpu;
    473 
    474     if (!x86_machine_is_acpi_enabled(X86_MACHINE(machine)) &&
    475         machine->kernel_filename != NULL &&
    476         mms->auto_kernel_cmdline && !mms->kernel_cmdline_fixed) {
    477         microvm_fix_kernel_cmdline(machine);
    478         mms->kernel_cmdline_fixed = true;
    479     }
    480 
    481     qemu_devices_reset(reason);
    482 
    483     CPU_FOREACH(cs) {
    484         cpu = X86_CPU(cs);
    485 
    486         x86_cpu_after_reset(cpu);
    487     }
    488 }
    489 
    490 static void microvm_machine_get_rtc(Object *obj, Visitor *v, const char *name,
    491                                     void *opaque, Error **errp)
    492 {
    493     MicrovmMachineState *mms = MICROVM_MACHINE(obj);
    494     OnOffAuto rtc = mms->rtc;
    495 
    496     visit_type_OnOffAuto(v, name, &rtc, errp);
    497 }
    498 
    499 static void microvm_machine_set_rtc(Object *obj, Visitor *v, const char *name,
    500                                     void *opaque, Error **errp)
    501 {
    502     MicrovmMachineState *mms = MICROVM_MACHINE(obj);
    503 
    504     visit_type_OnOffAuto(v, name, &mms->rtc, errp);
    505 }
    506 
    507 static void microvm_machine_get_pcie(Object *obj, Visitor *v, const char *name,
    508                                      void *opaque, Error **errp)
    509 {
    510     MicrovmMachineState *mms = MICROVM_MACHINE(obj);
    511     OnOffAuto pcie = mms->pcie;
    512 
    513     visit_type_OnOffAuto(v, name, &pcie, errp);
    514 }
    515 
    516 static void microvm_machine_set_pcie(Object *obj, Visitor *v, const char *name,
    517                                      void *opaque, Error **errp)
    518 {
    519     MicrovmMachineState *mms = MICROVM_MACHINE(obj);
    520 
    521     visit_type_OnOffAuto(v, name, &mms->pcie, errp);
    522 }
    523 
    524 static void microvm_machine_get_ioapic2(Object *obj, Visitor *v, const char *name,
    525                                         void *opaque, Error **errp)
    526 {
    527     MicrovmMachineState *mms = MICROVM_MACHINE(obj);
    528     OnOffAuto ioapic2 = mms->ioapic2;
    529 
    530     visit_type_OnOffAuto(v, name, &ioapic2, errp);
    531 }
    532 
    533 static void microvm_machine_set_ioapic2(Object *obj, Visitor *v, const char *name,
    534                                         void *opaque, Error **errp)
    535 {
    536     MicrovmMachineState *mms = MICROVM_MACHINE(obj);
    537 
    538     visit_type_OnOffAuto(v, name, &mms->ioapic2, errp);
    539 }
    540 
    541 static bool microvm_machine_get_isa_serial(Object *obj, Error **errp)
    542 {
    543     MicrovmMachineState *mms = MICROVM_MACHINE(obj);
    544 
    545     return mms->isa_serial;
    546 }
    547 
    548 static void microvm_machine_set_isa_serial(Object *obj, bool value,
    549                                            Error **errp)
    550 {
    551     MicrovmMachineState *mms = MICROVM_MACHINE(obj);
    552 
    553     mms->isa_serial = value;
    554 }
    555 
    556 static bool microvm_machine_get_option_roms(Object *obj, Error **errp)
    557 {
    558     MicrovmMachineState *mms = MICROVM_MACHINE(obj);
    559 
    560     return mms->option_roms;
    561 }
    562 
    563 static void microvm_machine_set_option_roms(Object *obj, bool value,
    564                                             Error **errp)
    565 {
    566     MicrovmMachineState *mms = MICROVM_MACHINE(obj);
    567 
    568     mms->option_roms = value;
    569 }
    570 
    571 static bool microvm_machine_get_auto_kernel_cmdline(Object *obj, Error **errp)
    572 {
    573     MicrovmMachineState *mms = MICROVM_MACHINE(obj);
    574 
    575     return mms->auto_kernel_cmdline;
    576 }
    577 
    578 static void microvm_machine_set_auto_kernel_cmdline(Object *obj, bool value,
    579                                                     Error **errp)
    580 {
    581     MicrovmMachineState *mms = MICROVM_MACHINE(obj);
    582 
    583     mms->auto_kernel_cmdline = value;
    584 }
    585 
    586 static void microvm_machine_done(Notifier *notifier, void *data)
    587 {
    588     MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
    589                                             machine_done);
    590 
    591     acpi_setup_microvm(mms);
    592     dt_setup_microvm(mms);
    593 }
    594 
    595 static void microvm_powerdown_req(Notifier *notifier, void *data)
    596 {
    597     MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
    598                                             powerdown_req);
    599     X86MachineState *x86ms = X86_MACHINE(mms);
    600 
    601     if (x86ms->acpi_dev) {
    602         Object *obj = OBJECT(x86ms->acpi_dev);
    603         AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
    604         adevc->send_event(ACPI_DEVICE_IF(x86ms->acpi_dev),
    605                           ACPI_POWER_DOWN_STATUS);
    606     }
    607 }
    608 
    609 static void microvm_machine_initfn(Object *obj)
    610 {
    611     MicrovmMachineState *mms = MICROVM_MACHINE(obj);
    612 
    613     /* Configuration */
    614     mms->rtc = ON_OFF_AUTO_AUTO;
    615     mms->pcie = ON_OFF_AUTO_AUTO;
    616     mms->ioapic2 = ON_OFF_AUTO_AUTO;
    617     mms->isa_serial = true;
    618     mms->option_roms = true;
    619     mms->auto_kernel_cmdline = true;
    620 
    621     /* State */
    622     mms->kernel_cmdline_fixed = false;
    623 
    624     mms->machine_done.notify = microvm_machine_done;
    625     qemu_add_machine_init_done_notifier(&mms->machine_done);
    626     mms->powerdown_req.notify = microvm_powerdown_req;
    627     qemu_register_powerdown_notifier(&mms->powerdown_req);
    628 }
    629 
    630 GlobalProperty microvm_properties[] = {
    631     /*
    632      * pcie host bridge (gpex) on microvm has no io address window,
    633      * so reserving io space is not going to work.  Turn it off.
    634      */
    635     { "pcie-root-port", "io-reserve", "0" },
    636 };
    637 
    638 static void microvm_class_init(ObjectClass *oc, void *data)
    639 {
    640     X86MachineClass *x86mc = X86_MACHINE_CLASS(oc);
    641     MachineClass *mc = MACHINE_CLASS(oc);
    642     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
    643 
    644     mc->init = microvm_machine_state_init;
    645 
    646     mc->family = "microvm_i386";
    647     mc->desc = "microvm (i386)";
    648     mc->units_per_default_bus = 1;
    649     mc->no_floppy = 1;
    650     mc->max_cpus = 288;
    651     mc->has_hotpluggable_cpus = false;
    652     mc->auto_enable_numa_with_memhp = false;
    653     mc->auto_enable_numa_with_memdev = false;
    654     mc->default_cpu_type = TARGET_DEFAULT_CPU_TYPE;
    655     mc->nvdimm_supported = false;
    656     mc->default_ram_id = "microvm.ram";
    657 
    658     /* Avoid relying too much on kernel components */
    659     mc->default_kernel_irqchip_split = true;
    660 
    661     /* Machine class handlers */
    662     mc->reset = microvm_machine_reset;
    663 
    664     /* hotplug (for cpu coldplug) */
    665     mc->get_hotplug_handler = microvm_get_hotplug_handler;
    666     hc->pre_plug = microvm_device_pre_plug_cb;
    667     hc->plug = microvm_device_plug_cb;
    668     hc->unplug_request = microvm_device_unplug_request_cb;
    669     hc->unplug = microvm_device_unplug_cb;
    670 
    671     x86mc->fwcfg_dma_enabled = true;
    672 
    673     object_class_property_add(oc, MICROVM_MACHINE_RTC, "OnOffAuto",
    674                               microvm_machine_get_rtc,
    675                               microvm_machine_set_rtc,
    676                               NULL, NULL);
    677     object_class_property_set_description(oc, MICROVM_MACHINE_RTC,
    678         "Enable MC146818 RTC");
    679 
    680     object_class_property_add(oc, MICROVM_MACHINE_PCIE, "OnOffAuto",
    681                               microvm_machine_get_pcie,
    682                               microvm_machine_set_pcie,
    683                               NULL, NULL);
    684     object_class_property_set_description(oc, MICROVM_MACHINE_PCIE,
    685         "Enable PCIe");
    686 
    687     object_class_property_add(oc, MICROVM_MACHINE_IOAPIC2, "OnOffAuto",
    688                               microvm_machine_get_ioapic2,
    689                               microvm_machine_set_ioapic2,
    690                               NULL, NULL);
    691     object_class_property_set_description(oc, MICROVM_MACHINE_IOAPIC2,
    692         "Enable second IO-APIC");
    693 
    694     object_class_property_add_bool(oc, MICROVM_MACHINE_ISA_SERIAL,
    695                                    microvm_machine_get_isa_serial,
    696                                    microvm_machine_set_isa_serial);
    697     object_class_property_set_description(oc, MICROVM_MACHINE_ISA_SERIAL,
    698         "Set off to disable the instantiation an ISA serial port");
    699 
    700     object_class_property_add_bool(oc, MICROVM_MACHINE_OPTION_ROMS,
    701                                    microvm_machine_get_option_roms,
    702                                    microvm_machine_set_option_roms);
    703     object_class_property_set_description(oc, MICROVM_MACHINE_OPTION_ROMS,
    704         "Set off to disable loading option ROMs");
    705 
    706     object_class_property_add_bool(oc, MICROVM_MACHINE_AUTO_KERNEL_CMDLINE,
    707                                    microvm_machine_get_auto_kernel_cmdline,
    708                                    microvm_machine_set_auto_kernel_cmdline);
    709     object_class_property_set_description(oc,
    710         MICROVM_MACHINE_AUTO_KERNEL_CMDLINE,
    711         "Set off to disable adding virtio-mmio devices to the kernel cmdline");
    712 
    713     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
    714 
    715     compat_props_add(mc->compat_props, microvm_properties,
    716                      G_N_ELEMENTS(microvm_properties));
    717 }
    718 
    719 static const TypeInfo microvm_machine_info = {
    720     .name          = TYPE_MICROVM_MACHINE,
    721     .parent        = TYPE_X86_MACHINE,
    722     .instance_size = sizeof(MicrovmMachineState),
    723     .instance_init = microvm_machine_initfn,
    724     .class_size    = sizeof(MicrovmMachineClass),
    725     .class_init    = microvm_class_init,
    726     .interfaces = (InterfaceInfo[]) {
    727          { TYPE_HOTPLUG_HANDLER },
    728          { }
    729     },
    730 };
    731 
    732 static void microvm_machine_init(void)
    733 {
    734     type_register_static(&microvm_machine_info);
    735 }
    736 type_init(microvm_machine_init);