159f4d655SAlexander Graf /* 259f4d655SAlexander Graf * VMApple machine emulation 359f4d655SAlexander Graf * 459f4d655SAlexander Graf * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. 559f4d655SAlexander Graf * 659f4d655SAlexander Graf * This work is licensed under the terms of the GNU GPL, version 2 or later. 759f4d655SAlexander Graf * See the COPYING file in the top-level directory. 859f4d655SAlexander Graf * 959f4d655SAlexander Graf * SPDX-License-Identifier: GPL-2.0-or-later 1059f4d655SAlexander Graf * 1159f4d655SAlexander Graf * VMApple is the device model that the macOS built-in hypervisor called 1259f4d655SAlexander Graf * "Virtualization.framework" exposes to Apple Silicon macOS guests. The 1359f4d655SAlexander Graf * machine model in this file implements the same device model in QEMU, but 1459f4d655SAlexander Graf * does not use any code from Virtualization.Framework. 1559f4d655SAlexander Graf */ 1659f4d655SAlexander Graf 1759f4d655SAlexander Graf #include "qemu/osdep.h" 1859f4d655SAlexander Graf #include "qemu/bitops.h" 1959f4d655SAlexander Graf #include "qemu/datadir.h" 2059f4d655SAlexander Graf #include "qemu/error-report.h" 2159f4d655SAlexander Graf #include "qemu/guest-random.h" 2259f4d655SAlexander Graf #include "qemu/help-texts.h" 2359f4d655SAlexander Graf #include "qemu/log.h" 2459f4d655SAlexander Graf #include "qemu/module.h" 2559f4d655SAlexander Graf #include "qemu/option.h" 2659f4d655SAlexander Graf #include "qemu/units.h" 2759f4d655SAlexander Graf #include "monitor/qdev.h" 2859f4d655SAlexander Graf #include "hw/boards.h" 2959f4d655SAlexander Graf #include "hw/irq.h" 3059f4d655SAlexander Graf #include "hw/loader.h" 3159f4d655SAlexander Graf #include "hw/qdev-properties.h" 3259f4d655SAlexander Graf #include "hw/sysbus.h" 3359f4d655SAlexander Graf #include "hw/usb.h" 3459f4d655SAlexander Graf #include "hw/arm/boot.h" 3559f4d655SAlexander Graf #include "hw/arm/primecell.h" 3659f4d655SAlexander Graf #include "hw/char/pl011.h" 3759f4d655SAlexander Graf #include "hw/intc/arm_gic.h" 3859f4d655SAlexander Graf #include "hw/intc/arm_gicv3_common.h" 3959f4d655SAlexander Graf #include "hw/misc/pvpanic.h" 4059f4d655SAlexander Graf #include "hw/pci-host/gpex.h" 4159f4d655SAlexander Graf #include "hw/usb/hcd-xhci-pci.h" 4259f4d655SAlexander Graf #include "hw/virtio/virtio-pci.h" 4359f4d655SAlexander Graf #include "hw/vmapple/vmapple.h" 4459f4d655SAlexander Graf #include "net/net.h" 4559f4d655SAlexander Graf #include "qapi/error.h" 4659f4d655SAlexander Graf #include "qapi/visitor.h" 4759f4d655SAlexander Graf #include "qapi/qapi-visit-common.h" 4859f4d655SAlexander Graf #include "qobject/qlist.h" 4959f4d655SAlexander Graf #include "standard-headers/linux/input.h" 5059f4d655SAlexander Graf #include "system/hvf.h" 5159f4d655SAlexander Graf #include "system/reset.h" 5259f4d655SAlexander Graf #include "system/runstate.h" 5359f4d655SAlexander Graf #include "system/system.h" 5459f4d655SAlexander Graf 5559f4d655SAlexander Graf struct VMAppleMachineState { 5659f4d655SAlexander Graf MachineState parent; 5759f4d655SAlexander Graf 5859f4d655SAlexander Graf Notifier machine_done; 5959f4d655SAlexander Graf struct arm_boot_info bootinfo; 6059f4d655SAlexander Graf const MemMapEntry *memmap; 6159f4d655SAlexander Graf const int *irqmap; 6259f4d655SAlexander Graf DeviceState *gic; 6359f4d655SAlexander Graf DeviceState *cfg; 6459f4d655SAlexander Graf DeviceState *pvpanic; 6559f4d655SAlexander Graf Notifier powerdown_notifier; 6659f4d655SAlexander Graf PCIBus *bus; 6759f4d655SAlexander Graf MemoryRegion fw_mr; 6859f4d655SAlexander Graf MemoryRegion ecam_alias; 6959f4d655SAlexander Graf uint64_t uuid; 7059f4d655SAlexander Graf }; 7159f4d655SAlexander Graf 7259f4d655SAlexander Graf #define TYPE_VMAPPLE_MACHINE MACHINE_TYPE_NAME("vmapple") 7359f4d655SAlexander Graf OBJECT_DECLARE_SIMPLE_TYPE(VMAppleMachineState, VMAPPLE_MACHINE) 7459f4d655SAlexander Graf 7559f4d655SAlexander Graf /* Number of external interrupt lines to configure the GIC with */ 7659f4d655SAlexander Graf #define NUM_IRQS 256 7759f4d655SAlexander Graf 7859f4d655SAlexander Graf enum { 7959f4d655SAlexander Graf VMAPPLE_FIRMWARE, 8059f4d655SAlexander Graf VMAPPLE_CONFIG, 8159f4d655SAlexander Graf VMAPPLE_MEM, 8259f4d655SAlexander Graf VMAPPLE_GIC_DIST, 8359f4d655SAlexander Graf VMAPPLE_GIC_REDIST, 8459f4d655SAlexander Graf VMAPPLE_UART, 8559f4d655SAlexander Graf VMAPPLE_RTC, 8659f4d655SAlexander Graf VMAPPLE_PCIE, 8759f4d655SAlexander Graf VMAPPLE_PCIE_MMIO, 8859f4d655SAlexander Graf VMAPPLE_PCIE_ECAM, 8959f4d655SAlexander Graf VMAPPLE_GPIO, 9059f4d655SAlexander Graf VMAPPLE_PVPANIC, 9159f4d655SAlexander Graf VMAPPLE_APV_GFX, 9259f4d655SAlexander Graf VMAPPLE_APV_IOSFC, 9359f4d655SAlexander Graf VMAPPLE_AES_1, 9459f4d655SAlexander Graf VMAPPLE_AES_2, 9559f4d655SAlexander Graf VMAPPLE_BDOOR, 9659f4d655SAlexander Graf VMAPPLE_MEMMAP_LAST, 9759f4d655SAlexander Graf }; 9859f4d655SAlexander Graf 9959f4d655SAlexander Graf static const MemMapEntry memmap[] = { 10059f4d655SAlexander Graf [VMAPPLE_FIRMWARE] = { 0x00100000, 0x00100000 }, 10159f4d655SAlexander Graf [VMAPPLE_CONFIG] = { 0x00400000, 0x00010000 }, 10259f4d655SAlexander Graf 10359f4d655SAlexander Graf [VMAPPLE_GIC_DIST] = { 0x10000000, 0x00010000 }, 10459f4d655SAlexander Graf [VMAPPLE_GIC_REDIST] = { 0x10010000, 0x00400000 }, 10559f4d655SAlexander Graf 10659f4d655SAlexander Graf [VMAPPLE_UART] = { 0x20010000, 0x00010000 }, 10759f4d655SAlexander Graf [VMAPPLE_RTC] = { 0x20050000, 0x00001000 }, 10859f4d655SAlexander Graf [VMAPPLE_GPIO] = { 0x20060000, 0x00001000 }, 10959f4d655SAlexander Graf [VMAPPLE_PVPANIC] = { 0x20070000, 0x00000002 }, 11059f4d655SAlexander Graf [VMAPPLE_BDOOR] = { 0x30000000, 0x00200000 }, 11159f4d655SAlexander Graf [VMAPPLE_APV_GFX] = { 0x30200000, 0x00010000 }, 11259f4d655SAlexander Graf [VMAPPLE_APV_IOSFC] = { 0x30210000, 0x00010000 }, 11359f4d655SAlexander Graf [VMAPPLE_AES_1] = { 0x30220000, 0x00004000 }, 11459f4d655SAlexander Graf [VMAPPLE_AES_2] = { 0x30230000, 0x00004000 }, 11559f4d655SAlexander Graf [VMAPPLE_PCIE_ECAM] = { 0x40000000, 0x10000000 }, 11659f4d655SAlexander Graf [VMAPPLE_PCIE_MMIO] = { 0x50000000, 0x1fff0000 }, 11759f4d655SAlexander Graf 11859f4d655SAlexander Graf /* Actual RAM size depends on configuration */ 11959f4d655SAlexander Graf [VMAPPLE_MEM] = { 0x70000000ULL, GiB}, 12059f4d655SAlexander Graf }; 12159f4d655SAlexander Graf 12259f4d655SAlexander Graf static const int irqmap[] = { 12359f4d655SAlexander Graf [VMAPPLE_UART] = 1, 12459f4d655SAlexander Graf [VMAPPLE_RTC] = 2, 12559f4d655SAlexander Graf [VMAPPLE_GPIO] = 0x5, 12659f4d655SAlexander Graf [VMAPPLE_APV_IOSFC] = 0x10, 12759f4d655SAlexander Graf [VMAPPLE_APV_GFX] = 0x11, 12859f4d655SAlexander Graf [VMAPPLE_AES_1] = 0x12, 12959f4d655SAlexander Graf [VMAPPLE_PCIE] = 0x20, 13059f4d655SAlexander Graf }; 13159f4d655SAlexander Graf 13259f4d655SAlexander Graf #define GPEX_NUM_IRQS 16 13359f4d655SAlexander Graf 13459f4d655SAlexander Graf static void create_bdif(VMAppleMachineState *vms, MemoryRegion *mem) 13559f4d655SAlexander Graf { 13659f4d655SAlexander Graf DeviceState *bdif; 13759f4d655SAlexander Graf SysBusDevice *bdif_sb; 13859f4d655SAlexander Graf DriveInfo *di_aux = drive_get(IF_PFLASH, 0, 0); 13959f4d655SAlexander Graf DriveInfo *di_root = drive_get(IF_PFLASH, 0, 1); 14059f4d655SAlexander Graf 14159f4d655SAlexander Graf if (!di_aux) { 14259f4d655SAlexander Graf error_report("No AUX device. Please specify one as pflash drive."); 14359f4d655SAlexander Graf exit(1); 14459f4d655SAlexander Graf } 14559f4d655SAlexander Graf 14659f4d655SAlexander Graf if (!di_root) { 14759f4d655SAlexander Graf /* Fall back to the first IF_VIRTIO device as root device */ 14859f4d655SAlexander Graf di_root = drive_get(IF_VIRTIO, 0, 0); 14959f4d655SAlexander Graf } 15059f4d655SAlexander Graf 15159f4d655SAlexander Graf if (!di_root) { 15259f4d655SAlexander Graf error_report("No root device. Please specify one as virtio drive."); 15359f4d655SAlexander Graf exit(1); 15459f4d655SAlexander Graf } 15559f4d655SAlexander Graf 15659f4d655SAlexander Graf /* PV backdoor device */ 15759f4d655SAlexander Graf bdif = qdev_new(TYPE_VMAPPLE_BDIF); 15859f4d655SAlexander Graf bdif_sb = SYS_BUS_DEVICE(bdif); 15959f4d655SAlexander Graf sysbus_mmio_map(bdif_sb, 0, vms->memmap[VMAPPLE_BDOOR].base); 16059f4d655SAlexander Graf 16159f4d655SAlexander Graf qdev_prop_set_drive(DEVICE(bdif), "aux", blk_by_legacy_dinfo(di_aux)); 16259f4d655SAlexander Graf qdev_prop_set_drive(DEVICE(bdif), "root", blk_by_legacy_dinfo(di_root)); 16359f4d655SAlexander Graf 16459f4d655SAlexander Graf sysbus_realize_and_unref(bdif_sb, &error_fatal); 16559f4d655SAlexander Graf } 16659f4d655SAlexander Graf 16759f4d655SAlexander Graf static void create_pvpanic(VMAppleMachineState *vms, MemoryRegion *mem) 16859f4d655SAlexander Graf { 16959f4d655SAlexander Graf SysBusDevice *pvpanic; 17059f4d655SAlexander Graf 17159f4d655SAlexander Graf vms->pvpanic = qdev_new(TYPE_PVPANIC_MMIO_DEVICE); 17259f4d655SAlexander Graf pvpanic = SYS_BUS_DEVICE(vms->pvpanic); 17359f4d655SAlexander Graf sysbus_mmio_map(pvpanic, 0, vms->memmap[VMAPPLE_PVPANIC].base); 17459f4d655SAlexander Graf 17559f4d655SAlexander Graf sysbus_realize_and_unref(pvpanic, &error_fatal); 17659f4d655SAlexander Graf } 17759f4d655SAlexander Graf 17859f4d655SAlexander Graf static bool create_cfg(VMAppleMachineState *vms, MemoryRegion *mem, 17959f4d655SAlexander Graf Error **errp) 18059f4d655SAlexander Graf { 18159f4d655SAlexander Graf ERRP_GUARD(); 18259f4d655SAlexander Graf SysBusDevice *cfg; 18359f4d655SAlexander Graf MachineState *machine = MACHINE(vms); 18459f4d655SAlexander Graf uint32_t rnd = 1; 18559f4d655SAlexander Graf 18659f4d655SAlexander Graf vms->cfg = qdev_new(TYPE_VMAPPLE_CFG); 18759f4d655SAlexander Graf cfg = SYS_BUS_DEVICE(vms->cfg); 18859f4d655SAlexander Graf sysbus_mmio_map(cfg, 0, vms->memmap[VMAPPLE_CONFIG].base); 18959f4d655SAlexander Graf 19059f4d655SAlexander Graf qemu_guest_getrandom_nofail(&rnd, sizeof(rnd)); 19159f4d655SAlexander Graf 19259f4d655SAlexander Graf qdev_prop_set_uint32(vms->cfg, "nr-cpus", machine->smp.cpus); 19359f4d655SAlexander Graf qdev_prop_set_uint64(vms->cfg, "ecid", vms->uuid); 19459f4d655SAlexander Graf qdev_prop_set_uint64(vms->cfg, "ram-size", machine->ram_size); 19559f4d655SAlexander Graf qdev_prop_set_uint32(vms->cfg, "rnd", rnd); 19659f4d655SAlexander Graf 19759f4d655SAlexander Graf if (!sysbus_realize_and_unref(cfg, errp)) { 19859f4d655SAlexander Graf error_prepend(errp, "Error creating vmapple cfg device: "); 19959f4d655SAlexander Graf return false; 20059f4d655SAlexander Graf } 20159f4d655SAlexander Graf 20259f4d655SAlexander Graf return true; 20359f4d655SAlexander Graf } 20459f4d655SAlexander Graf 20559f4d655SAlexander Graf static void create_gfx(VMAppleMachineState *vms, MemoryRegion *mem) 20659f4d655SAlexander Graf { 20759f4d655SAlexander Graf int irq_gfx = vms->irqmap[VMAPPLE_APV_GFX]; 20859f4d655SAlexander Graf int irq_iosfc = vms->irqmap[VMAPPLE_APV_IOSFC]; 20959f4d655SAlexander Graf SysBusDevice *gfx; 21059f4d655SAlexander Graf 21159f4d655SAlexander Graf gfx = SYS_BUS_DEVICE(qdev_new("apple-gfx-mmio")); 21259f4d655SAlexander Graf sysbus_mmio_map(gfx, 0, vms->memmap[VMAPPLE_APV_GFX].base); 21359f4d655SAlexander Graf sysbus_mmio_map(gfx, 1, vms->memmap[VMAPPLE_APV_IOSFC].base); 21459f4d655SAlexander Graf sysbus_connect_irq(gfx, 0, qdev_get_gpio_in(vms->gic, irq_gfx)); 21559f4d655SAlexander Graf sysbus_connect_irq(gfx, 1, qdev_get_gpio_in(vms->gic, irq_iosfc)); 21659f4d655SAlexander Graf sysbus_realize_and_unref(gfx, &error_fatal); 21759f4d655SAlexander Graf } 21859f4d655SAlexander Graf 21959f4d655SAlexander Graf static void create_aes(VMAppleMachineState *vms, MemoryRegion *mem) 22059f4d655SAlexander Graf { 22159f4d655SAlexander Graf int irq = vms->irqmap[VMAPPLE_AES_1]; 22259f4d655SAlexander Graf SysBusDevice *aes; 22359f4d655SAlexander Graf 22459f4d655SAlexander Graf aes = SYS_BUS_DEVICE(qdev_new(TYPE_APPLE_AES)); 22559f4d655SAlexander Graf sysbus_mmio_map(aes, 0, vms->memmap[VMAPPLE_AES_1].base); 22659f4d655SAlexander Graf sysbus_mmio_map(aes, 1, vms->memmap[VMAPPLE_AES_2].base); 22759f4d655SAlexander Graf sysbus_connect_irq(aes, 0, qdev_get_gpio_in(vms->gic, irq)); 22859f4d655SAlexander Graf sysbus_realize_and_unref(aes, &error_fatal); 22959f4d655SAlexander Graf } 23059f4d655SAlexander Graf 23159f4d655SAlexander Graf static int arm_gic_ppi_index(int cpu_nr, int ppi_index) 23259f4d655SAlexander Graf { 23359f4d655SAlexander Graf return NUM_IRQS + cpu_nr * GIC_INTERNAL + ppi_index; 23459f4d655SAlexander Graf } 23559f4d655SAlexander Graf 23659f4d655SAlexander Graf static void create_gic(VMAppleMachineState *vms, MemoryRegion *mem) 23759f4d655SAlexander Graf { 23859f4d655SAlexander Graf MachineState *ms = MACHINE(vms); 23959f4d655SAlexander Graf /* We create a standalone GIC */ 24059f4d655SAlexander Graf SysBusDevice *gicbusdev; 24159f4d655SAlexander Graf QList *redist_region_count; 24259f4d655SAlexander Graf int i; 24359f4d655SAlexander Graf unsigned int smp_cpus = ms->smp.cpus; 24459f4d655SAlexander Graf 24559f4d655SAlexander Graf vms->gic = qdev_new(gicv3_class_name()); 24659f4d655SAlexander Graf qdev_prop_set_uint32(vms->gic, "revision", 3); 24759f4d655SAlexander Graf qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus); 24859f4d655SAlexander Graf /* 24959f4d655SAlexander Graf * Note that the num-irq property counts both internal and external 25059f4d655SAlexander Graf * interrupts; there are always 32 of the former (mandated by GIC spec). 25159f4d655SAlexander Graf */ 25259f4d655SAlexander Graf qdev_prop_set_uint32(vms->gic, "num-irq", NUM_IRQS + 32); 25359f4d655SAlexander Graf 25459f4d655SAlexander Graf uint32_t redist0_capacity = 25559f4d655SAlexander Graf vms->memmap[VMAPPLE_GIC_REDIST].size / GICV3_REDIST_SIZE; 25659f4d655SAlexander Graf uint32_t redist0_count = MIN(smp_cpus, redist0_capacity); 25759f4d655SAlexander Graf 25859f4d655SAlexander Graf redist_region_count = qlist_new(); 25959f4d655SAlexander Graf qlist_append_int(redist_region_count, redist0_count); 26059f4d655SAlexander Graf qdev_prop_set_array(vms->gic, "redist-region-count", redist_region_count); 26159f4d655SAlexander Graf 26259f4d655SAlexander Graf gicbusdev = SYS_BUS_DEVICE(vms->gic); 26359f4d655SAlexander Graf sysbus_realize_and_unref(gicbusdev, &error_fatal); 26459f4d655SAlexander Graf sysbus_mmio_map(gicbusdev, 0, vms->memmap[VMAPPLE_GIC_DIST].base); 26559f4d655SAlexander Graf sysbus_mmio_map(gicbusdev, 1, vms->memmap[VMAPPLE_GIC_REDIST].base); 26659f4d655SAlexander Graf 26759f4d655SAlexander Graf /* 26859f4d655SAlexander Graf * Wire the outputs from each CPU's generic timer and the GICv3 26959f4d655SAlexander Graf * maintenance interrupt signal to the appropriate GIC PPI inputs, 27059f4d655SAlexander Graf * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs. 27159f4d655SAlexander Graf */ 27259f4d655SAlexander Graf for (i = 0; i < smp_cpus; i++) { 27359f4d655SAlexander Graf DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); 27459f4d655SAlexander Graf 27559f4d655SAlexander Graf /* Map the virt timer to PPI 27 */ 27659f4d655SAlexander Graf qdev_connect_gpio_out(cpudev, GTIMER_VIRT, 27759f4d655SAlexander Graf qdev_get_gpio_in(vms->gic, 27859f4d655SAlexander Graf arm_gic_ppi_index(i, 27))); 27959f4d655SAlexander Graf 28059f4d655SAlexander Graf /* Map the GIC IRQ and FIQ lines to CPU */ 28159f4d655SAlexander Graf sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); 28259f4d655SAlexander Graf sysbus_connect_irq(gicbusdev, i + smp_cpus, 28359f4d655SAlexander Graf qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); 28459f4d655SAlexander Graf } 28559f4d655SAlexander Graf } 28659f4d655SAlexander Graf 28759f4d655SAlexander Graf static void create_uart(const VMAppleMachineState *vms, int uart, 28859f4d655SAlexander Graf MemoryRegion *mem, Chardev *chr) 28959f4d655SAlexander Graf { 29059f4d655SAlexander Graf hwaddr base = vms->memmap[uart].base; 29159f4d655SAlexander Graf int irq = vms->irqmap[uart]; 29259f4d655SAlexander Graf DeviceState *dev = qdev_new(TYPE_PL011); 29359f4d655SAlexander Graf SysBusDevice *s = SYS_BUS_DEVICE(dev); 29459f4d655SAlexander Graf 29559f4d655SAlexander Graf qdev_prop_set_chr(dev, "chardev", chr); 29659f4d655SAlexander Graf sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 29759f4d655SAlexander Graf memory_region_add_subregion(mem, base, 29859f4d655SAlexander Graf sysbus_mmio_get_region(s, 0)); 29959f4d655SAlexander Graf sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq)); 30059f4d655SAlexander Graf } 30159f4d655SAlexander Graf 30259f4d655SAlexander Graf static void create_rtc(const VMAppleMachineState *vms) 30359f4d655SAlexander Graf { 30459f4d655SAlexander Graf hwaddr base = vms->memmap[VMAPPLE_RTC].base; 30559f4d655SAlexander Graf int irq = vms->irqmap[VMAPPLE_RTC]; 30659f4d655SAlexander Graf 30759f4d655SAlexander Graf sysbus_create_simple("pl031", base, qdev_get_gpio_in(vms->gic, irq)); 30859f4d655SAlexander Graf } 30959f4d655SAlexander Graf 31059f4d655SAlexander Graf static DeviceState *gpio_key_dev; 31159f4d655SAlexander Graf static void vmapple_powerdown_req(Notifier *n, void *opaque) 31259f4d655SAlexander Graf { 31359f4d655SAlexander Graf /* use gpio Pin 3 for power button event */ 31459f4d655SAlexander Graf qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1); 31559f4d655SAlexander Graf } 31659f4d655SAlexander Graf 31759f4d655SAlexander Graf static void create_gpio_devices(const VMAppleMachineState *vms, int gpio, 31859f4d655SAlexander Graf MemoryRegion *mem) 31959f4d655SAlexander Graf { 32059f4d655SAlexander Graf DeviceState *pl061_dev; 32159f4d655SAlexander Graf hwaddr base = vms->memmap[gpio].base; 32259f4d655SAlexander Graf int irq = vms->irqmap[gpio]; 32359f4d655SAlexander Graf SysBusDevice *s; 32459f4d655SAlexander Graf 32559f4d655SAlexander Graf pl061_dev = qdev_new("pl061"); 32659f4d655SAlexander Graf /* Pull lines down to 0 if not driven by the PL061 */ 32759f4d655SAlexander Graf qdev_prop_set_uint32(pl061_dev, "pullups", 0); 32859f4d655SAlexander Graf qdev_prop_set_uint32(pl061_dev, "pulldowns", 0xff); 32959f4d655SAlexander Graf s = SYS_BUS_DEVICE(pl061_dev); 33059f4d655SAlexander Graf sysbus_realize_and_unref(s, &error_fatal); 33159f4d655SAlexander Graf memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0)); 33259f4d655SAlexander Graf sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq)); 33359f4d655SAlexander Graf gpio_key_dev = sysbus_create_simple("gpio-key", -1, 33459f4d655SAlexander Graf qdev_get_gpio_in(pl061_dev, 3)); 33559f4d655SAlexander Graf } 33659f4d655SAlexander Graf 33759f4d655SAlexander Graf static void vmapple_firmware_init(VMAppleMachineState *vms, 33859f4d655SAlexander Graf MemoryRegion *sysmem) 33959f4d655SAlexander Graf { 34059f4d655SAlexander Graf hwaddr size = vms->memmap[VMAPPLE_FIRMWARE].size; 34159f4d655SAlexander Graf hwaddr base = vms->memmap[VMAPPLE_FIRMWARE].base; 34259f4d655SAlexander Graf const char *bios_name; 34359f4d655SAlexander Graf int image_size; 34459f4d655SAlexander Graf char *fname; 34559f4d655SAlexander Graf 34659f4d655SAlexander Graf bios_name = MACHINE(vms)->firmware; 34759f4d655SAlexander Graf if (!bios_name) { 34859f4d655SAlexander Graf error_report("No firmware specified"); 34959f4d655SAlexander Graf exit(1); 35059f4d655SAlexander Graf } 35159f4d655SAlexander Graf 35259f4d655SAlexander Graf fname = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); 35359f4d655SAlexander Graf if (!fname) { 35459f4d655SAlexander Graf error_report("Could not find ROM image '%s'", bios_name); 35559f4d655SAlexander Graf exit(1); 35659f4d655SAlexander Graf } 35759f4d655SAlexander Graf 35859f4d655SAlexander Graf memory_region_init_ram(&vms->fw_mr, NULL, "firmware", size, &error_fatal); 35959f4d655SAlexander Graf image_size = load_image_mr(fname, &vms->fw_mr); 36059f4d655SAlexander Graf 36159f4d655SAlexander Graf g_free(fname); 36259f4d655SAlexander Graf if (image_size < 0) { 36359f4d655SAlexander Graf error_report("Could not load ROM image '%s'", bios_name); 36459f4d655SAlexander Graf exit(1); 36559f4d655SAlexander Graf } 36659f4d655SAlexander Graf 36759f4d655SAlexander Graf memory_region_add_subregion(get_system_memory(), base, &vms->fw_mr); 36859f4d655SAlexander Graf } 36959f4d655SAlexander Graf 37059f4d655SAlexander Graf static void create_pcie(VMAppleMachineState *vms) 37159f4d655SAlexander Graf { 37259f4d655SAlexander Graf hwaddr base_mmio = vms->memmap[VMAPPLE_PCIE_MMIO].base; 37359f4d655SAlexander Graf hwaddr size_mmio = vms->memmap[VMAPPLE_PCIE_MMIO].size; 37459f4d655SAlexander Graf hwaddr base_ecam = vms->memmap[VMAPPLE_PCIE_ECAM].base; 37559f4d655SAlexander Graf hwaddr size_ecam = vms->memmap[VMAPPLE_PCIE_ECAM].size; 37659f4d655SAlexander Graf int irq = vms->irqmap[VMAPPLE_PCIE]; 37759f4d655SAlexander Graf MemoryRegion *mmio_alias; 37859f4d655SAlexander Graf MemoryRegion *mmio_reg; 37959f4d655SAlexander Graf MemoryRegion *ecam_reg; 38059f4d655SAlexander Graf DeviceState *dev; 38159f4d655SAlexander Graf int i; 38259f4d655SAlexander Graf PCIHostState *pci; 38359f4d655SAlexander Graf DeviceState *usb_controller; 38459f4d655SAlexander Graf USBBus *usb_bus; 38559f4d655SAlexander Graf 38659f4d655SAlexander Graf dev = qdev_new(TYPE_GPEX_HOST); 38759f4d655SAlexander Graf qdev_prop_set_uint32(dev, "num-irqs", GPEX_NUM_IRQS); 38859f4d655SAlexander Graf sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 38959f4d655SAlexander Graf 39059f4d655SAlexander Graf /* Map only the first size_ecam bytes of ECAM space */ 39159f4d655SAlexander Graf ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); 39259f4d655SAlexander Graf memory_region_init_alias(&vms->ecam_alias, OBJECT(dev), "pcie-ecam", 39359f4d655SAlexander Graf ecam_reg, 0, size_ecam); 39459f4d655SAlexander Graf memory_region_add_subregion(get_system_memory(), base_ecam, 39559f4d655SAlexander Graf &vms->ecam_alias); 39659f4d655SAlexander Graf 39759f4d655SAlexander Graf /* 39859f4d655SAlexander Graf * Map the MMIO window from [0x50000000-0x7fff0000] in PCI space into 39959f4d655SAlexander Graf * system address space at [0x50000000-0x7fff0000]. 40059f4d655SAlexander Graf */ 40159f4d655SAlexander Graf mmio_alias = g_new0(MemoryRegion, 1); 40259f4d655SAlexander Graf mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); 40359f4d655SAlexander Graf memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", 40459f4d655SAlexander Graf mmio_reg, base_mmio, size_mmio); 40559f4d655SAlexander Graf memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias); 40659f4d655SAlexander Graf 40759f4d655SAlexander Graf for (i = 0; i < GPEX_NUM_IRQS; i++) { 40859f4d655SAlexander Graf sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, 40959f4d655SAlexander Graf qdev_get_gpio_in(vms->gic, irq + i)); 41059f4d655SAlexander Graf gpex_set_irq_num(GPEX_HOST(dev), i, irq + i); 41159f4d655SAlexander Graf } 41259f4d655SAlexander Graf 41359f4d655SAlexander Graf pci = PCI_HOST_BRIDGE(dev); 41459f4d655SAlexander Graf vms->bus = pci->bus; 41559f4d655SAlexander Graf g_assert(vms->bus); 41659f4d655SAlexander Graf 41759f4d655SAlexander Graf while ((dev = qemu_create_nic_device("virtio-net-pci", true, NULL))) { 41859f4d655SAlexander Graf qdev_realize_and_unref(dev, BUS(vms->bus), &error_fatal); 41959f4d655SAlexander Graf } 42059f4d655SAlexander Graf 42159f4d655SAlexander Graf if (defaults_enabled()) { 42259f4d655SAlexander Graf usb_controller = qdev_new(TYPE_QEMU_XHCI); 42359f4d655SAlexander Graf qdev_realize_and_unref(usb_controller, BUS(pci->bus), &error_fatal); 42459f4d655SAlexander Graf 42559f4d655SAlexander Graf usb_bus = USB_BUS(object_resolve_type_unambiguous(TYPE_USB_BUS, 42659f4d655SAlexander Graf &error_fatal)); 42759f4d655SAlexander Graf usb_create_simple(usb_bus, "usb-kbd"); 42859f4d655SAlexander Graf usb_create_simple(usb_bus, "usb-tablet"); 42959f4d655SAlexander Graf } 43059f4d655SAlexander Graf } 43159f4d655SAlexander Graf 43259f4d655SAlexander Graf static void vmapple_reset(void *opaque) 43359f4d655SAlexander Graf { 43459f4d655SAlexander Graf VMAppleMachineState *vms = opaque; 43559f4d655SAlexander Graf hwaddr base = vms->memmap[VMAPPLE_FIRMWARE].base; 43659f4d655SAlexander Graf 43759f4d655SAlexander Graf cpu_set_pc(first_cpu, base); 43859f4d655SAlexander Graf } 43959f4d655SAlexander Graf 44059f4d655SAlexander Graf static void mach_vmapple_init(MachineState *machine) 44159f4d655SAlexander Graf { 44259f4d655SAlexander Graf VMAppleMachineState *vms = VMAPPLE_MACHINE(machine); 44359f4d655SAlexander Graf MachineClass *mc = MACHINE_GET_CLASS(machine); 44459f4d655SAlexander Graf const CPUArchIdList *possible_cpus; 44559f4d655SAlexander Graf MemoryRegion *sysmem = get_system_memory(); 44659f4d655SAlexander Graf int n; 44759f4d655SAlexander Graf unsigned int smp_cpus = machine->smp.cpus; 44859f4d655SAlexander Graf unsigned int max_cpus = machine->smp.max_cpus; 44959f4d655SAlexander Graf 45059f4d655SAlexander Graf vms->memmap = memmap; 45159f4d655SAlexander Graf machine->usb = true; 45259f4d655SAlexander Graf 45359f4d655SAlexander Graf possible_cpus = mc->possible_cpu_arch_ids(machine); 45459f4d655SAlexander Graf assert(possible_cpus->len == max_cpus); 45559f4d655SAlexander Graf for (n = 0; n < possible_cpus->len; n++) { 45659f4d655SAlexander Graf Object *cpu; 45759f4d655SAlexander Graf CPUState *cs; 45859f4d655SAlexander Graf 45959f4d655SAlexander Graf if (n >= smp_cpus) { 46059f4d655SAlexander Graf break; 46159f4d655SAlexander Graf } 46259f4d655SAlexander Graf 46359f4d655SAlexander Graf cpu = object_new(possible_cpus->cpus[n].type); 46459f4d655SAlexander Graf object_property_set_int(cpu, "mp-affinity", 46559f4d655SAlexander Graf possible_cpus->cpus[n].arch_id, &error_fatal); 46659f4d655SAlexander Graf 46759f4d655SAlexander Graf cs = CPU(cpu); 46859f4d655SAlexander Graf cs->cpu_index = n; 46959f4d655SAlexander Graf 47059f4d655SAlexander Graf numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpu), 47159f4d655SAlexander Graf &error_fatal); 47259f4d655SAlexander Graf 47359f4d655SAlexander Graf if (object_property_find(cpu, "has_el3")) { 47459f4d655SAlexander Graf object_property_set_bool(cpu, "has_el3", false, &error_fatal); 47559f4d655SAlexander Graf } 47659f4d655SAlexander Graf if (object_property_find(cpu, "has_el2")) { 47759f4d655SAlexander Graf object_property_set_bool(cpu, "has_el2", false, &error_fatal); 47859f4d655SAlexander Graf } 47959f4d655SAlexander Graf object_property_set_int(cpu, "psci-conduit", QEMU_PSCI_CONDUIT_HVC, 48059f4d655SAlexander Graf &error_fatal); 48159f4d655SAlexander Graf 48259f4d655SAlexander Graf /* Secondary CPUs start in PSCI powered-down state */ 48359f4d655SAlexander Graf if (n > 0) { 48459f4d655SAlexander Graf object_property_set_bool(cpu, "start-powered-off", true, 48559f4d655SAlexander Graf &error_fatal); 48659f4d655SAlexander Graf } 48759f4d655SAlexander Graf 48859f4d655SAlexander Graf object_property_set_link(cpu, "memory", OBJECT(sysmem), &error_abort); 48959f4d655SAlexander Graf qdev_realize(DEVICE(cpu), NULL, &error_fatal); 49059f4d655SAlexander Graf object_unref(cpu); 49159f4d655SAlexander Graf } 49259f4d655SAlexander Graf 49359f4d655SAlexander Graf memory_region_add_subregion(sysmem, vms->memmap[VMAPPLE_MEM].base, 49459f4d655SAlexander Graf machine->ram); 49559f4d655SAlexander Graf 49659f4d655SAlexander Graf create_gic(vms, sysmem); 49759f4d655SAlexander Graf create_bdif(vms, sysmem); 49859f4d655SAlexander Graf create_pvpanic(vms, sysmem); 49959f4d655SAlexander Graf create_aes(vms, sysmem); 50059f4d655SAlexander Graf create_gfx(vms, sysmem); 50159f4d655SAlexander Graf create_uart(vms, VMAPPLE_UART, sysmem, serial_hd(0)); 50259f4d655SAlexander Graf create_rtc(vms); 50359f4d655SAlexander Graf create_pcie(vms); 50459f4d655SAlexander Graf 50559f4d655SAlexander Graf create_gpio_devices(vms, VMAPPLE_GPIO, sysmem); 50659f4d655SAlexander Graf 50759f4d655SAlexander Graf vmapple_firmware_init(vms, sysmem); 50859f4d655SAlexander Graf create_cfg(vms, sysmem, &error_fatal); 50959f4d655SAlexander Graf 51059f4d655SAlexander Graf /* connect powerdown request */ 51159f4d655SAlexander Graf vms->powerdown_notifier.notify = vmapple_powerdown_req; 51259f4d655SAlexander Graf qemu_register_powerdown_notifier(&vms->powerdown_notifier); 51359f4d655SAlexander Graf 51459f4d655SAlexander Graf vms->bootinfo.ram_size = machine->ram_size; 51559f4d655SAlexander Graf vms->bootinfo.board_id = -1; 51659f4d655SAlexander Graf vms->bootinfo.loader_start = vms->memmap[VMAPPLE_MEM].base; 51759f4d655SAlexander Graf vms->bootinfo.skip_dtb_autoload = true; 51859f4d655SAlexander Graf vms->bootinfo.firmware_loaded = true; 51959f4d655SAlexander Graf arm_load_kernel(ARM_CPU(first_cpu), machine, &vms->bootinfo); 52059f4d655SAlexander Graf 52159f4d655SAlexander Graf qemu_register_reset(vmapple_reset, vms); 52259f4d655SAlexander Graf } 52359f4d655SAlexander Graf 52459f4d655SAlexander Graf static CpuInstanceProperties 52559f4d655SAlexander Graf vmapple_cpu_index_to_props(MachineState *ms, unsigned cpu_index) 52659f4d655SAlexander Graf { 52759f4d655SAlexander Graf MachineClass *mc = MACHINE_GET_CLASS(ms); 52859f4d655SAlexander Graf const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); 52959f4d655SAlexander Graf 53059f4d655SAlexander Graf assert(cpu_index < possible_cpus->len); 53159f4d655SAlexander Graf return possible_cpus->cpus[cpu_index].props; 53259f4d655SAlexander Graf } 53359f4d655SAlexander Graf 53459f4d655SAlexander Graf 53559f4d655SAlexander Graf static int64_t vmapple_get_default_cpu_node_id(const MachineState *ms, int idx) 53659f4d655SAlexander Graf { 53759f4d655SAlexander Graf return idx % ms->numa_state->num_nodes; 53859f4d655SAlexander Graf } 53959f4d655SAlexander Graf 54059f4d655SAlexander Graf static const CPUArchIdList *vmapple_possible_cpu_arch_ids(MachineState *ms) 54159f4d655SAlexander Graf { 54259f4d655SAlexander Graf int n; 54359f4d655SAlexander Graf unsigned int max_cpus = ms->smp.max_cpus; 54459f4d655SAlexander Graf 54559f4d655SAlexander Graf if (ms->possible_cpus) { 54659f4d655SAlexander Graf assert(ms->possible_cpus->len == max_cpus); 54759f4d655SAlexander Graf return ms->possible_cpus; 54859f4d655SAlexander Graf } 54959f4d655SAlexander Graf 55059f4d655SAlexander Graf ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + 55159f4d655SAlexander Graf sizeof(CPUArchId) * max_cpus); 55259f4d655SAlexander Graf ms->possible_cpus->len = max_cpus; 55359f4d655SAlexander Graf for (n = 0; n < ms->possible_cpus->len; n++) { 55459f4d655SAlexander Graf ms->possible_cpus->cpus[n].type = ms->cpu_type; 55559f4d655SAlexander Graf ms->possible_cpus->cpus[n].arch_id = 55659f4d655SAlexander Graf arm_build_mp_affinity(n, GICV3_TARGETLIST_BITS); 55759f4d655SAlexander Graf ms->possible_cpus->cpus[n].props.has_thread_id = true; 55859f4d655SAlexander Graf ms->possible_cpus->cpus[n].props.thread_id = n; 55959f4d655SAlexander Graf } 56059f4d655SAlexander Graf return ms->possible_cpus; 56159f4d655SAlexander Graf } 56259f4d655SAlexander Graf 56359f4d655SAlexander Graf static GlobalProperty vmapple_compat_defaults[] = { 56459f4d655SAlexander Graf { TYPE_VIRTIO_PCI, "disable-legacy", "on" }, 56559f4d655SAlexander Graf /* 56659f4d655SAlexander Graf * macOS XHCI driver attempts to schedule events onto even rings 1 & 2 56759f4d655SAlexander Graf * even when (as here) there is no MSI(-X) support. Disabling interrupter 56859f4d655SAlexander Graf * mapping in the XHCI controller works around the problem. 56959f4d655SAlexander Graf */ 57059f4d655SAlexander Graf { TYPE_XHCI_PCI, "conditional-intr-mapping", "on" }, 57159f4d655SAlexander Graf }; 57259f4d655SAlexander Graf 573*12d1a768SPhilippe Mathieu-Daudé static void vmapple_machine_class_init(ObjectClass *oc, const void *data) 57459f4d655SAlexander Graf { 57559f4d655SAlexander Graf MachineClass *mc = MACHINE_CLASS(oc); 57659f4d655SAlexander Graf 57759f4d655SAlexander Graf mc->init = mach_vmapple_init; 57859f4d655SAlexander Graf mc->max_cpus = 32; 57959f4d655SAlexander Graf mc->block_default_type = IF_VIRTIO; 58059f4d655SAlexander Graf mc->no_cdrom = 1; 58159f4d655SAlexander Graf mc->pci_allow_0_address = true; 58259f4d655SAlexander Graf mc->minimum_page_bits = 12; 58359f4d655SAlexander Graf mc->possible_cpu_arch_ids = vmapple_possible_cpu_arch_ids; 58459f4d655SAlexander Graf mc->cpu_index_to_instance_props = vmapple_cpu_index_to_props; 58559f4d655SAlexander Graf mc->default_cpu_type = ARM_CPU_TYPE_NAME("host"); 58659f4d655SAlexander Graf mc->get_default_cpu_node_id = vmapple_get_default_cpu_node_id; 58759f4d655SAlexander Graf mc->default_ram_id = "mach-vmapple.ram"; 58859f4d655SAlexander Graf mc->desc = "Apple aarch64 Virtual Machine"; 58959f4d655SAlexander Graf 59059f4d655SAlexander Graf compat_props_add(mc->compat_props, vmapple_compat_defaults, 59159f4d655SAlexander Graf G_N_ELEMENTS(vmapple_compat_defaults)); 59259f4d655SAlexander Graf } 59359f4d655SAlexander Graf 59459f4d655SAlexander Graf static void vmapple_instance_init(Object *obj) 59559f4d655SAlexander Graf { 59659f4d655SAlexander Graf VMAppleMachineState *vms = VMAPPLE_MACHINE(obj); 59759f4d655SAlexander Graf 59859f4d655SAlexander Graf vms->irqmap = irqmap; 59959f4d655SAlexander Graf 60059f4d655SAlexander Graf object_property_add_uint64_ptr(obj, "uuid", &vms->uuid, 60159f4d655SAlexander Graf OBJ_PROP_FLAG_READWRITE); 60259f4d655SAlexander Graf object_property_set_description(obj, "uuid", "Machine UUID (SDOM)"); 60359f4d655SAlexander Graf } 60459f4d655SAlexander Graf 60559f4d655SAlexander Graf static const TypeInfo vmapple_machine_info = { 60659f4d655SAlexander Graf .name = TYPE_VMAPPLE_MACHINE, 60759f4d655SAlexander Graf .parent = TYPE_MACHINE, 60859f4d655SAlexander Graf .instance_size = sizeof(VMAppleMachineState), 60959f4d655SAlexander Graf .class_init = vmapple_machine_class_init, 61059f4d655SAlexander Graf .instance_init = vmapple_instance_init, 61159f4d655SAlexander Graf }; 61259f4d655SAlexander Graf 61359f4d655SAlexander Graf static void machvmapple_machine_init(void) 61459f4d655SAlexander Graf { 61559f4d655SAlexander Graf type_register_static(&vmapple_machine_info); 61659f4d655SAlexander Graf } 61759f4d655SAlexander Graf type_init(machvmapple_machine_init); 61859f4d655SAlexander Graf 619