diff options
Diffstat (limited to 'hw/ppc/spapr.c')
-rw-r--r-- | hw/ppc/spapr.c | 331 |
1 files changed, 256 insertions, 75 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 16bfab90b..a11e1217b 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -26,6 +26,7 @@ */ #include "sysemu/sysemu.h" #include "hw/hw.h" +#include "hw/fw-path-provider.h" #include "elf.h" #include "net/net.h" #include "sysemu/blockdev.h" @@ -45,10 +46,13 @@ #include "hw/pci/msi.h" #include "hw/pci/pci.h" +#include "hw/scsi/scsi.h" +#include "hw/virtio/virtio-scsi.h" #include "exec/address-spaces.h" #include "hw/usb.h" #include "qemu/config-file.h" +#include "qemu/error-report.h" #include <libfdt.h> @@ -62,7 +66,7 @@ * * We load our kernel at 4M, leaving space for SLOF initial image */ -#define FDT_MAX_SIZE 0x10000 +#define FDT_MAX_SIZE 0x40000 #define RTAS_MAX_SIZE 0x10000 #define FW_MAX_SIZE 0x400000 #define FW_FILE_NAME "slof.bin" @@ -80,6 +84,8 @@ #define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) +#define TYPE_SPAPR_MACHINE "spapr-machine" + sPAPREnvironment *spapr; int spapr_allocate_irq(int hint, bool lsi) @@ -88,6 +94,9 @@ int spapr_allocate_irq(int hint, bool lsi) if (hint) { irq = hint; + if (hint >= spapr->next_irq) { + spapr->next_irq = hint + 1; + } /* FIXME: we should probably check for collisions somehow */ } else { irq = spapr->next_irq++; @@ -103,22 +112,39 @@ int spapr_allocate_irq(int hint, bool lsi) return irq; } -/* Allocate block of consequtive IRQs, returns a number of the first */ -int spapr_allocate_irq_block(int num, bool lsi) +/* + * Allocate block of consequtive IRQs, returns a number of the first. + * If msi==true, aligns the first IRQ number to num. + */ +int spapr_allocate_irq_block(int num, bool lsi, bool msi) { int first = -1; - int i; + int i, hint = 0; + + /* + * MSIMesage::data is used for storing VIRQ so + * it has to be aligned to num to support multiple + * MSI vectors. MSI-X is not affected by this. + * The hint is used for the first IRQ, the rest should + * be allocated continuously. + */ + if (msi) { + assert((num == 1) || (num == 2) || (num == 4) || + (num == 8) || (num == 16) || (num == 32)); + hint = (spapr->next_irq + num - 1) & ~(num - 1); + } for (i = 0; i < num; ++i) { int irq; - irq = spapr_allocate_irq(0, lsi); + irq = spapr_allocate_irq(hint, lsi); if (!irq) { return -1; } if (0 == i) { first = irq; + hint = 0; } /* If the above doesn't create a consecutive block then that's @@ -141,14 +167,33 @@ static XICSState *try_create_xics(const char *type, int nr_servers, return NULL; } - return XICS(dev); + return XICS_COMMON(dev); } static XICSState *xics_system_init(int nr_servers, int nr_irqs) { XICSState *icp = NULL; - icp = try_create_xics(TYPE_XICS, nr_servers, nr_irqs); + if (kvm_enabled()) { + QemuOpts *machine_opts = qemu_get_machine_opts(); + bool irqchip_allowed = qemu_opt_get_bool(machine_opts, + "kernel_irqchip", true); + bool irqchip_required = qemu_opt_get_bool(machine_opts, + "kernel_irqchip", false); + if (irqchip_allowed) { + icp = try_create_xics(TYPE_KVM_XICS, nr_servers, nr_irqs); + } + + if (irqchip_required && !icp) { + perror("Failed to create in-kernel XICS\n"); + abort(); + } + } + + if (!icp) { + icp = try_create_xics(TYPE_XICS, nr_servers, nr_irqs); + } + if (!icp) { perror("Failed to create XICS\n"); abort(); @@ -165,22 +210,22 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) int smt = kvmppc_smt_threads(); uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; - assert(spapr->cpu_model); - - for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { + CPU_FOREACH(cpu) { + DeviceClass *dc = DEVICE_GET_CLASS(cpu); + int index = ppc_get_vcpu_dt_id(POWERPC_CPU(cpu)); uint32_t associativity[] = {cpu_to_be32(0x5), cpu_to_be32(0x0), cpu_to_be32(0x0), cpu_to_be32(0x0), cpu_to_be32(cpu->numa_node), - cpu_to_be32(cpu->cpu_index)}; + cpu_to_be32(index)}; - if ((cpu->cpu_index % smt) != 0) { + if ((index % smt) != 0) { continue; } - snprintf(cpu_model, 32, "/cpus/%s@%x", spapr->cpu_model, - cpu->cpu_index); + snprintf(cpu_model, 32, "/cpus/%s@%x", dc->fw_name, + index); offset = fdt_path_offset(fdt, cpu_model); if (offset < 0) { @@ -249,10 +294,10 @@ static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop, } while (0) -static void *spapr_create_fdt_skel(const char *cpu_model, - hwaddr initrd_base, +static void *spapr_create_fdt_skel(hwaddr initrd_base, hwaddr initrd_size, hwaddr kernel_size, + bool little_endian, const char *boot_device, const char *kernel_cmdline, uint32_t epow_irq) @@ -262,11 +307,10 @@ static void *spapr_create_fdt_skel(const char *cpu_model, uint32_t start_prop = cpu_to_be32(initrd_base); uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt" - "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk"; + "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk\0hcall-set-mode"; char qemu_hypertas_prop[] = "hcall-memop1"; uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)}; uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; - char *modelname; int i, smt = kvmppc_smt_threads(); unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80}; @@ -306,6 +350,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model, cpu_to_be64(kernel_size) }; _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop)))); + if (little_endian) { + _FDT((fdt_property(fdt, "qemu,boot-kernel-le", NULL, 0))); + } } if (boot_device) { _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device))); @@ -322,20 +369,12 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property_cell(fdt, "#address-cells", 0x1))); _FDT((fdt_property_cell(fdt, "#size-cells", 0x0))); - modelname = g_strdup(cpu_model); - - for (i = 0; i < strlen(modelname); i++) { - modelname[i] = toupper(modelname[i]); - } - - /* This is needed during FDT finalization */ - spapr->cpu_model = g_strdup(modelname); - - for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) { + CPU_FOREACH(cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; + DeviceClass *dc = DEVICE_GET_CLASS(cs); PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs); - int index = cs->cpu_index; + int index = ppc_get_vcpu_dt_id(cpu); uint32_t servers_prop[smp_threads]; uint32_t gservers_prop[smp_threads * 2]; char *nodename; @@ -350,7 +389,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model, continue; } - nodename = g_strdup_printf("%s@%x", modelname, index); + nodename = g_strdup_printf("%s@%x", dc->fw_name, index); _FDT((fdt_begin_node(fdt, nodename))); @@ -398,6 +437,10 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s", gservers_prop, sizeof(gservers_prop)))); + if (env->spr_cb[SPR_PURR].oea_read) { + _FDT((fdt_property(fdt, "ibm,purr", NULL, 0))); + } + if (env->mmu_model & POWERPC_MMU_1TSEG) { _FDT((fdt_property(fdt, "ibm,processor-segment-sizes", segs, sizeof(segs)))); @@ -430,8 +473,6 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_end_node(fdt))); } - g_free(modelname); - _FDT((fdt_end_node(fdt))); /* RTAS */ @@ -492,14 +533,15 @@ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt) cpu_to_be32(0x0), cpu_to_be32(0x0), cpu_to_be32(0x0)}; char mem_name[32]; - hwaddr node0_size, mem_start; + hwaddr node0_size, mem_start, node_size; uint64_t mem_reg_property[2]; int i, off; /* memory node(s) */ - node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; - if (spapr->rma_size > node0_size) { - spapr->rma_size = node0_size; + if (nb_numa_nodes > 1 && node_mem[0] < ram_size) { + node0_size = node_mem[0]; + } else { + node0_size = ram_size; } /* RMA */ @@ -532,7 +574,15 @@ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt) mem_start = node0_size; for (i = 1; i < nb_numa_nodes; i++) { mem_reg_property[0] = cpu_to_be64(mem_start); - mem_reg_property[1] = cpu_to_be64(node_mem[i]); + if (mem_start >= ram_size) { + node_size = 0; + } else { + node_size = node_mem[i]; + if (node_size > ram_size - mem_start) { + node_size = ram_size - mem_start; + } + } + mem_reg_property[1] = cpu_to_be64(node_size); associativity[3] = associativity[4] = cpu_to_be32(i); sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start); off = fdt_add_subnode(fdt, 0, mem_name); @@ -542,7 +592,7 @@ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt) sizeof(mem_reg_property)))); _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, sizeof(associativity)))); - mem_start += node_mem[i]; + mem_start += node_size; } return 0; @@ -553,7 +603,9 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, hwaddr rtas_addr, hwaddr rtas_size) { - int ret; + int ret, i; + size_t cb = 0; + char *bootlist; void *fdt; sPAPRPHBState *phb; @@ -595,6 +647,21 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, fprintf(stderr, "Couldn't finalize CPU device tree properties\n"); } + bootlist = get_boot_devices_list(&cb, true); + if (cb && bootlist) { + int offset = fdt_path_offset(fdt, "/chosen"); + if (offset < 0) { + exit(1); + } + for (i = 0; i < cb; i++) { + if (bootlist[i] == '\n') { + bootlist[i] = ' '; + } + + } + ret = fdt_setprop_string(fdt, offset, "qemu,boot-list", bootlist); + } + if (!spapr->has_graphics) { spapr_populate_chosen_stdout(fdt, spapr->vio_bus); } @@ -642,6 +709,7 @@ static void spapr_reset_htab(sPAPREnvironment *spapr) if (shift > 0) { /* Kernel handles htab, we don't need to allocate one */ spapr->htab_shift = shift; + kvmppc_kern_htab = true; } else { if (!spapr->htab) { /* Allocate an htab if we don't yet have one */ @@ -654,7 +722,8 @@ static void spapr_reset_htab(sPAPREnvironment *spapr) /* Update the RMA size if necessary */ if (spapr->vrma_adjust) { - spapr->rma_size = kvmppc_rma_size(ram_size, spapr->htab_shift); + hwaddr node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; + spapr->rma_size = kvmppc_rma_size(node0_size, spapr->htab_shift); } } @@ -696,8 +765,21 @@ static void spapr_cpu_reset(void *opaque) env->spr[SPR_HIOR] = 0; env->external_htab = (uint8_t *)spapr->htab; + if (kvm_enabled() && !env->external_htab) { + /* + * HV KVM, set external_htab to 1 so our ppc_hash64_load_hpte* + * functions do the right thing. + */ + env->external_htab = (void *)1; + } env->htab_base = -1; - env->htab_mask = HTAB_SIZE(spapr) - 1; + /* + * htab_mask is the mask used to normalize hash value to PTEG index. + * htab_shift is log2 of hash table size. + * We have 8 hpte per group, and each hpte is 16 bytes. + * ie have 128 bytes per hpte entry. + */ + env->htab_mask = (1ULL << ((spapr)->htab_shift - 7)) - 1; env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab | (spapr->htab_shift - 18); } @@ -705,18 +787,10 @@ static void spapr_cpu_reset(void *opaque) static void spapr_create_nvram(sPAPREnvironment *spapr) { DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram"); - const char *drivename = qemu_opt_get(qemu_get_machine_opts(), "nvram"); + DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0); - if (drivename) { - BlockDriverState *bs; - - bs = bdrv_find(drivename); - if (!bs) { - fprintf(stderr, "No such block device \"%s\" for nvram\n", - drivename); - exit(1); - } - qdev_prop_set_drive_nofail(dev, "drive", bs); + if (dinfo) { + qdev_prop_set_drive_nofail(dev, "drive", dinfo->bdrv); } qdev_init_nofail(dev); @@ -729,13 +803,15 @@ static int spapr_vga_init(PCIBus *pci_bus) { switch (vga_interface_type) { case VGA_NONE: + return false; + case VGA_DEVICE: + return true; case VGA_STD: return pci_vga_init(pci_bus) != NULL; default: fprintf(stderr, "This vga model is not supported," "currently it only supports -vga std\n"); exit(0); - break; } } @@ -789,7 +865,7 @@ static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr, { int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64; int index = spapr->htab_save_index; - int64_t starttime = qemu_get_clock_ns(rt_clock); + int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); assert(spapr->htab_first_pass); @@ -820,7 +896,7 @@ static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr, qemu_put_buffer(f, HPTE(spapr->htab, chunkstart), HASH_PTE_SIZE_64 * n_valid); - if ((qemu_get_clock_ns(rt_clock) - starttime) > max_ns) { + if ((qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) { break; } } @@ -841,7 +917,7 @@ static int htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr, int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64; int examined = 0, sent = 0; int index = spapr->htab_save_index; - int64_t starttime = qemu_get_clock_ns(rt_clock); + int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); assert(!spapr->htab_first_pass); @@ -886,7 +962,7 @@ static int htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr, HASH_PTE_SIZE_64 * n_valid); sent += index - chunkstart; - if (!final && (qemu_get_clock_ns(rt_clock) - starttime) > max_ns) { + if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) { break; } } @@ -1071,7 +1147,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) const char *kernel_filename = args->kernel_filename; const char *kernel_cmdline = args->kernel_cmdline; const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; + const char *boot_device = args->boot_order; PowerPCCPU *cpu; CPUPPCState *env; PCIHostState *phb; @@ -1079,9 +1155,11 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); hwaddr rma_alloc_size; + hwaddr node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; uint32_t initrd_base = 0; long kernel_size = 0, initrd_size = 0; long load_limit, rtas_limit, fw_size; + bool kernel_le = false; char *filename; msi_supported = true; @@ -1099,10 +1177,10 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) exit(1); } - if (rma_alloc_size && (rma_alloc_size < ram_size)) { + if (rma_alloc_size && (rma_alloc_size < node0_size)) { spapr->rma_size = rma_alloc_size; } else { - spapr->rma_size = ram_size; + spapr->rma_size = node0_size; /* With KVM, we don't actually know whether KVM supports an * unbounded RMA (PR KVM) or is limited by the hash table size @@ -1119,6 +1197,12 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) } } + if (spapr->rma_size > node0_size) { + fprintf(stderr, "Error: Numa node 0 has to span the RMA (%#08"HWADDR_PRIx")\n", + spapr->rma_size); + exit(1); + } + /* We place the device tree and RTAS just below either the top of the RMA, * or just below 2GB, whichever is lowere, so that it can be * processed with 32-bit real mode code if necessary */ @@ -1155,8 +1239,6 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) } env = &cpu->env; - xics_cpu_setup(spapr->icp, cpu); - /* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init(env, TIMEBASE_FREQ); @@ -1170,6 +1252,8 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) kvmppc_set_papr(cpu); } + xics_cpu_setup(spapr->icp, cpu); + qemu_register_reset(spapr_cpu_reset, cpu); } @@ -1214,6 +1298,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) spapr_create_nvram(spapr); /* Set up PCI */ + spapr_pci_msi_init(spapr, SPAPR_PCI_MSI_WINDOW); spapr_pci_rtas_init(); phb = spapr_create_phb(spapr, 0); @@ -1260,14 +1345,15 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL, NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0); - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, - KERNEL_LOAD_ADDR, - load_limit - KERNEL_LOAD_ADDR); + if (kernel_size == ELF_LOAD_WRONG_ENDIAN) { + kernel_size = load_elf(kernel_filename, + translate_kernel_address, NULL, + NULL, &lowaddr, NULL, 0, ELF_MACHINE, 0); + kernel_le = kernel_size > 0; } if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); + fprintf(stderr, "qemu: error loading %s: %s\n", + kernel_filename, load_elf_strerror(kernel_size)); exit(1); } @@ -1308,14 +1394,31 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) &savevm_htab_handlers, spapr); /* Prepare the device tree */ - spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, - initrd_base, initrd_size, - kernel_size, + spapr->fdt_skel = spapr_create_fdt_skel(initrd_base, initrd_size, + kernel_size, kernel_le, boot_device, kernel_cmdline, spapr->epow_irq); assert(spapr->fdt_skel != NULL); } +static int spapr_kvm_type(const char *vm_type) +{ + if (!vm_type) { + return 0; + } + + if (!strcmp(vm_type, "HV")) { + return 1; + } + + if (!strcmp(vm_type, "PR")) { + return 2; + } + + error_report("Unknown kvm-type specified '%s'", vm_type); + exit(1); +} + static QEMUMachine spapr_machine = { .name = "pseries", .desc = "pSeries Logical Partition (PAPR compliant)", @@ -1325,12 +1428,90 @@ static QEMUMachine spapr_machine = { .block_default_type = IF_SCSI, .max_cpus = MAX_CPUS, .no_parallel = 1, - .boot_order = NULL, + .default_boot_order = NULL, + .kvm_type = spapr_kvm_type, +}; + +/* + * Implementation of an interface to adjust firmware patch + * for the bootindex property handling. + */ +static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus, + DeviceState *dev) +{ +#define CAST(type, obj, name) \ + ((type *)object_dynamic_cast(OBJECT(obj), (name))) + SCSIDevice *d = CAST(SCSIDevice, dev, TYPE_SCSI_DEVICE); + sPAPRPHBState *phb = CAST(sPAPRPHBState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE); + + if (d) { + void *spapr = CAST(void, bus->parent, "spapr-vscsi"); + VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI); + USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE); + + if (spapr) { + /* + * Replace "channel@0/disk@0,0" with "disk@8000000000000000": + * We use SRP luns of the form 8000 | (bus << 8) | (id << 5) | lun + * in the top 16 bits of the 64-bit LUN + */ + unsigned id = 0x8000 | (d->id << 8) | d->lun; + return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev), + (uint64_t)id << 48); + } else if (virtio) { + /* + * We use SRP luns of the form 01000000 | (target << 8) | lun + * in the top 32 bits of the 64-bit LUN + * Note: the quote above is from SLOF and it is wrong, + * the actual binding is: + * swap 0100 or 10 << or 20 << ( target lun-id -- srplun ) + */ + unsigned id = 0x1000000 | (d->id << 16) | d->lun; + return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev), + (uint64_t)id << 32); + } else if (usb) { + /* + * We use SRP luns of the form 01000000 | (usb-port << 16) | lun + * in the top 32 bits of the 64-bit LUN + */ + unsigned usb_port = atoi(usb->port->path); + unsigned id = 0x1000000 | (usb_port << 16) | d->lun; + return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev), + (uint64_t)id << 32); + } + } + + if (phb) { + /* Replace "pci" with "pci@800000020000000" */ + return g_strdup_printf("pci@%"PRIX64, phb->buid); + } + + return NULL; +} + +static void spapr_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc); + + mc->qemu_machine = data; + fwc->get_dev_path = spapr_get_fw_dev_path; +} + +static const TypeInfo spapr_machine_info = { + .name = TYPE_SPAPR_MACHINE, + .parent = TYPE_MACHINE, + .class_init = spapr_machine_class_init, + .class_data = &spapr_machine, + .interfaces = (InterfaceInfo[]) { + { TYPE_FW_PATH_PROVIDER }, + { } + }, }; -static void spapr_machine_init(void) +static void spapr_machine_register_types(void) { - qemu_register_machine(&spapr_machine); + type_register_static(&spapr_machine_info); } -machine_init(spapr_machine_init); +type_init(spapr_machine_register_types) |