cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

microvm.c (26244B)


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