qemu/hw/i386/microvm.c
<<
>>
Prefs
   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    Error *local_err = NULL;
 462
 463    microvm_memory_init(mms);
 464
 465    x86_cpus_init(x86ms, CPU_VERSION_LATEST);
 466    if (local_err) {
 467        error_report_err(local_err);
 468        exit(1);
 469    }
 470
 471    microvm_devices_init(mms);
 472}
 473
 474static void microvm_machine_reset(MachineState *machine)
 475{
 476    MicrovmMachineState *mms = MICROVM_MACHINE(machine);
 477    CPUState *cs;
 478    X86CPU *cpu;
 479
 480    if (!x86_machine_is_acpi_enabled(X86_MACHINE(machine)) &&
 481        machine->kernel_filename != NULL &&
 482        mms->auto_kernel_cmdline && !mms->kernel_cmdline_fixed) {
 483        microvm_fix_kernel_cmdline(machine);
 484        mms->kernel_cmdline_fixed = true;
 485    }
 486
 487    qemu_devices_reset();
 488
 489    CPU_FOREACH(cs) {
 490        cpu = X86_CPU(cs);
 491
 492        if (cpu->apic_state) {
 493            device_legacy_reset(cpu->apic_state);
 494        }
 495    }
 496}
 497
 498static void microvm_machine_get_pic(Object *obj, Visitor *v, const char *name,
 499                                    void *opaque, Error **errp)
 500{
 501    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 502    OnOffAuto pic = mms->pic;
 503
 504    visit_type_OnOffAuto(v, name, &pic, errp);
 505}
 506
 507static void microvm_machine_set_pic(Object *obj, Visitor *v, const char *name,
 508                                    void *opaque, Error **errp)
 509{
 510    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 511
 512    visit_type_OnOffAuto(v, name, &mms->pic, errp);
 513}
 514
 515static void microvm_machine_get_pit(Object *obj, Visitor *v, const char *name,
 516                                    void *opaque, Error **errp)
 517{
 518    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 519    OnOffAuto pit = mms->pit;
 520
 521    visit_type_OnOffAuto(v, name, &pit, errp);
 522}
 523
 524static void microvm_machine_set_pit(Object *obj, Visitor *v, const char *name,
 525                                    void *opaque, Error **errp)
 526{
 527    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 528
 529    visit_type_OnOffAuto(v, name, &mms->pit, errp);
 530}
 531
 532static void microvm_machine_get_rtc(Object *obj, Visitor *v, const char *name,
 533                                    void *opaque, Error **errp)
 534{
 535    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 536    OnOffAuto rtc = mms->rtc;
 537
 538    visit_type_OnOffAuto(v, name, &rtc, errp);
 539}
 540
 541static void microvm_machine_set_rtc(Object *obj, Visitor *v, const char *name,
 542                                    void *opaque, Error **errp)
 543{
 544    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 545
 546    visit_type_OnOffAuto(v, name, &mms->rtc, errp);
 547}
 548
 549static void microvm_machine_get_pcie(Object *obj, Visitor *v, const char *name,
 550                                     void *opaque, Error **errp)
 551{
 552    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 553    OnOffAuto pcie = mms->pcie;
 554
 555    visit_type_OnOffAuto(v, name, &pcie, errp);
 556}
 557
 558static void microvm_machine_set_pcie(Object *obj, Visitor *v, const char *name,
 559                                     void *opaque, Error **errp)
 560{
 561    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 562
 563    visit_type_OnOffAuto(v, name, &mms->pcie, errp);
 564}
 565
 566static void microvm_machine_get_ioapic2(Object *obj, Visitor *v, const char *name,
 567                                        void *opaque, Error **errp)
 568{
 569    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 570    OnOffAuto ioapic2 = mms->ioapic2;
 571
 572    visit_type_OnOffAuto(v, name, &ioapic2, errp);
 573}
 574
 575static void microvm_machine_set_ioapic2(Object *obj, Visitor *v, const char *name,
 576                                        void *opaque, Error **errp)
 577{
 578    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 579
 580    visit_type_OnOffAuto(v, name, &mms->ioapic2, errp);
 581}
 582
 583static bool microvm_machine_get_isa_serial(Object *obj, Error **errp)
 584{
 585    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 586
 587    return mms->isa_serial;
 588}
 589
 590static void microvm_machine_set_isa_serial(Object *obj, bool value,
 591                                           Error **errp)
 592{
 593    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 594
 595    mms->isa_serial = value;
 596}
 597
 598static bool microvm_machine_get_option_roms(Object *obj, Error **errp)
 599{
 600    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 601
 602    return mms->option_roms;
 603}
 604
 605static void microvm_machine_set_option_roms(Object *obj, bool value,
 606                                            Error **errp)
 607{
 608    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 609
 610    mms->option_roms = value;
 611}
 612
 613static bool microvm_machine_get_auto_kernel_cmdline(Object *obj, Error **errp)
 614{
 615    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 616
 617    return mms->auto_kernel_cmdline;
 618}
 619
 620static void microvm_machine_set_auto_kernel_cmdline(Object *obj, bool value,
 621                                                    Error **errp)
 622{
 623    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 624
 625    mms->auto_kernel_cmdline = value;
 626}
 627
 628static void microvm_machine_done(Notifier *notifier, void *data)
 629{
 630    MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
 631                                            machine_done);
 632
 633    acpi_setup_microvm(mms);
 634}
 635
 636static void microvm_powerdown_req(Notifier *notifier, void *data)
 637{
 638    MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
 639                                            powerdown_req);
 640    X86MachineState *x86ms = X86_MACHINE(mms);
 641
 642    if (x86ms->acpi_dev) {
 643        Object *obj = OBJECT(x86ms->acpi_dev);
 644        AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
 645        adevc->send_event(ACPI_DEVICE_IF(x86ms->acpi_dev),
 646                          ACPI_POWER_DOWN_STATUS);
 647    }
 648}
 649
 650static void microvm_machine_initfn(Object *obj)
 651{
 652    MicrovmMachineState *mms = MICROVM_MACHINE(obj);
 653
 654    /* Configuration */
 655    mms->pic = ON_OFF_AUTO_AUTO;
 656    mms->pit = ON_OFF_AUTO_AUTO;
 657    mms->rtc = ON_OFF_AUTO_AUTO;
 658    mms->pcie = ON_OFF_AUTO_AUTO;
 659    mms->ioapic2 = ON_OFF_AUTO_AUTO;
 660    mms->isa_serial = true;
 661    mms->option_roms = true;
 662    mms->auto_kernel_cmdline = true;
 663
 664    /* State */
 665    mms->kernel_cmdline_fixed = false;
 666
 667    mms->machine_done.notify = microvm_machine_done;
 668    qemu_add_machine_init_done_notifier(&mms->machine_done);
 669    mms->powerdown_req.notify = microvm_powerdown_req;
 670    qemu_register_powerdown_notifier(&mms->powerdown_req);
 671}
 672
 673static void microvm_class_init(ObjectClass *oc, void *data)
 674{
 675    MachineClass *mc = MACHINE_CLASS(oc);
 676    HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
 677
 678    mc->init = microvm_machine_state_init;
 679
 680    mc->family = "microvm_i386";
 681    mc->desc = "microvm (i386)";
 682    mc->units_per_default_bus = 1;
 683    mc->no_floppy = 1;
 684    mc->max_cpus = 288;
 685    mc->has_hotpluggable_cpus = false;
 686    mc->auto_enable_numa_with_memhp = false;
 687    mc->auto_enable_numa_with_memdev = false;
 688    mc->default_cpu_type = TARGET_DEFAULT_CPU_TYPE;
 689    mc->nvdimm_supported = false;
 690    mc->default_ram_id = "microvm.ram";
 691
 692    /* Avoid relying too much on kernel components */
 693    mc->default_kernel_irqchip_split = true;
 694
 695    /* Machine class handlers */
 696    mc->reset = microvm_machine_reset;
 697
 698    /* hotplug (for cpu coldplug) */
 699    mc->get_hotplug_handler = microvm_get_hotplug_handler;
 700    hc->pre_plug = microvm_device_pre_plug_cb;
 701    hc->plug = microvm_device_plug_cb;
 702    hc->unplug_request = microvm_device_unplug_request_cb;
 703    hc->unplug = microvm_device_unplug_cb;
 704
 705    object_class_property_add(oc, MICROVM_MACHINE_PIC, "OnOffAuto",
 706                              microvm_machine_get_pic,
 707                              microvm_machine_set_pic,
 708                              NULL, NULL);
 709    object_class_property_set_description(oc, MICROVM_MACHINE_PIC,
 710        "Enable i8259 PIC");
 711
 712    object_class_property_add(oc, MICROVM_MACHINE_PIT, "OnOffAuto",
 713                              microvm_machine_get_pit,
 714                              microvm_machine_set_pit,
 715                              NULL, NULL);
 716    object_class_property_set_description(oc, MICROVM_MACHINE_PIT,
 717        "Enable i8254 PIT");
 718
 719    object_class_property_add(oc, MICROVM_MACHINE_RTC, "OnOffAuto",
 720                              microvm_machine_get_rtc,
 721                              microvm_machine_set_rtc,
 722                              NULL, NULL);
 723    object_class_property_set_description(oc, MICROVM_MACHINE_RTC,
 724        "Enable MC146818 RTC");
 725
 726    object_class_property_add(oc, MICROVM_MACHINE_PCIE, "OnOffAuto",
 727                              microvm_machine_get_pcie,
 728                              microvm_machine_set_pcie,
 729                              NULL, NULL);
 730    object_class_property_set_description(oc, MICROVM_MACHINE_PCIE,
 731        "Enable PCIe");
 732
 733    object_class_property_add(oc, MICROVM_MACHINE_IOAPIC2, "OnOffAuto",
 734                              microvm_machine_get_ioapic2,
 735                              microvm_machine_set_ioapic2,
 736                              NULL, NULL);
 737    object_class_property_set_description(oc, MICROVM_MACHINE_IOAPIC2,
 738        "Enable second IO-APIC");
 739
 740    object_class_property_add_bool(oc, MICROVM_MACHINE_ISA_SERIAL,
 741                                   microvm_machine_get_isa_serial,
 742                                   microvm_machine_set_isa_serial);
 743    object_class_property_set_description(oc, MICROVM_MACHINE_ISA_SERIAL,
 744        "Set off to disable the instantiation an ISA serial port");
 745
 746    object_class_property_add_bool(oc, MICROVM_MACHINE_OPTION_ROMS,
 747                                   microvm_machine_get_option_roms,
 748                                   microvm_machine_set_option_roms);
 749    object_class_property_set_description(oc, MICROVM_MACHINE_OPTION_ROMS,
 750        "Set off to disable loading option ROMs");
 751
 752    object_class_property_add_bool(oc, MICROVM_MACHINE_AUTO_KERNEL_CMDLINE,
 753                                   microvm_machine_get_auto_kernel_cmdline,
 754                                   microvm_machine_set_auto_kernel_cmdline);
 755    object_class_property_set_description(oc,
 756        MICROVM_MACHINE_AUTO_KERNEL_CMDLINE,
 757        "Set off to disable adding virtio-mmio devices to the kernel cmdline");
 758
 759    machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
 760}
 761
 762static const TypeInfo microvm_machine_info = {
 763    .name          = TYPE_MICROVM_MACHINE,
 764    .parent        = TYPE_X86_MACHINE,
 765    .instance_size = sizeof(MicrovmMachineState),
 766    .instance_init = microvm_machine_initfn,
 767    .class_size    = sizeof(MicrovmMachineClass),
 768    .class_init    = microvm_class_init,
 769    .interfaces = (InterfaceInfo[]) {
 770         { TYPE_HOTPLUG_HANDLER },
 771         { }
 772    },
 773};
 774
 775static void microvm_machine_init(void)
 776{
 777    type_register_static(&microvm_machine_info);
 778}
 779type_init(microvm_machine_init);
 780