Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/MAINTAINERS b/MAINTAINERS
- index 6111b6b4d9..3104e58eff 100644
- --- a/MAINTAINERS
- +++ b/MAINTAINERS
- @@ -2573,6 +2573,12 @@ F: hw/usb/canokey.c
- F: hw/usb/canokey.h
- F: docs/system/devices/canokey.rst
- +VMapple
- +M: Alexander Graf <[email protected]>
- +S: Maintained
- +F: hw/vmapple/*
- +F: include/hw/vmapple/*
- +
- Subsystems
- ----------
- Overall Audio backends
- diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c
- index a44cf1c144..dd285c694c 100644
- --- a/accel/hvf/hvf-accel-ops.c
- +++ b/accel/hvf/hvf-accel-ops.c
- @@ -88,7 +88,7 @@ struct mac_slot {
- uint64_t gva;
- };
- -struct mac_slot mac_slots[32];
- +struct mac_slot mac_slots[512];
- static int do_hvf_set_memory(hvf_slot *slot, hv_memory_flags_t flags)
- {
- diff --git a/hw/Kconfig b/hw/Kconfig
- index ba62ff6417..d99854afdd 100644
- --- a/hw/Kconfig
- +++ b/hw/Kconfig
- @@ -41,6 +41,7 @@ source tpm/Kconfig
- source usb/Kconfig
- source virtio/Kconfig
- source vfio/Kconfig
- +source vmapple/Kconfig
- source xen/Kconfig
- source watchdog/Kconfig
- diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
- index bc89eb4806..a786849238 100644
- --- a/hw/arm/sbsa-ref.c
- +++ b/hw/arm/sbsa-ref.c
- @@ -681,7 +681,7 @@ static void create_pcie(SBSAMachineState *sms)
- /* Map IO port space */
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
- - for (i = 0; i < GPEX_NUM_IRQS; i++) {
- + for (i = 0; i < PCI_NUM_PINS; i++) {
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
- qdev_get_gpio_in(sms->gic, irq + i));
- gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
- diff --git a/hw/arm/virt.c b/hw/arm/virt.c
- index 7d9dbc2663..40ce59a68a 100644
- --- a/hw/arm/virt.c
- +++ b/hw/arm/virt.c
- @@ -1467,7 +1467,7 @@ static void create_pcie(VirtMachineState *vms)
- /* Map IO port space */
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
- - for (i = 0; i < GPEX_NUM_IRQS; i++) {
- + for (i = 0; i < PCI_NUM_PINS; i++) {
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
- qdev_get_gpio_in(vms->gic, irq + i));
- gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
- diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
- index 39e7f23fab..76b85bb3cb 100644
- --- a/hw/block/virtio-blk.c
- +++ b/hw/block/virtio-blk.c
- @@ -1120,6 +1120,20 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
- break;
- }
- + case VIRTIO_BLK_T_APPLE1:
- + {
- + if (s->conf.x_apple_type) {
- + /* Only valid on Apple Virtio */
- + char buf[iov_size(in_iov, in_num)];
- + memset(buf, 0, sizeof(buf));
- + iov_from_buf(in_iov, in_num, 0, buf, sizeof(buf));
- + virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
- + } else {
- + virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
- + }
- + virtio_blk_free_request(req);
- + break;
- + }
- default:
- virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
- virtio_blk_free_request(req);
- @@ -1351,6 +1365,10 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
- } else {
- blkcfg.zoned.model = VIRTIO_BLK_Z_NONE;
- }
- + if (s->conf.x_apple_type) {
- + /* Apple abuses the same location for its type id */
- + blkcfg.max_secure_erase_sectors = s->conf.x_apple_type;
- + }
- memcpy(config, &blkcfg, s->config_size);
- }
- @@ -1625,6 +1643,10 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
- s->config_size = virtio_get_config_size(&virtio_blk_cfg_size_params,
- s->host_features);
- + if (s->conf.x_apple_type) {
- + /* Apple Virtio puts the blk type at 0x3c, make sure we have space. */
- + s->config_size = MAX(s->config_size, 0x3d);
- + }
- virtio_init(vdev, VIRTIO_ID_BLOCK, s->config_size);
- s->blk = conf->conf.blk;
- @@ -1734,6 +1756,7 @@ static Property virtio_blk_properties[] = {
- conf.max_write_zeroes_sectors, BDRV_REQUEST_MAX_SECTORS),
- DEFINE_PROP_BOOL("x-enable-wce-if-config-wce", VirtIOBlock,
- conf.x_enable_wce_if_config_wce, true),
- + DEFINE_PROP_UINT32("x-apple-type", VirtIOBlock, conf.x_apple_type, 0),
- DEFINE_PROP_END_OF_LIST(),
- };
- diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
- index 7227a2156c..9ca007b870 100644
- --- a/hw/i386/microvm.c
- +++ b/hw/i386/microvm.c
- @@ -139,7 +139,7 @@ static void create_gpex(MicrovmMachineState *mms)
- mms->gpex.mmio64.base, mmio64_alias);
- }
- - for (i = 0; i < GPEX_NUM_IRQS; i++) {
- + for (i = 0; i < PCI_NUM_PINS; i++) {
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
- x86ms->gsi[mms->gpex.irq + i]);
- }
- diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
- index e19b042ce8..67ff03cb10 100644
- --- a/hw/loongarch/virt.c
- +++ b/hw/loongarch/virt.c
- @@ -533,7 +533,7 @@ static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState *
- memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE,
- pio_alias);
- - for (i = 0; i < GPEX_NUM_IRQS; i++) {
- + for (i = 0; i < PCI_NUM_PINS; i++) {
- sysbus_connect_irq(d, i,
- qdev_get_gpio_in(pch_pic, 16 + i));
- gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i);
- diff --git a/hw/meson.build b/hw/meson.build
- index c7ac7d3d75..e156a6618f 100644
- --- a/hw/meson.build
- +++ b/hw/meson.build
- @@ -40,6 +40,7 @@ subdir('tpm')
- subdir('usb')
- subdir('vfio')
- subdir('virtio')
- +subdir('vmapple')
- subdir('watchdog')
- subdir('xen')
- subdir('xenpv')
- diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
- index 3ad0a223df..c6162c8efc 100644
- --- a/hw/mips/loongson3_virt.c
- +++ b/hw/mips/loongson3_virt.c
- @@ -438,7 +438,7 @@ static inline void loongson3_virt_devices_init(MachineState *machine,
- virt_memmap[VIRT_PCIE_PIO].base, s->pio_alias);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].base);
- - for (i = 0; i < GPEX_NUM_IRQS; i++) {
- + for (i = 0; i < PCI_NUM_PINS; i++) {
- irq = qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
- gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i);
- diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
- index 6996d265e4..b69746a60a 100644
- --- a/hw/misc/Kconfig
- +++ b/hw/misc/Kconfig
- @@ -125,6 +125,10 @@ config PVPANIC_ISA
- depends on ISA_BUS
- select PVPANIC_COMMON
- +config PVPANIC_MMIO
- + bool
- + select PVPANIC_COMMON
- +
- config AUX
- bool
- select I2C
- diff --git a/hw/misc/meson.build b/hw/misc/meson.build
- index 892f8b91c5..3aea9a5e68 100644
- --- a/hw/misc/meson.build
- +++ b/hw/misc/meson.build
- @@ -115,6 +115,7 @@ system_ss.add(when: 'CONFIG_ARMSSE_CPUID', if_true: files('armsse-cpuid.c'))
- system_ss.add(when: 'CONFIG_ARMSSE_MHU', if_true: files('armsse-mhu.c'))
- system_ss.add(when: 'CONFIG_PVPANIC_ISA', if_true: files('pvpanic-isa.c'))
- +system_ss.add(when: 'CONFIG_PVPANIC_MMIO', if_true: files('pvpanic-mmio.c'))
- system_ss.add(when: 'CONFIG_PVPANIC_PCI', if_true: files('pvpanic-pci.c'))
- system_ss.add(when: 'CONFIG_AUX', if_true: files('auxbus.c'))
- system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
- diff --git a/hw/misc/pvpanic-mmio.c b/hw/misc/pvpanic-mmio.c
- new file mode 100644
- index 0000000000..aebe7227e6
- --- /dev/null
- +++ b/hw/misc/pvpanic-mmio.c
- @@ -0,0 +1,66 @@
- +/*
- + * QEMU simulated pvpanic device (MMIO frontend)
- + *
- + * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- + *
- + * This work is licensed under the terms of the GNU GPL, version 2 or later.
- + * See the COPYING file in the top-level directory.
- + */
- +
- +#include "qemu/osdep.h"
- +#include "qemu/module.h"
- +#include "sysemu/runstate.h"
- +
- +#include "hw/nvram/fw_cfg.h"
- +#include "hw/qdev-properties.h"
- +#include "hw/misc/pvpanic.h"
- +#include "qom/object.h"
- +#include "hw/isa/isa.h"
- +#include "standard-headers/linux/pvpanic.h"
- +
- +OBJECT_DECLARE_SIMPLE_TYPE(PVPanicMMIOState, PVPANIC_MMIO_DEVICE)
- +
- +#define PVPANIC_MMIO_SIZE 0x2
- +
- +struct PVPanicMMIOState {
- + SysBusDevice parent_obj;
- +
- + PVPanicState pvpanic;
- +};
- +
- +static void pvpanic_mmio_initfn(Object *obj)
- +{
- + PVPanicMMIOState *s = PVPANIC_MMIO_DEVICE(obj);
- +
- + pvpanic_setup_io(&s->pvpanic, DEVICE(s), PVPANIC_MMIO_SIZE);
- + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->pvpanic.mr);
- +}
- +
- +static Property pvpanic_mmio_properties[] = {
- + DEFINE_PROP_UINT8("events", PVPanicMMIOState, pvpanic.events,
- + PVPANIC_PANICKED | PVPANIC_CRASH_LOADED),
- + DEFINE_PROP_END_OF_LIST(),
- +};
- +
- +static void pvpanic_mmio_class_init(ObjectClass *klass, void *data)
- +{
- + DeviceClass *dc = DEVICE_CLASS(klass);
- +
- + device_class_set_props(dc, pvpanic_mmio_properties);
- + set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- +}
- +
- +static const TypeInfo pvpanic_mmio_info = {
- + .name = TYPE_PVPANIC_MMIO_DEVICE,
- + .parent = TYPE_SYS_BUS_DEVICE,
- + .instance_size = sizeof(PVPanicMMIOState),
- + .instance_init = pvpanic_mmio_initfn,
- + .class_init = pvpanic_mmio_class_init,
- +};
- +
- +static void pvpanic_register_types(void)
- +{
- + type_register_static(&pvpanic_mmio_info);
- +}
- +
- +type_init(pvpanic_register_types)
- diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c
- index f8a68a6a6b..16a5676c4b 100644
- --- a/hw/openrisc/virt.c
- +++ b/hw/openrisc/virt.c
- @@ -318,7 +318,7 @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base,
- {
- int pin, dev;
- uint32_t irq_map_stride = 0;
- - uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * 6] = {};
- + uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 6] = {};
- uint32_t *irq_map = full_irq_map;
- /*
- @@ -330,11 +330,11 @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base,
- * possible slot) seeing the interrupt-map-mask will allow the table
- * to wrap to any number of devices.
- */
- - for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
- + for (dev = 0; dev < PCI_NUM_PINS; dev++) {
- int devfn = dev << 3;
- - for (pin = 0; pin < GPEX_NUM_IRQS; pin++) {
- - int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
- + for (pin = 0; pin < PCI_NUM_PINS; pin++) {
- + int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
- int i = 0;
- /* Fill PCI address cells */
- @@ -357,7 +357,7 @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base,
- }
- qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
- - GPEX_NUM_IRQS * GPEX_NUM_IRQS *
- + PCI_NUM_PINS * PCI_NUM_PINS *
- irq_map_stride * sizeof(uint32_t));
- qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
- @@ -409,7 +409,7 @@ static void openrisc_virt_pcie_init(OR1KVirtState *state,
- memory_region_add_subregion(get_system_memory(), pio_base, alias);
- /* Connect IRQ lines. */
- - for (i = 0; i < GPEX_NUM_IRQS; i++) {
- + for (i = 0; i < PCI_NUM_PINS; i++) {
- pcie_irq = get_per_cpu_irq(cpus, num_cpus, irq_base + i);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pcie_irq);
- diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c
- index a6752fac5e..7d5d996f34 100644
- --- a/hw/pci-host/gpex.c
- +++ b/hw/pci-host/gpex.c
- @@ -32,6 +32,7 @@
- #include "qemu/osdep.h"
- #include "qapi/error.h"
- #include "hw/irq.h"
- +#include "hw/pci/pci_bus.h"
- #include "hw/pci-host/gpex.h"
- #include "hw/qdev-properties.h"
- #include "migration/vmstate.h"
- @@ -50,7 +51,7 @@ static void gpex_set_irq(void *opaque, int irq_num, int level)
- int gpex_set_irq_num(GPEXHost *s, int index, int gsi)
- {
- - if (index >= GPEX_NUM_IRQS) {
- + if (index >= s->nr_irqs) {
- return -EINVAL;
- }
- @@ -74,14 +75,29 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opaque, int pin)
- return route;
- }
- +static int gpex_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin)
- +{
- + PCIBus *bus = pci_device_root_bus(pci_dev);
- +
- + return (PCI_SLOT(pci_dev->devfn) + pin) % bus->nirq;
- +}
- +
- static void gpex_host_realize(DeviceState *dev, Error **errp)
- {
- PCIHostState *pci = PCI_HOST_BRIDGE(dev);
- GPEXHost *s = GPEX_HOST(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
- + pci_map_irq_fn map_irq_fn = pci_swizzle_map_irq_fn;
- int i;
- + s->irq = g_malloc0(s->nr_irqs * sizeof(*s->irq));
- + s->irq_num = g_malloc0(s->nr_irqs * sizeof(*s->irq_num));
- +
- + if (s->nr_irqs != PCI_NUM_PINS) {
- + map_irq_fn = gpex_swizzle_map_irq_fn;
- + }
- +
- pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX);
- sysbus_init_mmio(sbd, &pex->mmio);
- @@ -128,19 +144,27 @@ static void gpex_host_realize(DeviceState *dev, Error **errp)
- sysbus_init_mmio(sbd, &s->io_ioport);
- }
- - for (i = 0; i < GPEX_NUM_IRQS; i++) {
- + for (i = 0; i < s->nr_irqs; i++) {
- sysbus_init_irq(sbd, &s->irq[i]);
- s->irq_num[i] = -1;
- }
- - pci->bus = pci_register_root_bus(dev, "pcie.0", gpex_set_irq,
- - pci_swizzle_map_irq_fn, s, &s->io_mmio,
- - &s->io_ioport, 0, 4, TYPE_PCIE_BUS);
- + pci->bus = pci_register_root_bus(dev, "pcie.0", gpex_set_irq, map_irq_fn,
- + s, &s->io_mmio, &s->io_ioport, 0,
- + s->nr_irqs, TYPE_PCIE_BUS);
- pci_bus_set_route_irq_fn(pci->bus, gpex_route_intx_pin_to_irq);
- qdev_realize(DEVICE(&s->gpex_root), BUS(pci->bus), &error_fatal);
- }
- +static void gpex_host_unrealize(DeviceState *dev)
- +{
- + GPEXHost *s = GPEX_HOST(dev);
- +
- + g_free(s->irq);
- + g_free(s->irq_num);
- +}
- +
- static const char *gpex_host_root_bus_path(PCIHostState *host_bridge,
- PCIBus *rootbus)
- {
- @@ -154,6 +178,7 @@ static Property gpex_host_properties[] = {
- */
- DEFINE_PROP_BOOL("allow-unmapped-accesses", GPEXHost,
- allow_unmapped_accesses, true),
- + DEFINE_PROP_UINT32("nr-irqs", GPEXHost, nr_irqs, PCI_NUM_PINS),
- DEFINE_PROP_END_OF_LIST(),
- };
- @@ -164,6 +189,7 @@ static void gpex_host_class_init(ObjectClass *klass, void *data)
- hc->root_bus_path = gpex_host_root_bus_path;
- dc->realize = gpex_host_realize;
- + dc->unrealize = gpex_host_unrealize;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->fw_name = "pci";
- device_class_set_props(dc, gpex_host_properties);
- diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
- index 99c4e6314b..c13e8c8142 100644
- --- a/hw/riscv/virt.c
- +++ b/hw/riscv/virt.c
- @@ -175,7 +175,7 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename,
- {
- int pin, dev;
- uint32_t irq_map_stride = 0;
- - uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS *
- + uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS *
- FDT_MAX_INT_MAP_WIDTH] = {};
- uint32_t *irq_map = full_irq_map;
- @@ -187,11 +187,11 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename,
- * possible slot) seeing the interrupt-map-mask will allow the table
- * to wrap to any number of devices.
- */
- - for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
- + for (dev = 0; dev < PCI_NUM_PINS; dev++) {
- int devfn = dev * 0x8;
- - for (pin = 0; pin < GPEX_NUM_IRQS; pin++) {
- - int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
- + for (pin = 0; pin < PCI_NUM_PINS; pin++) {
- + int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
- int i = 0;
- /* Fill PCI address cells */
- @@ -217,7 +217,7 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename,
- }
- qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
- - GPEX_NUM_IRQS * GPEX_NUM_IRQS *
- + PCI_NUM_PINS * PCI_NUM_PINS *
- irq_map_stride * sizeof(uint32_t));
- qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
- @@ -1106,7 +1106,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
- - for (i = 0; i < GPEX_NUM_IRQS; i++) {
- + for (i = 0; i < PCI_NUM_PINS; i++) {
- irq = qdev_get_gpio_in(irqchip, PCIE_IRQ + i);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
- diff --git a/hw/virtio/virtio-blk-pci.c b/hw/virtio/virtio-blk-pci.c
- index 9743bee965..5fbf98f750 100644
- --- a/hw/virtio/virtio-blk-pci.c
- +++ b/hw/virtio/virtio-blk-pci.c
- @@ -62,6 +62,13 @@ static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
- }
- qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
- +
- + if (conf->x_apple_type) {
- + /* Apple virtio-blk uses a different vendor/device id */
- + pci_config_set_vendor_id(vpci_dev->pci_dev.config, PCI_VENDOR_ID_APPLE);
- + pci_config_set_device_id(vpci_dev->pci_dev.config,
- + PCI_DEVICE_ID_APPLE_VIRTIO_BLK);
- + }
- }
- static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
- diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
- new file mode 100644
- index 0000000000..7a2375dc95
- --- /dev/null
- +++ b/hw/vmapple/Kconfig
- @@ -0,0 +1,30 @@
- +config VMAPPLE_AES
- + bool
- +
- +config VMAPPLE_BDIF
- + bool
- +
- +config VMAPPLE_CFG
- + bool
- +
- +config VMAPPLE_PVG
- + bool
- +
- +config VMAPPLE
- + bool
- + depends on ARM && HVF
- + default y if ARM && HVF
- + imply PCI_DEVICES
- + select ARM_GIC
- + select PLATFORM_BUS
- + select PCI_EXPRESS
- + select PCI_EXPRESS_GENERIC_BRIDGE
- + select PL011 # UART
- + select PL031 # RTC
- + select PL061 # GPIO
- + select GPIO_PWR
- + select PVPANIC_MMIO
- + select VMAPPLE_AES
- + select VMAPPLE_BDIF
- + select VMAPPLE_CFG
- + select VMAPPLE_PVG
- diff --git a/hw/vmapple/aes.c b/hw/vmapple/aes.c
- new file mode 100644
- index 0000000000..eaf1e26abe
- --- /dev/null
- +++ b/hw/vmapple/aes.c
- @@ -0,0 +1,583 @@
- +/*
- + * QEMU Apple AES device emulation
- + *
- + * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- + *
- + * This work is licensed under the terms of the GNU GPL, version 2 or later.
- + * See the COPYING file in the top-level directory.
- + */
- +
- +#include "qemu/osdep.h"
- +#include "hw/irq.h"
- +#include "migration/vmstate.h"
- +#include "qemu/log.h"
- +#include "qemu/module.h"
- +#include "trace.h"
- +#include "hw/sysbus.h"
- +#include "crypto/hash.h"
- +#include "crypto/aes.h"
- +#include "crypto/cipher.h"
- +
- +#define TYPE_AES "apple-aes"
- +#define MAX_FIFO_SIZE 9
- +
- +#define CMD_KEY 0x1
- +#define CMD_KEY_CONTEXT_SHIFT 27
- +#define CMD_KEY_CONTEXT_MASK (0x1 << CMD_KEY_CONTEXT_SHIFT)
- +#define CMD_KEY_SELECT_SHIFT 24
- +#define CMD_KEY_SELECT_MASK (0x7 << CMD_KEY_SELECT_SHIFT)
- +#define CMD_KEY_KEY_LEN_SHIFT 22
- +#define CMD_KEY_KEY_LEN_MASK (0x3 << CMD_KEY_KEY_LEN_SHIFT)
- +#define CMD_KEY_ENCRYPT_SHIFT 20
- +#define CMD_KEY_ENCRYPT_MASK (0x1 << CMD_KEY_ENCRYPT_SHIFT)
- +#define CMD_KEY_BLOCK_MODE_SHIFT 16
- +#define CMD_KEY_BLOCK_MODE_MASK (0x3 << CMD_KEY_BLOCK_MODE_SHIFT)
- +#define CMD_IV 0x2
- +#define CMD_IV_CONTEXT_SHIFT 26
- +#define CMD_IV_CONTEXT_MASK (0x3 << CMD_KEY_CONTEXT_SHIFT)
- +#define CMD_DSB 0x3
- +#define CMD_SKG 0x4
- +#define CMD_DATA 0x5
- +#define CMD_DATA_KEY_CTX_SHIFT 27
- +#define CMD_DATA_KEY_CTX_MASK (0x1 << CMD_DATA_KEY_CTX_SHIFT)
- +#define CMD_DATA_IV_CTX_SHIFT 25
- +#define CMD_DATA_IV_CTX_MASK (0x3 << CMD_DATA_IV_CTX_SHIFT)
- +#define CMD_DATA_LEN_MASK 0xffffff
- +#define CMD_STORE_IV 0x6
- +#define CMD_STORE_IV_ADDR_MASK 0xffffff
- +#define CMD_WRITE_REG 0x7
- +#define CMD_FLAG 0x8
- +#define CMD_FLAG_STOP_MASK BIT(26)
- +#define CMD_FLAG_RAISE_IRQ_MASK BIT(27)
- +#define CMD_FLAG_INFO_MASK 0xff
- +#define CMD_MAX 0x10
- +
- +#define CMD_SHIFT 28
- +
- +#define REG_STATUS 0xc
- +#define REG_STATUS_DMA_READ_RUNNING BIT(0)
- +#define REG_STATUS_DMA_READ_PENDING BIT(1)
- +#define REG_STATUS_DMA_WRITE_RUNNING BIT(2)
- +#define REG_STATUS_DMA_WRITE_PENDING BIT(3)
- +#define REG_STATUS_BUSY BIT(4)
- +#define REG_STATUS_EXECUTING BIT(5)
- +#define REG_STATUS_READY BIT(6)
- +#define REG_STATUS_TEXT_DPA_SEEDED BIT(7)
- +#define REG_STATUS_UNWRAP_DPA_SEEDED BIT(8)
- +
- +#define REG_IRQ_STATUS 0x18
- +#define REG_IRQ_STATUS_INVALID_CMD BIT(2)
- +#define REG_IRQ_STATUS_FLAG BIT(5)
- +#define REG_IRQ_ENABLE 0x1c
- +#define REG_WATERMARK 0x20
- +#define REG_Q_STATUS 0x24
- +#define REG_FLAG_INFO 0x30
- +#define REG_FIFO 0x200
- +
- +static const uint32_t key_lens[4] = {
- + [0] = 16,
- + [1] = 24,
- + [2] = 32,
- + [3] = 64,
- +};
- +
- +struct key {
- + uint32_t key_len;
- + uint32_t key[8];
- +};
- +
- +struct iv {
- + uint32_t iv[4];
- +};
- +
- +struct context {
- + struct key key;
- + struct iv iv;
- +};
- +
- +static struct key builtin_keys[7] = {
- + [1] = {
- + .key_len = 32,
- + .key = { 0x1 },
- + },
- + [2] = {
- + .key_len = 32,
- + .key = { 0x2 },
- + },
- + [3] = {
- + .key_len = 32,
- + .key = { 0x3 },
- + }
- +};
- +
- +typedef struct AESState {
- + /* Private */
- + SysBusDevice parent_obj;
- +
- + /* Public */
- + qemu_irq irq;
- + MemoryRegion iomem1;
- + MemoryRegion iomem2;
- +
- + uint32_t status;
- + uint32_t q_status;
- + uint32_t irq_status;
- + uint32_t irq_enable;
- + uint32_t watermark;
- + uint32_t flag_info;
- + uint32_t fifo[MAX_FIFO_SIZE];
- + uint32_t fifo_idx;
- + struct key key[2];
- + struct iv iv[4];
- + bool is_encrypt;
- + QCryptoCipherMode block_mode;
- +} AESState;
- +
- +OBJECT_DECLARE_SIMPLE_TYPE(AESState, AES)
- +
- +static void aes_update_irq(AESState *s)
- +{
- + qemu_set_irq(s->irq, !!(s->irq_status & s->irq_enable));
- +}
- +
- +static uint64_t aes1_read(void *opaque, hwaddr offset, unsigned size)
- +{
- + AESState *s = opaque;
- + uint64_t res = 0;
- +
- + switch (offset) {
- + case REG_STATUS:
- + res = s->status;
- + break;
- + case REG_IRQ_STATUS:
- + res = s->irq_status;
- + break;
- + case REG_IRQ_ENABLE:
- + res = s->irq_enable;
- + break;
- + case REG_WATERMARK:
- + res = s->watermark;
- + break;
- + case REG_Q_STATUS:
- + res = s->q_status;
- + break;
- + case REG_FLAG_INFO:
- + res = s->flag_info;
- + break;
- +
- + default:
- + trace_aes_read_unknown(offset);
- + break;
- + }
- +
- + trace_aes_read(offset, res);
- +
- + return res;
- +}
- +
- +static void fifo_append(AESState *s, uint64_t val)
- +{
- + if (s->fifo_idx == MAX_FIFO_SIZE) {
- + /* Exceeded the FIFO. Bail out */
- + return;
- + }
- +
- + s->fifo[s->fifo_idx++] = val;
- +}
- +
- +static bool has_payload(AESState *s, uint32_t elems)
- +{
- + return s->fifo_idx >= (elems + 1);
- +}
- +
- +static bool cmd_key(AESState *s)
- +{
- + uint32_t cmd = s->fifo[0];
- + uint32_t key_select = (cmd & CMD_KEY_SELECT_MASK) >> CMD_KEY_SELECT_SHIFT;
- + uint32_t ctxt = (cmd & CMD_KEY_CONTEXT_MASK) >> CMD_KEY_CONTEXT_SHIFT;
- + uint32_t key_len;
- +
- + switch ((cmd & CMD_KEY_BLOCK_MODE_MASK) >> CMD_KEY_BLOCK_MODE_SHIFT) {
- + case 0:
- + s->block_mode = QCRYPTO_CIPHER_MODE_ECB;
- + break;
- + case 1:
- + s->block_mode = QCRYPTO_CIPHER_MODE_CBC;
- + break;
- + default:
- + return false;
- + }
- +
- + s->is_encrypt = !!((cmd & CMD_KEY_ENCRYPT_MASK) >> CMD_KEY_ENCRYPT_SHIFT);
- + key_len = key_lens[((cmd & CMD_KEY_KEY_LEN_MASK) >> CMD_KEY_KEY_LEN_SHIFT)];
- +
- + if (key_select) {
- + trace_aes_cmd_key_select_builtin(ctxt, key_select,
- + s->is_encrypt ? "en" : "de",
- + QCryptoCipherMode_str(s->block_mode));
- + s->key[ctxt] = builtin_keys[key_select];
- + } else {
- + trace_aes_cmd_key_select_new(ctxt, key_len,
- + s->is_encrypt ? "en" : "de",
- + QCryptoCipherMode_str(s->block_mode));
- + if (key_len > sizeof(s->key[ctxt].key)) {
- + return false;
- + }
- + if (!has_payload(s, key_len / sizeof(uint32_t))) {
- + /* wait for payload */
- + return false;
- + }
- + memcpy(&s->key[ctxt].key, &s->fifo[1], key_len);
- + s->key[ctxt].key_len = key_len;
- + }
- +
- + return true;
- +}
- +
- +static bool cmd_iv(AESState *s)
- +{
- + uint32_t cmd = s->fifo[0];
- + uint32_t ctxt = (cmd & CMD_IV_CONTEXT_MASK) >> CMD_IV_CONTEXT_SHIFT;
- +
- + if (!has_payload(s, 4)) {
- + /* wait for payload */
- + return false;
- + }
- + memcpy(&s->iv[ctxt].iv, &s->fifo[1], sizeof(s->iv[ctxt].iv));
- + trace_aes_cmd_iv(ctxt, s->fifo[1], s->fifo[2], s->fifo[3], s->fifo[4]);
- +
- + return true;
- +}
- +
- +static char hexdigit2str(uint8_t val)
- +{
- + g_assert(val < 0x10);
- + if (val >= 0xa) {
- + return 'a' + (val - 0xa);
- + } else {
- + return '0' + val;
- + }
- +}
- +
- +static void dump_data(const char *desc, const void *p, size_t len)
- +{
- + char hex[(len * 2) + 1];
- + const uint8_t *data = p;
- + char *hexp = hex;
- + size_t i;
- +
- + if (len > 0x1000) {
- + /* Too large buffer, let's bail out */
- + return;
- + }
- +
- + for (i = 0; i < len; i++) {
- + uint8_t val = data[i];
- + *(hexp++) = hexdigit2str(val >> 4);
- + *(hexp++) = hexdigit2str(val & 0xf);
- + }
- + *hexp = '\0';
- +
- + trace_aes_dump_data(desc, hex);
- +}
- +
- +static bool cmd_data(AESState *s)
- +{
- + uint32_t cmd = s->fifo[0];
- + uint32_t ctxt_iv = 0;
- + uint32_t ctxt_key = (cmd & CMD_DATA_KEY_CTX_MASK) >> CMD_DATA_KEY_CTX_SHIFT;
- + uint32_t len = cmd & CMD_DATA_LEN_MASK;
- + uint64_t src_addr = s->fifo[2];
- + uint64_t dst_addr = s->fifo[3];
- + QCryptoCipherAlgorithm alg;
- + QCryptoCipher *cipher;
- + char *src;
- + char *dst;
- +
- + src_addr |= ((uint64_t)s->fifo[1] << 16) & 0xffff00000000ULL;
- + dst_addr |= ((uint64_t)s->fifo[1] << 32) & 0xffff00000000ULL;
- +
- + trace_aes_cmd_data(ctxt_key, ctxt_iv, src_addr, dst_addr, len);
- +
- + if (!has_payload(s, 3)) {
- + /* wait for payload */
- + trace_aes_cmd_data_error("No payload");
- + return false;
- + }
- +
- + if (ctxt_key >= ARRAY_SIZE(s->key) ||
- + ctxt_iv >= ARRAY_SIZE(s->iv)) {
- + /* Invalid input */
- + trace_aes_cmd_data_error("Invalid key or iv");
- + return false;
- + }
- +
- + src = g_malloc0(len);
- + dst = g_malloc0(len);
- +
- + cpu_physical_memory_read(src_addr, src, len);
- +
- + dump_data("cmd_data(): src_data=", src, len);
- +
- + switch (s->key[ctxt_key].key_len) {
- + case 128 / 8:
- + alg = QCRYPTO_CIPHER_ALG_AES_128;
- + break;
- + case 192 / 8:
- + alg = QCRYPTO_CIPHER_ALG_AES_192;
- + break;
- + case 256 / 8:
- + alg = QCRYPTO_CIPHER_ALG_AES_256;
- + break;
- + default:
- + trace_aes_cmd_data_error("Invalid key len");
- + goto err_free;
- + }
- + cipher = qcrypto_cipher_new(alg, s->block_mode,
- + (void *)s->key[ctxt_key].key,
- + s->key[ctxt_key].key_len, NULL);
- + g_assert(cipher != NULL);
- + if (s->block_mode != QCRYPTO_CIPHER_MODE_ECB) {
- + if (qcrypto_cipher_setiv(cipher, (void *)s->iv[ctxt_iv].iv,
- + sizeof(s->iv[ctxt_iv].iv), NULL) != 0) {
- + trace_aes_cmd_data_error("Failed to set IV");
- + goto err_free_cipher;
- + }
- + }
- + if (s->is_encrypt) {
- + if (qcrypto_cipher_encrypt(cipher, src, dst, len, NULL) != 0) {
- + trace_aes_cmd_data_error("Encrypt failed");
- + goto err_free_cipher;
- + }
- + } else {
- + if (qcrypto_cipher_decrypt(cipher, src, dst, len, NULL) != 0) {
- + trace_aes_cmd_data_error("Decrypt failed");
- + goto err_free_cipher;
- + }
- + }
- + qcrypto_cipher_free(cipher);
- +
- + dump_data("cmd_data(): dst_data=", dst, len);
- + cpu_physical_memory_write(dst_addr, dst, len);
- + g_free(src);
- + g_free(dst);
- +
- + return true;
- +
- +err_free_cipher:
- + qcrypto_cipher_free(cipher);
- +err_free:
- + g_free(src);
- + g_free(dst);
- + return false;
- +}
- +
- +static bool cmd_store_iv(AESState *s)
- +{
- + uint32_t cmd = s->fifo[0];
- + uint32_t ctxt = (cmd & CMD_IV_CONTEXT_MASK) >> CMD_IV_CONTEXT_SHIFT;
- + uint64_t addr = s->fifo[1];
- +
- + if (!has_payload(s, 1)) {
- + /* wait for payload */
- + return false;
- + }
- +
- + if (ctxt >= ARRAY_SIZE(s->iv)) {
- + /* Invalid context selected */
- + return false;
- + }
- +
- + addr |= ((uint64_t)cmd << 32) & 0xff00000000ULL;
- + cpu_physical_memory_write(addr, &s->iv[ctxt].iv, sizeof(s->iv[ctxt].iv));
- +
- + trace_aes_cmd_store_iv(ctxt, addr, s->iv[ctxt].iv[0], s->iv[ctxt].iv[1],
- + s->iv[ctxt].iv[2], s->iv[ctxt].iv[3]);
- +
- + return true;
- +}
- +
- +static bool cmd_flag(AESState *s)
- +{
- + uint32_t cmd = s->fifo[0];
- + uint32_t raise_irq = cmd & CMD_FLAG_RAISE_IRQ_MASK;
- +
- + /* We always process data when it's coming in, so fire an IRQ immediately */
- + if (raise_irq) {
- + s->irq_status |= REG_IRQ_STATUS_FLAG;
- + }
- +
- + s->flag_info = cmd & CMD_FLAG_INFO_MASK;
- +
- + trace_aes_cmd_flag(!!raise_irq, s->flag_info);
- +
- + return true;
- +}
- +
- +static void fifo_process(AESState *s)
- +{
- + uint32_t cmd = s->fifo[0] >> CMD_SHIFT;
- + bool success = false;
- +
- + if (!s->fifo_idx) {
- + return;
- + }
- +
- + switch (cmd) {
- + case CMD_KEY:
- + success = cmd_key(s);
- + break;
- + case CMD_IV:
- + success = cmd_iv(s);
- + break;
- + case CMD_DATA:
- + success = cmd_data(s);
- + break;
- + case CMD_STORE_IV:
- + success = cmd_store_iv(s);
- + break;
- + case CMD_FLAG:
- + success = cmd_flag(s);
- + break;
- + default:
- + s->irq_status |= REG_IRQ_STATUS_INVALID_CMD;
- + break;
- + }
- +
- + if (success) {
- + s->fifo_idx = 0;
- + }
- +
- + trace_aes_fifo_process(cmd, success ? 1 : 0);
- +}
- +
- +static void aes1_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
- +{
- + AESState *s = opaque;
- +
- + trace_aes_write(offset, val);
- +
- + switch (offset) {
- + case REG_IRQ_STATUS:
- + s->irq_status &= ~val;
- + break;
- + case REG_IRQ_ENABLE:
- + s->irq_enable = val;
- + break;
- + case REG_FIFO:
- + fifo_append(s, val);
- + fifo_process(s);
- + break;
- + default:
- + trace_aes_write_unknown(offset);
- + return;
- + }
- +
- + aes_update_irq(s);
- +}
- +
- +static const MemoryRegionOps aes1_ops = {
- + .read = aes1_read,
- + .write = aes1_write,
- + .endianness = DEVICE_NATIVE_ENDIAN,
- + .valid = {
- + .min_access_size = 4,
- + .max_access_size = 8,
- + },
- + .impl = {
- + .min_access_size = 4,
- + .max_access_size = 4,
- + },
- +};
- +
- +static uint64_t aes2_read(void *opaque, hwaddr offset, unsigned size)
- +{
- + uint64_t res = 0;
- +
- + switch (offset) {
- + case 0:
- + res = 0;
- + break;
- + default:
- + trace_aes_2_read_unknown(offset);
- + break;
- + }
- +
- + trace_aes_2_read(offset, res);
- +
- + return res;
- +}
- +
- +static void aes2_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
- +{
- + trace_aes_2_write(offset, val);
- +
- + switch (offset) {
- + default:
- + trace_aes_2_write_unknown(offset);
- + return;
- + }
- +}
- +
- +static const MemoryRegionOps aes2_ops = {
- + .read = aes2_read,
- + .write = aes2_write,
- + .endianness = DEVICE_NATIVE_ENDIAN,
- + .valid = {
- + .min_access_size = 4,
- + .max_access_size = 8,
- + },
- + .impl = {
- + .min_access_size = 4,
- + .max_access_size = 4,
- + },
- +};
- +
- +static void aes_reset(DeviceState *d)
- +{
- + AESState *s = AES(d);
- +
- + s->status = 0x3f80;
- + s->q_status = 2;
- + s->irq_status = 0;
- + s->irq_enable = 0;
- + s->watermark = 0;
- +}
- +
- +static void aes_init(Object *obj)
- +{
- + AESState *s = AES(obj);
- +
- + memory_region_init_io(&s->iomem1, obj, &aes1_ops, s, TYPE_AES, 0x4000);
- + memory_region_init_io(&s->iomem2, obj, &aes2_ops, s, TYPE_AES, 0x4000);
- + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem1);
- + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem2);
- + sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
- +}
- +
- +static void aes_realize(DeviceState *dev, Error **errp)
- +{
- +}
- +
- +static void aes_class_init(ObjectClass *klass, void *data)
- +{
- + DeviceClass *dc = DEVICE_CLASS(klass);
- +
- + dc->reset = aes_reset;
- + dc->realize = aes_realize;
- +}
- +
- +static const TypeInfo aes_info = {
- + .name = TYPE_AES,
- + .parent = TYPE_SYS_BUS_DEVICE,
- + .instance_size = sizeof(AESState),
- + .class_init = aes_class_init,
- + .instance_init = aes_init,
- +};
- +
- +static void aes_register_types(void)
- +{
- + type_register_static(&aes_info);
- +}
- +
- +type_init(aes_register_types)
- diff --git a/hw/vmapple/apple-gfx.m b/hw/vmapple/apple-gfx.m
- new file mode 100644
- index 0000000000..173b721645
- --- /dev/null
- +++ b/hw/vmapple/apple-gfx.m
- @@ -0,0 +1,579 @@
- +/*
- + * QEMU Apple ParavirtualizedGraphics.framework device
- + *
- + * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- + *
- + * This work is licensed under the terms of the GNU GPL, version 2 or later.
- + * See the COPYING file in the top-level directory.
- + *
- + * ParavirtualizedGraphics.framework is a set of libraries that macOS provides
- + * which implements 3d graphics passthrough to the host as well as a
- + * proprietary guest communication channel to drive it. This device model
- + * implements support to drive that library from within QEMU.
- + */
- +
- +#include "qemu/osdep.h"
- +#include "hw/irq.h"
- +#include "migration/vmstate.h"
- +#include "qemu/log.h"
- +#include "qemu/module.h"
- +#include "trace.h"
- +#include "hw/sysbus.h"
- +#include "hw/pci/msi.h"
- +#include "crypto/hash.h"
- +#include "sysemu/cpus.h"
- +#include "ui/console.h"
- +#include "monitor/monitor.h"
- +#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
- +#include <mach/mach.h>
- +
- +#define TYPE_APPLE_GFX "apple-gfx"
- +
- +#define MAX_MRS 512
- +
- +static const PGDisplayCoord_t apple_gfx_modes[] = {
- + { .x = 1440, .y = 1080 },
- + { .x = 1280, .y = 1024 },
- +};
- +
- +/*
- + * We have to map PVG memory into our address space. Use the one below
- + * as base start address. In normal linker setups it points to a free
- + * memory range.
- + */
- +#define APPLE_GFX_BASE_VA ((void *)(uintptr_t)0x500000000000UL)
- +
- +/*
- + * ParavirtualizedGraphics.Framework only ships header files for the x86
- + * variant which does not include IOSFC descriptors and host devices. We add
- + * their definitions here so that we can also work with the ARM version.
- + */
- +typedef bool(^IOSFCRaiseInterrupt)(uint32_t vector);
- +typedef bool(^IOSFCUnmapMemory)(void *a, void *b, void *c, void *d, void *e, void *f);
- +typedef bool(^IOSFCMapMemory)(uint64_t phys, uint64_t len, bool ro, void **va, void *e, void *f);
- +
- +@interface PGDeviceDescriptorExt : PGDeviceDescriptor
- +@property (readwrite, nonatomic) bool usingIOSurfaceMapper;
- +@end
- +
- +@interface PGIOSurfaceHostDeviceDescriptor : NSObject
- +-(PGIOSurfaceHostDeviceDescriptor *)init;
- +@property (readwrite, nonatomic, copy, nullable) IOSFCMapMemory mapMemory;
- +@property (readwrite, nonatomic, copy, nullable) IOSFCUnmapMemory unmapMemory;
- +@property (readwrite, nonatomic, copy, nullable) IOSFCRaiseInterrupt raiseInterrupt;
- +@end
- +
- +@interface PGIOSurfaceHostDevice : NSObject
- +-(void)initWithDescriptor:(PGIOSurfaceHostDeviceDescriptor *) desc;
- +-(uint32_t)mmioReadAtOffset:(size_t) offset;
- +-(void)mmioWriteAtOffset:(size_t) offset value:(uint32_t)value;
- +@end
- +
- +typedef struct AppleGFXMR {
- + QTAILQ_ENTRY(AppleGFXMR) node;
- + hwaddr pa;
- + void *va;
- + uint64_t len;
- +} AppleGFXMR;
- +
- +typedef QTAILQ_HEAD(, AppleGFXMR) AppleGFXMRList;
- +
- +typedef struct AppleGFXTask {
- + QTAILQ_ENTRY(AppleGFXTask) node;
- + void *mem;
- + uint64_t len;
- +} AppleGFXTask;
- +
- +typedef QTAILQ_HEAD(, AppleGFXTask) AppleGFXTaskList;
- +
- +typedef struct AppleGFXState {
- + /* Private */
- + SysBusDevice parent_obj;
- +
- + /* Public */
- + qemu_irq irq_gfx;
- + qemu_irq irq_iosfc;
- + MemoryRegion iomem_gfx;
- + MemoryRegion iomem_iosfc;
- + id<PGDevice> pgdev;
- + id<PGDisplay> pgdisp;
- + PGIOSurfaceHostDevice *pgiosfc;
- + AppleGFXMRList mrs;
- + AppleGFXTaskList tasks;
- + QemuConsole *con;
- + void *vram;
- + id<MTLDevice> mtl;
- + id<MTLTexture> texture;
- + bool handles_frames;
- + bool new_frame;
- + bool cursor_show;
- + DisplaySurface *surface;
- + QEMUCursor *cursor;
- +} AppleGFXState;
- +
- +
- +OBJECT_DECLARE_SIMPLE_TYPE(AppleGFXState, APPLE_GFX)
- +
- +static AppleGFXTask *apple_gfx_new_task(AppleGFXState *s, uint64_t len)
- +{
- + void *base = APPLE_GFX_BASE_VA;
- + AppleGFXTask *task;
- +
- + QTAILQ_FOREACH(task, &s->tasks, node) {
- + if ((task->mem + task->len) > base) {
- + base = task->mem + task->len;
- + }
- + }
- +
- + task = g_new0(AppleGFXTask, 1);
- +
- + task->len = len;
- + task->mem = base;
- + QTAILQ_INSERT_TAIL(&s->tasks, task, node);
- +
- + return task;
- +}
- +
- +static AppleGFXMR *apple_gfx_mapMemory(AppleGFXState *s, AppleGFXTask *task,
- + uint64_t voff, uint64_t phys, uint64_t len)
- +{
- + AppleGFXMR *mr = g_new0(AppleGFXMR, 1);
- +
- + mr->pa = phys;
- + mr->len = len;
- + mr->va = task->mem + voff;
- + QTAILQ_INSERT_TAIL(&s->mrs, mr, node);
- +
- + return mr;
- +}
- +
- +static uint64_t apple_gfx_read(void *opaque, hwaddr offset, unsigned size)
- +{
- + AppleGFXState *s = opaque;
- + uint64_t res = 0;
- +
- + switch (offset) {
- + default:
- + res = [s->pgdev mmioReadAtOffset:offset];
- + break;
- + }
- +
- + trace_apple_gfx_read(offset, res);
- +
- + return res;
- +}
- +
- +static void apple_gfx_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
- +{
- + AppleGFXState *s = opaque;
- +
- + trace_apple_gfx_write(offset, val);
- +
- + qemu_mutex_unlock_iothread();
- + [s->pgdev mmioWriteAtOffset:offset value:val];
- + qemu_mutex_lock_iothread();
- +}
- +
- +static const MemoryRegionOps apple_gfx_ops = {
- + .read = apple_gfx_read,
- + .write = apple_gfx_write,
- + .endianness = DEVICE_NATIVE_ENDIAN,
- + .valid = {
- + .min_access_size = 4,
- + .max_access_size = 8,
- + },
- + .impl = {
- + .min_access_size = 4,
- + .max_access_size = 4,
- + },
- +};
- +
- +static uint64_t apple_iosfc_read(void *opaque, hwaddr offset, unsigned size)
- +{
- + AppleGFXState *s = opaque;
- + uint64_t res = 0;
- +
- + qemu_mutex_unlock_iothread();
- + res = [s->pgiosfc mmioReadAtOffset:offset];
- + qemu_mutex_lock_iothread();
- +
- + trace_apple_iosfc_read(offset, res);
- +
- + return res;
- +}
- +
- +static void apple_iosfc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
- +{
- + AppleGFXState *s = opaque;
- +
- + trace_apple_iosfc_write(offset, val);
- +
- + [s->pgiosfc mmioWriteAtOffset:offset value:val];
- +}
- +
- +static const MemoryRegionOps apple_iosfc_ops = {
- + .read = apple_iosfc_read,
- + .write = apple_iosfc_write,
- + .endianness = DEVICE_NATIVE_ENDIAN,
- + .valid = {
- + .min_access_size = 4,
- + .max_access_size = 8,
- + },
- + .impl = {
- + .min_access_size = 4,
- + .max_access_size = 8,
- + },
- +};
- +
- +static void apple_gfx_fb_update_display(void *opaque)
- +{
- + AppleGFXState *s = opaque;
- +
- + if (!s->new_frame || !s->handles_frames) {
- + return;
- + }
- +
- + s->new_frame = false;
- +
- + BOOL r;
- + uint32_t width = surface_width(s->surface);
- + uint32_t height = surface_height(s->surface);
- + MTLRegion region = MTLRegionMake2D(0, 0, width, height);
- + id<MTLCommandQueue> commandQueue = [s->mtl newCommandQueue];
- + id<MTLCommandBuffer> mipmapCommandBuffer = [commandQueue commandBuffer];
- +
- + r = [s->pgdisp encodeCurrentFrameToCommandBuffer:mipmapCommandBuffer
- + texture:s->texture
- + region:region];
- +
- + if (r != YES) {
- + return;
- + }
- +
- + id<MTLBlitCommandEncoder> blitCommandEncoder = [mipmapCommandBuffer blitCommandEncoder];
- + [blitCommandEncoder generateMipmapsForTexture:s->texture];
- + [blitCommandEncoder endEncoding];
- + [mipmapCommandBuffer commit];
- + [mipmapCommandBuffer waitUntilCompleted];
- + [s->texture getBytes:s->vram bytesPerRow:(width * 4)
- + bytesPerImage: (width * height * 4)
- + fromRegion: region
- + mipmapLevel: 0
- + slice: 0];
- +
- + /* Need to render cursor manually if not supported by backend */
- + if (!dpy_cursor_define_supported(s->con) && s->cursor && s->cursor_show) {
- + pixman_image_t *image =
- + pixman_image_create_bits(PIXMAN_a8r8g8b8,
- + s->cursor->width,
- + s->cursor->height,
- + (uint32_t *)s->cursor->data,
- + s->cursor->width * 4);
- +
- + pixman_image_composite(PIXMAN_OP_OVER,
- + image, NULL, s->surface->image,
- + 0, 0, 0, 0, s->pgdisp.cursorPosition.x,
- + s->pgdisp.cursorPosition.y, s->cursor->width,
- + s->cursor->height);
- +
- + pixman_image_unref(image);
- + }
- +
- + dpy_gfx_update_full(s->con);
- +
- + [commandQueue release];
- +}
- +
- +static const GraphicHwOps apple_gfx_fb_ops = {
- + .gfx_update = apple_gfx_fb_update_display,
- +};
- +
- +static void update_cursor(AppleGFXState *s)
- +{
- + dpy_mouse_set(s->con, s->pgdisp.cursorPosition.x, s->pgdisp.cursorPosition.y, s->cursor_show);
- +
- + /* Need to render manually if cursor is not natively supported */
- + if (!dpy_cursor_define_supported(s->con)) {
- + s->new_frame = true;
- + }
- +}
- +
- +static void set_mode(AppleGFXState *s, uint32_t width, uint32_t height)
- +{
- + void *vram = g_malloc0(width * height * 4);
- + void *old_vram = s->vram;
- + DisplaySurface *surface;
- + MTLTextureDescriptor *textureDescriptor;
- + id<MTLTexture> old_texture = s->texture;
- +
- + if (s->surface &&
- + width == surface_width(s->surface) &&
- + height == surface_height(s->surface)) {
- + return;
- + }
- + surface = qemu_create_displaysurface_from(width, height, PIXMAN_LE_a8r8g8b8,
- + width * 4, vram);
- + s->surface = surface;
- + dpy_gfx_replace_surface(s->con, surface);
- + s->vram = vram;
- + g_free(old_vram);
- +
- + textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
- + width:width
- + height:height
- + mipmapped:NO];
- + textureDescriptor.usage = s->pgdisp.minimumTextureUsage;
- + s->texture = [s->mtl newTextureWithDescriptor:textureDescriptor];
- +
- + if (old_texture) {
- + [old_texture release];
- + }
- +}
- +
- +static void create_fb(AppleGFXState *s)
- +{
- +
- + s->con = graphic_console_init(NULL, 0, &apple_gfx_fb_ops, s);
- + set_mode(s, 1440, 1080);
- +
- + s->cursor_show = true;
- +}
- +
- +static void apple_gfx_reset(DeviceState *d)
- +{
- +}
- +
- +static void apple_gfx_init(Object *obj)
- +{
- + AppleGFXState *s = APPLE_GFX(obj);
- +
- + memory_region_init_io(&s->iomem_gfx, obj, &apple_gfx_ops, s, TYPE_APPLE_GFX, 0x4000);
- + memory_region_init_io(&s->iomem_iosfc, obj, &apple_iosfc_ops, s, TYPE_APPLE_GFX, 0x10000);
- + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem_gfx);
- + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem_iosfc);
- + sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq_gfx);
- + sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq_iosfc);
- +}
- +
- +static void apple_gfx_realize(DeviceState *dev, Error **errp)
- +{
- + AppleGFXState *s = APPLE_GFX(dev);
- + PGDeviceDescriptor *desc = [PGDeviceDescriptor new];
- + PGDisplayDescriptor *disp_desc = [PGDisplayDescriptor new];
- + PGIOSurfaceHostDeviceDescriptor *iosfc_desc = [PGIOSurfaceHostDeviceDescriptor new];
- + PGDeviceDescriptorExt *desc_ext = (PGDeviceDescriptorExt *)desc;
- + PGDisplayMode *modes[ARRAY_SIZE(apple_gfx_modes)];
- + int i;
- +
- + for (i = 0; i < ARRAY_SIZE(apple_gfx_modes); i++) {
- + modes[i] = [PGDisplayMode new];
- + [modes[i] initWithSizeInPixels:apple_gfx_modes[i] refreshRateInHz:60.];
- + }
- +
- + s->mtl = MTLCreateSystemDefaultDevice();
- +
- + desc.device = s->mtl;
- + desc_ext.usingIOSurfaceMapper = true;
- +
- + desc.createTask = ^(uint64_t vmSize, void * _Nullable * _Nonnull baseAddress) {
- + AppleGFXTask *task = apple_gfx_new_task(s, vmSize);
- + *baseAddress = task->mem;
- + trace_apple_gfx_create_task(vmSize, *baseAddress);
- + return (PGTask_t *)task;
- + };
- +
- + desc.destroyTask = ^(PGTask_t * _Nonnull _task) {
- + AppleGFXTask *task = (AppleGFXTask *)_task;
- + trace_apple_gfx_destroy_task(task);
- + QTAILQ_REMOVE(&s->tasks, task, node);
- + g_free(task);
- + };
- +
- + desc.mapMemory = ^(PGTask_t * _Nonnull _task, uint32_t rangeCount, uint64_t virtualOffset, bool readOnly, PGPhysicalMemoryRange_t * _Nonnull ranges) {
- + AppleGFXTask *task = (AppleGFXTask*)_task;
- + mach_port_t mtask = mach_task_self();
- + trace_apple_gfx_map_memory(task, rangeCount, virtualOffset, readOnly);
- + for (int i = 0; i < rangeCount; i++) {
- + PGPhysicalMemoryRange_t *range = &ranges[i];
- + MemoryRegion *tmp_mr;
- + /* TODO: Bounds checks? r/o? */
- + qemu_mutex_lock_iothread();
- + AppleGFXMR *mr = apple_gfx_mapMemory(s, task, virtualOffset,
- + range->physicalAddress,
- + range->physicalLength);
- +
- + trace_apple_gfx_map_memory_range(i, range->physicalAddress, range->physicalLength, mr->va);
- +
- + vm_address_t target = (vm_address_t)mr->va;
- + uint64_t mask = 0;
- + bool anywhere = false;
- + vm_address_t source = (vm_address_t)gpa2hva(&tmp_mr, mr->pa, mr->len, NULL);
- + vm_prot_t cur_protection = 0;
- + vm_prot_t max_protection = 0;
- + kern_return_t retval = vm_remap(mtask, &target, mr->len, mask,
- + anywhere, mtask, source, false,
- + &cur_protection, &max_protection,
- + VM_INHERIT_DEFAULT);
- + trace_apple_gfx_remap(retval, source, target);
- + g_assert(retval == KERN_SUCCESS);
- +
- + qemu_mutex_unlock_iothread();
- +
- + virtualOffset += mr->len;
- + }
- + return (bool)true;
- + };
- +
- + desc.unmapMemory = ^(PGTask_t * _Nonnull _task, uint64_t virtualOffset, uint64_t length) {
- + AppleGFXTask *task = (AppleGFXTask *)_task;
- + AppleGFXMR *mr, *next;
- +
- + trace_apple_gfx_unmap_memory(task, virtualOffset, length);
- + qemu_mutex_lock_iothread();
- + QTAILQ_FOREACH_SAFE(mr, &s->mrs, node, next) {
- + if (mr->va >= (task->mem + virtualOffset) &&
- + (mr->va + mr->len) <= (task->mem + virtualOffset + length)) {
- + vm_address_t addr = (vm_address_t)mr->va;
- + vm_deallocate(mach_task_self(), addr, mr->len);
- + QTAILQ_REMOVE(&s->mrs, mr, node);
- + g_free(mr);
- + }
- + }
- + qemu_mutex_unlock_iothread();
- + return (bool)true;
- + };
- +
- + desc.readMemory = ^(uint64_t physicalAddress, uint64_t length, void * _Nonnull dst) {
- + trace_apple_gfx_read_memory(physicalAddress, length, dst);
- + cpu_physical_memory_read(physicalAddress, dst, length);
- + return (bool)true;
- + };
- +
- + desc.raiseInterrupt = ^(uint32_t vector) {
- + bool locked;
- +
- + trace_apple_gfx_raise_irq(vector);
- + locked = qemu_mutex_iothread_locked();
- + if (!locked) {
- + qemu_mutex_lock_iothread();
- + }
- + qemu_irq_pulse(s->irq_gfx);
- + if (!locked) {
- + qemu_mutex_unlock_iothread();
- + }
- + };
- +
- + desc.addTraceRange = ^(PGPhysicalMemoryRange_t * _Nonnull range, PGTraceRangeHandler _Nonnull handler) {
- + /* Never saw this called. Return a bogus pointer so we catch access. */
- + return (PGTraceRange_t *)(void *)(uintptr_t)0x4242;
- + };
- +
- + desc.removeTraceRange = ^(PGTraceRange_t * _Nonnull range) {
- + /* Never saw this called. Nothing to do. */
- + };
- + s->pgdev = PGNewDeviceWithDescriptor(desc);
- +
- + [disp_desc init];
- + disp_desc.name = @"QEMU display";
- + disp_desc.sizeInMillimeters = NSMakeSize(400., 300.); /* A 20" display */
- + disp_desc.queue = dispatch_get_main_queue();
- + disp_desc.newFrameEventHandler = ^(void) {
- + trace_apple_gfx_new_frame();
- +
- + /* Tell QEMU gfx stack that a new frame arrived */
- + s->handles_frames = true;
- + s->new_frame = true;
- + };
- + disp_desc.modeChangeHandler = ^(PGDisplayCoord_t sizeInPixels, OSType pixelFormat) {
- + trace_apple_gfx_mode_change(sizeInPixels.x, sizeInPixels.y);
- + set_mode(s, sizeInPixels.x, sizeInPixels.y);
- + };
- + disp_desc.cursorGlyphHandler = ^(NSBitmapImageRep *glyph, PGDisplayCoord_t hotSpot) {
- + uint32_t bpp = glyph.bitsPerPixel;
- + uint64_t width = glyph.pixelsWide;
- + uint64_t height = glyph.pixelsHigh;
- +
- + trace_apple_gfx_cursor_set(bpp, width, height);
- +
- + if (s->cursor) {
- + cursor_unref(s->cursor);
- + }
- + s->cursor = cursor_alloc(width, height);
- +
- + /* TODO handle different bpp */
- + if (bpp == 32) {
- + memcpy(s->cursor->data, glyph.bitmapData, glyph.bytesPerPlane);
- + dpy_cursor_define(s->con, s->cursor);
- + update_cursor(s);
- + }
- + };
- + disp_desc.cursorShowHandler = ^(BOOL show) {
- + trace_apple_gfx_cursor_show(show);
- + s->cursor_show = show;
- + update_cursor(s);
- + };
- + disp_desc.cursorMoveHandler = ^(void) {
- + trace_apple_gfx_cursor_move();
- + update_cursor(s);
- + };
- +
- + s->pgdisp = [s->pgdev newDisplayWithDescriptor:disp_desc port:0 serialNum:1234];
- + s->pgdisp.modeList = [NSArray arrayWithObjects:modes count:ARRAY_SIZE(apple_gfx_modes)];
- +
- + [iosfc_desc init];
- + iosfc_desc.mapMemory = ^(uint64_t phys, uint64_t len, bool ro, void **va, void *e, void *f) {
- + trace_apple_iosfc_map_memory(phys, len, ro, va, e, f);
- + MemoryRegion *tmp_mr;
- + *va = gpa2hva(&tmp_mr, phys, len, NULL);
- + return (bool)true;
- + };
- +
- + iosfc_desc.unmapMemory = ^(void *a, void *b, void *c, void *d, void *e, void *f) {
- + trace_apple_iosfc_unmap_memory(a, b, c, d, e, f);
- + return (bool)true;
- + };
- +
- + iosfc_desc.raiseInterrupt = ^(uint32_t vector) {
- + trace_apple_iosfc_raise_irq(vector);
- + bool locked = qemu_mutex_iothread_locked();
- + if (!locked) {
- + qemu_mutex_lock_iothread();
- + }
- + qemu_irq_pulse(s->irq_iosfc);
- + if (!locked) {
- + qemu_mutex_unlock_iothread();
- + }
- + return (bool)true;
- + };
- +
- + s->pgiosfc = [PGIOSurfaceHostDevice new];
- + [s->pgiosfc initWithDescriptor:iosfc_desc];
- +
- + QTAILQ_INIT(&s->mrs);
- + QTAILQ_INIT(&s->tasks);
- +
- + create_fb(s);
- +}
- +
- +static void apple_gfx_class_init(ObjectClass *klass, void *data)
- +{
- + DeviceClass *dc = DEVICE_CLASS(klass);
- +
- + dc->reset = apple_gfx_reset;
- + dc->realize = apple_gfx_realize;
- +}
- +
- +static TypeInfo apple_gfx_info = {
- + .name = TYPE_APPLE_GFX,
- + .parent = TYPE_SYS_BUS_DEVICE,
- + .instance_size = sizeof(AppleGFXState),
- + .class_init = apple_gfx_class_init,
- + .instance_init = apple_gfx_init,
- +};
- +
- +static void apple_gfx_register_types(void)
- +{
- + type_register_static(&apple_gfx_info);
- +}
- +
- +type_init(apple_gfx_register_types)
- diff --git a/hw/vmapple/bdif.c b/hw/vmapple/bdif.c
- new file mode 100644
- index 0000000000..36b5915ff3
- --- /dev/null
- +++ b/hw/vmapple/bdif.c
- @@ -0,0 +1,245 @@
- +/*
- + * VMApple Backdoor Interface
- + *
- + * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- + *
- + * This work is licensed under the terms of the GNU GPL, version 2 or later.
- + * See the COPYING file in the top-level directory.
- + */
- +
- +#include "qemu/osdep.h"
- +#include "hw/vmapple/bdif.h"
- +#include "qemu/log.h"
- +#include "qemu/module.h"
- +#include "qapi/error.h"
- +#include "trace.h"
- +#include "hw/block/block.h"
- +#include "sysemu/block-backend.h"
- +
- +#define REG_DEVID_MASK 0xffff0000
- +#define DEVID_ROOT 0x00000000
- +#define DEVID_AUX 0x00010000
- +#define DEVID_USB 0x00100000
- +
- +#define REG_STATUS 0x0
- +#define REG_STATUS_ACTIVE BIT(0)
- +#define REG_CFG 0x4
- +#define REG_CFG_ACTIVE BIT(1)
- +#define REG_UNK1 0x8
- +#define REG_BUSY 0x10
- +#define REG_BUSY_READY BIT(0)
- +#define REG_UNK2 0x400
- +#define REG_CMD 0x408
- +#define REG_NEXT_DEVICE 0x420
- +#define REG_UNK3 0x434
- +
- +typedef struct vblk_sector {
- + uint32_t pad;
- + uint32_t pad2;
- + uint32_t sector;
- + uint32_t pad3;
- +} VblkSector;
- +
- +typedef struct vblk_req_cmd {
- + uint64_t addr;
- + uint32_t len;
- + uint32_t flags;
- +} VblkReqCmd;
- +
- +typedef struct vblk_req {
- + VblkReqCmd sector;
- + VblkReqCmd data;
- + VblkReqCmd retval;
- +} VblkReq;
- +
- +#define VBLK_DATA_FLAGS_READ 0x00030001
- +#define VBLK_DATA_FLAGS_WRITE 0x00010001
- +
- +#define VBLK_RET_SUCCESS 0
- +#define VBLK_RET_FAILED 1
- +
- +static uint64_t bdif_read(void *opaque, hwaddr offset, unsigned size)
- +{
- + uint64_t ret = -1;
- + uint64_t devid = (offset & REG_DEVID_MASK);
- +
- + switch (offset & ~REG_DEVID_MASK) {
- + case REG_STATUS:
- + ret = REG_STATUS_ACTIVE;
- + break;
- + case REG_CFG:
- + ret = REG_CFG_ACTIVE;
- + break;
- + case REG_UNK1:
- + ret = 0x420;
- + break;
- + case REG_BUSY:
- + ret = REG_BUSY_READY;
- + break;
- + case REG_UNK2:
- + ret = 0x1;
- + break;
- + case REG_UNK3:
- + ret = 0x0;
- + break;
- + case REG_NEXT_DEVICE:
- + switch (devid) {
- + case DEVID_ROOT:
- + ret = 0x8000000;
- + break;
- + case DEVID_AUX:
- + ret = 0x10000;
- + break;
- + }
- + break;
- + }
- +
- + trace_bdif_read(offset, size, ret);
- + return ret;
- +}
- +
- +static void le2cpu_sector(VblkSector *sector)
- +{
- + sector->sector = le32_to_cpu(sector->sector);
- +}
- +
- +static void le2cpu_reqcmd(VblkReqCmd *cmd)
- +{
- + cmd->addr = le64_to_cpu(cmd->addr);
- + cmd->len = le32_to_cpu(cmd->len);
- + cmd->flags = le32_to_cpu(cmd->flags);
- +}
- +
- +static void le2cpu_req(VblkReq *req)
- +{
- + le2cpu_reqcmd(&req->sector);
- + le2cpu_reqcmd(&req->data);
- + le2cpu_reqcmd(&req->retval);
- +}
- +
- +static void vblk_cmd(uint64_t devid, BlockBackend *blk, uint64_t value,
- + uint64_t static_off)
- +{
- + VblkReq req;
- + VblkSector sector;
- + uint64_t off = 0;
- + char *buf = NULL;
- + uint8_t ret = VBLK_RET_FAILED;
- + int r;
- +
- + cpu_physical_memory_read(value, &req, sizeof(req));
- + le2cpu_req(&req);
- +
- + if (req.sector.len != sizeof(sector)) {
- + ret = VBLK_RET_FAILED;
- + goto out;
- + }
- +
- + /* Read the vblk command */
- + cpu_physical_memory_read(req.sector.addr, §or, sizeof(sector));
- + le2cpu_sector(§or);
- +
- + off = sector.sector * 512ULL + static_off;
- +
- + /* Sanity check that we're not allocating bogus sizes */
- + if (req.data.len > (128 * 1024 * 1024)) {
- + goto out;
- + }
- +
- + buf = g_malloc0(req.data.len);
- + switch (req.data.flags) {
- + case VBLK_DATA_FLAGS_READ:
- + r = blk_pread(blk, off, req.data.len, buf, 0);
- + trace_bdif_vblk_read(devid == DEVID_AUX ? "aux" : "root",
- + req.data.addr, off, req.data.len, r);
- + if (r < 0) {
- + goto out;
- + }
- + cpu_physical_memory_write(req.data.addr, buf, req.data.len);
- + ret = VBLK_RET_SUCCESS;
- + break;
- + case VBLK_DATA_FLAGS_WRITE:
- + /* Not needed, iBoot only reads */
- + break;
- + default:
- + break;
- + }
- +
- +out:
- + g_free(buf);
- + cpu_physical_memory_write(req.retval.addr, &ret, 1);
- +}
- +
- +static void bdif_write(void *opaque, hwaddr offset,
- + uint64_t value, unsigned size)
- +{
- + VMAppleBdifState *s = opaque;
- + uint64_t devid = (offset & REG_DEVID_MASK);
- +
- + trace_bdif_write(offset, size, value);
- +
- + switch (offset & ~REG_DEVID_MASK) {
- + case REG_CMD:
- + switch (devid) {
- + case DEVID_ROOT:
- + vblk_cmd(devid, s->root, value, 0x0);
- + break;
- + case DEVID_AUX:
- + vblk_cmd(devid, s->aux, value, 0x0);
- + break;
- + }
- + break;
- + }
- +}
- +
- +static const MemoryRegionOps bdif_ops = {
- + .read = bdif_read,
- + .write = bdif_write,
- + .endianness = DEVICE_NATIVE_ENDIAN,
- + .valid = {
- + .min_access_size = 1,
- + .max_access_size = 8,
- + },
- + .impl = {
- + .min_access_size = 1,
- + .max_access_size = 8,
- + },
- +};
- +
- +static void bdif_init(Object *obj)
- +{
- + VMAppleBdifState *s = VMAPPLE_BDIF(obj);
- +
- + memory_region_init_io(&s->mmio, obj, &bdif_ops, obj,
- + "VMApple Backdoor Interface", VMAPPLE_BDIF_SIZE);
- + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
- +}
- +
- +static Property bdif_properties[] = {
- + DEFINE_PROP_DRIVE("aux", VMAppleBdifState, aux),
- + DEFINE_PROP_DRIVE("root", VMAppleBdifState, root),
- + DEFINE_PROP_END_OF_LIST(),
- +};
- +
- +static void bdif_class_init(ObjectClass *klass, void *data)
- +{
- + DeviceClass *dc = DEVICE_CLASS(klass);
- +
- + dc->desc = "VMApple Backdoor Interface";
- + device_class_set_props(dc, bdif_properties);
- +}
- +
- +static const TypeInfo bdif_info = {
- + .name = TYPE_VMAPPLE_BDIF,
- + .parent = TYPE_SYS_BUS_DEVICE,
- + .instance_size = sizeof(VMAppleBdifState),
- + .instance_init = bdif_init,
- + .class_init = bdif_class_init,
- +};
- +
- +static void bdif_register_types(void)
- +{
- + type_register_static(&bdif_info);
- +}
- +
- +type_init(bdif_register_types)
- diff --git a/hw/vmapple/cfg.c b/hw/vmapple/cfg.c
- new file mode 100644
- index 0000000000..d48e3c3afa
- --- /dev/null
- +++ b/hw/vmapple/cfg.c
- @@ -0,0 +1,105 @@
- +/*
- + * VMApple Configuration Region
- + *
- + * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- + *
- + * This work is licensed under the terms of the GNU GPL, version 2 or later.
- + * See the COPYING file in the top-level directory.
- + */
- +
- +#include "qemu/osdep.h"
- +#include "hw/vmapple/cfg.h"
- +#include "qemu/log.h"
- +#include "qemu/module.h"
- +#include "qapi/error.h"
- +
- +static void vmapple_cfg_reset(DeviceState *dev)
- +{
- + VMAppleCfgState *s = VMAPPLE_CFG(dev);
- + VMAppleCfg *cfg;
- +
- + cfg = memory_region_get_ram_ptr(&s->mem);
- + memset((void *)cfg, 0, VMAPPLE_CFG_SIZE);
- + *cfg = s->cfg;
- +}
- +
- +static void vmapple_cfg_realize(DeviceState *dev, Error **errp)
- +{
- + VMAppleCfgState *s = VMAPPLE_CFG(dev);
- + uint32_t i;
- +
- + strncpy(s->cfg.serial, s->serial, sizeof(s->cfg.serial));
- + strncpy(s->cfg.model, s->model, sizeof(s->cfg.model));
- + strncpy(s->cfg.soc_name, s->soc_name, sizeof(s->cfg.soc_name));
- + strncpy(s->cfg.unk8, "D/A", sizeof(s->cfg.soc_name));
- + s->cfg.ecid = cpu_to_be64(s->cfg.ecid);
- + s->cfg.version = 2;
- + s->cfg.unk1 = 1;
- + s->cfg.unk2 = 1;
- + s->cfg.unk3 = 0x20;
- + s->cfg.unk4 = 0;
- + s->cfg.unk5 = 1;
- + s->cfg.unk6 = 1;
- + s->cfg.unk7 = 0;
- + s->cfg.unk10 = 1;
- +
- + g_assert(s->cfg.nr_cpus < ARRAY_SIZE(s->cfg.cpu_ids));
- + for (i = 0; i < s->cfg.nr_cpus; i++) {
- + s->cfg.cpu_ids[i] = i;
- + }
- +}
- +
- +static void vmapple_cfg_init(Object *obj)
- +{
- + VMAppleCfgState *s = VMAPPLE_CFG(obj);
- +
- + memory_region_init_ram(&s->mem, obj, "VMApple Config", VMAPPLE_CFG_SIZE,
- + &error_fatal);
- + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mem);
- +
- + s->serial = (char *)"1234";
- + s->model = (char *)"VM0001";
- + s->soc_name = (char *)"Apple M1 (Virtual)";
- +}
- +
- +static Property vmapple_cfg_properties[] = {
- + DEFINE_PROP_UINT32("nr-cpus", VMAppleCfgState, cfg.nr_cpus, 1),
- + DEFINE_PROP_UINT64("ecid", VMAppleCfgState, cfg.ecid, 0),
- + DEFINE_PROP_UINT64("ram-size", VMAppleCfgState, cfg.ram_size, 0),
- + DEFINE_PROP_UINT32("run_installer1", VMAppleCfgState, cfg.run_installer1, 0),
- + DEFINE_PROP_UINT32("run_installer2", VMAppleCfgState, cfg.run_installer2, 0),
- + DEFINE_PROP_UINT32("rnd", VMAppleCfgState, cfg.rnd, 0),
- + DEFINE_PROP_MACADDR("mac-en0", VMAppleCfgState, cfg.mac_en0),
- + DEFINE_PROP_MACADDR("mac-en1", VMAppleCfgState, cfg.mac_en1),
- + DEFINE_PROP_MACADDR("mac-wifi0", VMAppleCfgState, cfg.mac_wifi0),
- + DEFINE_PROP_MACADDR("mac-bt0", VMAppleCfgState, cfg.mac_bt0),
- + DEFINE_PROP_STRING("serial", VMAppleCfgState, serial),
- + DEFINE_PROP_STRING("model", VMAppleCfgState, model),
- + DEFINE_PROP_STRING("soc_name", VMAppleCfgState, soc_name),
- + DEFINE_PROP_END_OF_LIST(),
- +};
- +
- +static void vmapple_cfg_class_init(ObjectClass *klass, void *data)
- +{
- + DeviceClass *dc = DEVICE_CLASS(klass);
- +
- + dc->realize = vmapple_cfg_realize;
- + dc->desc = "VMApple Configuration Region";
- + device_class_set_props(dc, vmapple_cfg_properties);
- + dc->reset = vmapple_cfg_reset;
- +}
- +
- +static const TypeInfo vmapple_cfg_info = {
- + .name = TYPE_VMAPPLE_CFG,
- + .parent = TYPE_SYS_BUS_DEVICE,
- + .instance_size = sizeof(VMAppleCfgState),
- + .instance_init = vmapple_cfg_init,
- + .class_init = vmapple_cfg_class_init,
- +};
- +
- +static void vmapple_cfg_register_types(void)
- +{
- + type_register_static(&vmapple_cfg_info);
- +}
- +
- +type_init(vmapple_cfg_register_types)
- diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
- new file mode 100644
- index 0000000000..76d745f6b8
- --- /dev/null
- +++ b/hw/vmapple/meson.build
- @@ -0,0 +1,5 @@
- +system_ss.add(when: 'CONFIG_VMAPPLE_AES', if_true: files('aes.c'))
- +system_ss.add(when: 'CONFIG_VMAPPLE_BDIF', if_true: files('bdif.c'))
- +system_ss.add(when: 'CONFIG_VMAPPLE_CFG', if_true: files('cfg.c'))
- +system_ss.add(when: 'CONFIG_VMAPPLE_PVG', if_true: [files('apple-gfx.m'), pvg, metal])
- +specific_ss.add(when: 'CONFIG_VMAPPLE', if_true: files('vmapple.c'))
- diff --git a/hw/vmapple/trace-events b/hw/vmapple/trace-events
- new file mode 100644
- index 0000000000..078e679560
- --- /dev/null
- +++ b/hw/vmapple/trace-events
- @@ -0,0 +1,47 @@
- +# See docs/devel/tracing.rst for syntax documentation.
- +
- +# aes.c
- +aes_read_unknown(uint64_t offset) "offset=0x%"PRIx64
- +aes_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
- +aes_cmd_key_select_builtin(uint32_t ctx, uint32_t key_id, const char *direction, const char *cipher) "[%d] Selecting builtin key %d to %scrypt with %s"
- +aes_cmd_key_select_new(uint32_t ctx, uint32_t key_len, const char *direction, const char *cipher) "[%d] Selecting new key size=%d to %scrypt with %s"
- +aes_cmd_iv(uint32_t ctx, uint32_t iv0, uint32_t iv1, uint32_t iv2, uint32_t iv3) "[%d] 0x%08x 0x%08x 0x%08x 0x%08x"
- +aes_cmd_data(uint32_t key, uint32_t iv, uint64_t src, uint64_t dst, uint32_t len) "[key=%d iv=%d] src=0x%"PRIx64" dst=0x%"PRIx64" len=0x%x"
- +aes_cmd_data_error(const char *reason) "reason=%s"
- +aes_cmd_store_iv(uint32_t ctx, uint64_t addr, uint32_t iv0, uint32_t iv1, uint32_t iv2, uint32_t iv3) "[%d] addr=0x%"PRIx64"x -> 0x%08x 0x%08x 0x%08x 0x%08x"
- +aes_cmd_flag(uint32_t raise, uint32_t flag_info) "raise=%d flag_info=0x%x"
- +aes_fifo_process(uint32_t cmd, uint32_t success) "cmd=%d success=%d"
- +aes_write_unknown(uint64_t offset) "offset=0x%"PRIx64
- +aes_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
- +aes_2_read_unknown(uint64_t offset) "offset=0x%"PRIx64
- +aes_2_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
- +aes_2_write_unknown(uint64_t offset) "offset=0x%"PRIx64
- +aes_2_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
- +aes_dump_data(const char *desc, const char *hex) "%s%s"
- +
- +# bdif.c
- +bdif_read(uint64_t offset, uint32_t size, uint64_t value) "offset=0x%"PRIx64" size=0x%x value=0x%"PRIx64
- +bdif_write(uint64_t offset, uint32_t size, uint64_t value) "offset=0x%"PRIx64" size=0x%x value=0x%"PRIx64
- +bdif_vblk_read(const char *dev, uint64_t addr, uint64_t offset, uint32_t len, int r) "dev=%s addr=0x%"PRIx64" off=0x%"PRIx64" size=0x%x r=%d"
- +
- +# apple-gfx.m
- +apple_gfx_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
- +apple_gfx_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
- +apple_gfx_create_task(uint32_t vm_size, void *va) "vm_size=0x%x base_addr=%p"
- +apple_gfx_destroy_task(void *task) "task=%p"
- +apple_gfx_map_memory(void *task, uint32_t range_count, uint64_t virtual_offset, uint32_t read_only) "task=%p range_count=0x%x virtual_offset=0x%"PRIx64" read_only=%d"
- +apple_gfx_map_memory_range(uint32_t i, uint64_t phys_addr, uint64_t phys_len, void *va) "[%d] phys_addr=0x%"PRIx64" phys_len=0x%"PRIx64" va=%p"
- +apple_gfx_remap(uint64_t retval, uint64_t source, uint64_t target) "retval=%"PRId64" source=0x%"PRIx64" target=0x%"PRIx64
- +apple_gfx_unmap_memory(void *task, uint64_t virtual_offset, uint64_t length) "task=%p virtual_offset=0x%"PRIx64" length=0x%"PRIx64
- +apple_gfx_read_memory(uint64_t phys_address, uint64_t length, void *dst) "phys_addr=0x%"PRIx64" length=0x%"PRIx64" dest=%p"
- +apple_gfx_raise_irq(uint32_t vector) "vector=0x%x"
- +apple_gfx_new_frame(void) ""
- +apple_gfx_mode_change(uint64_t x, uint64_t y) "x=%"PRId64" y=%"PRId64
- +apple_gfx_cursor_set(uint32_t bpp, uint64_t width, uint64_t height) "bpp=%d width=%"PRId64" height=0x%"PRId64
- +apple_gfx_cursor_show(uint32_t show) "show=%d"
- +apple_gfx_cursor_move(void) ""
- +apple_iosfc_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
- +apple_iosfc_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
- +apple_iosfc_map_memory(uint64_t phys, uint64_t len, uint32_t ro, void *va, void *e, void *f) "phys=0x%"PRIx64" len=0x%"PRIx64" ro=%d va=%p e=%p f=%p"
- +apple_iosfc_unmap_memory(void *a, void *b, void *c, void *d, void *e, void *f) "a=%p b=%p c=%p d=%p e=%p f=%p"
- +apple_iosfc_raise_irq(uint32_t vector) "vector=0x%x"
- diff --git a/hw/vmapple/trace.h b/hw/vmapple/trace.h
- new file mode 100644
- index 0000000000..572adbefe0
- --- /dev/null
- +++ b/hw/vmapple/trace.h
- @@ -0,0 +1 @@
- +#include "trace/trace-hw_vmapple.h"
- diff --git a/hw/vmapple/vmapple.c b/hw/vmapple/vmapple.c
- new file mode 100644
- index 0000000000..5d3fe54b96
- --- /dev/null
- +++ b/hw/vmapple/vmapple.c
- @@ -0,0 +1,661 @@
- +/*
- + * VMApple machine emulation
- + *
- + * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- + *
- + * This work is licensed under the terms of the GNU GPL, version 2 or later.
- + * See the COPYING file in the top-level directory.
- + *
- + * VMApple is the device model that the macOS built-in hypervisor called
- + * "Virtualization.framework" exposes to Apple Silicon macOS guests. The
- + * machine model in this file implements the same device model in QEMU, but
- + * does not use any code from Virtualization.Framework.
- + */
- +
- +#include "qemu/osdep.h"
- +#include "qemu/help-texts.h"
- +#include "qemu/datadir.h"
- +#include "qemu/units.h"
- +#include "qemu/option.h"
- +#include "monitor/qdev.h"
- +#include "qapi/error.h"
- +#include "hw/sysbus.h"
- +#include "hw/arm/boot.h"
- +#include "hw/arm/primecell.h"
- +#include "hw/boards.h"
- +#include "net/net.h"
- +#include "sysemu/sysemu.h"
- +#include "sysemu/runstate.h"
- +#include "sysemu/kvm.h"
- +#include "sysemu/hvf.h"
- +#include "hw/loader.h"
- +#include "qapi/error.h"
- +#include "qemu/bitops.h"
- +#include "qemu/error-report.h"
- +#include "qemu/module.h"
- +#include "hw/pci-host/gpex.h"
- +#include "hw/virtio/virtio-pci.h"
- +#include "hw/qdev-properties.h"
- +#include "hw/intc/arm_gic.h"
- +#include "hw/intc/arm_gicv3_common.h"
- +#include "hw/irq.h"
- +#include "qapi/visitor.h"
- +#include "qapi/qapi-visit-common.h"
- +#include "standard-headers/linux/input.h"
- +#include "target/arm/internals.h"
- +#include "target/arm/kvm_arm.h"
- +#include "hw/char/pl011.h"
- +#include "qemu/guest-random.h"
- +#include "sysemu/reset.h"
- +#include "qemu/log.h"
- +#include "hw/vmapple/cfg.h"
- +#include "hw/misc/pvpanic.h"
- +#include "hw/vmapple/bdif.h"
- +
- +struct VMAppleMachineClass {
- + MachineClass parent;
- +};
- +
- +struct VMAppleMachineState {
- + MachineState parent;
- + Notifier machine_done;
- + struct arm_boot_info bootinfo;
- + MemMapEntry *memmap;
- + const int *irqmap;
- + DeviceState *gic;
- + DeviceState *cfg;
- + Notifier powerdown_notifier;
- + PCIBus *bus;
- + MemoryRegion fw_mr;
- + uint64_t uuid;
- +};
- +
- +#define DEFINE_VMAPPLE_MACHINE_LATEST(major, minor, latest) \
- + static void vmapple##major##_##minor##_class_init(ObjectClass *oc, \
- + void *data) \
- + { \
- + MachineClass *mc = MACHINE_CLASS(oc); \
- + vmapple_machine_##major##_##minor##_options(mc); \
- + mc->desc = "QEMU " # major "." # minor " Apple Virtual Machine"; \
- + if (latest) { \
- + mc->alias = "vmapple"; \
- + } \
- + } \
- + static const TypeInfo machvmapple##major##_##minor##_info = { \
- + .name = MACHINE_TYPE_NAME("vmapple-" # major "." # minor), \
- + .parent = TYPE_VMAPPLE_MACHINE, \
- + .class_init = vmapple##major##_##minor##_class_init, \
- + }; \
- + static void machvmapple_machine_##major##_##minor##_init(void) \
- + { \
- + type_register_static(&machvmapple##major##_##minor##_info); \
- + } \
- + type_init(machvmapple_machine_##major##_##minor##_init);
- +
- +#define DEFINE_VMAPPLE_MACHINE_AS_LATEST(major, minor) \
- + DEFINE_VMAPPLE_MACHINE_LATEST(major, minor, true)
- +#define DEFINE_VMAPPLE_MACHINE(major, minor) \
- + DEFINE_VMAPPLE_MACHINE_LATEST(major, minor, false)
- +
- +#define TYPE_VMAPPLE_MACHINE MACHINE_TYPE_NAME("vmapple")
- +OBJECT_DECLARE_TYPE(VMAppleMachineState, VMAppleMachineClass, VMAPPLE_MACHINE)
- +
- +/* Number of external interrupt lines to configure the GIC with */
- +#define NUM_IRQS 256
- +
- +enum {
- + VMAPPLE_FIRMWARE,
- + VMAPPLE_CONFIG,
- + VMAPPLE_MEM,
- + VMAPPLE_GIC_DIST,
- + VMAPPLE_GIC_REDIST,
- + VMAPPLE_UART,
- + VMAPPLE_RTC,
- + VMAPPLE_PCIE,
- + VMAPPLE_PCIE_MMIO,
- + VMAPPLE_PCIE_ECAM,
- + VMAPPLE_GPIO,
- + VMAPPLE_PVPANIC,
- + VMAPPLE_APV_GFX,
- + VMAPPLE_APV_IOSFC,
- + VMAPPLE_AES_1,
- + VMAPPLE_AES_2,
- + VMAPPLE_BDOOR,
- + VMAPPLE_MEMMAP_LAST,
- +};
- +
- +static MemMapEntry memmap[] = {
- + [VMAPPLE_FIRMWARE] = { 0x00100000, 0x00100000 },
- + [VMAPPLE_CONFIG] = { 0x00400000, 0x00010000 },
- +
- + [VMAPPLE_GIC_DIST] = { 0x10000000, 0x00010000 },
- + [VMAPPLE_GIC_REDIST] = { 0x10010000, 0x00400000 },
- +
- + [VMAPPLE_UART] = { 0x20010000, 0x00010000 },
- + [VMAPPLE_RTC] = { 0x20050000, 0x00001000 },
- + [VMAPPLE_GPIO] = { 0x20060000, 0x00001000 },
- + [VMAPPLE_PVPANIC] = { 0x20070000, 0x00000002 },
- + [VMAPPLE_BDOOR] = { 0x30000000, 0x00200000 },
- + [VMAPPLE_APV_GFX] = { 0x30200000, 0x00010000 },
- + [VMAPPLE_APV_IOSFC] = { 0x30210000, 0x00010000 },
- + [VMAPPLE_AES_1] = { 0x30220000, 0x00004000 },
- + [VMAPPLE_AES_2] = { 0x30230000, 0x00004000 },
- + [VMAPPLE_PCIE_ECAM] = { 0x40000000, 0x10000000 },
- + [VMAPPLE_PCIE_MMIO] = { 0x50000000, 0x1fff0000 },
- +
- + /* Actual RAM size depends on configuration */
- + [VMAPPLE_MEM] = { 0x70000000ULL, GiB},
- +};
- +
- +static const int irqmap[] = {
- + [VMAPPLE_UART] = 1,
- + [VMAPPLE_RTC] = 2,
- + [VMAPPLE_GPIO] = 0x5,
- + [VMAPPLE_APV_IOSFC] = 0x10,
- + [VMAPPLE_APV_GFX] = 0x11,
- + [VMAPPLE_AES_1] = 0x12,
- + [VMAPPLE_PCIE] = 0x20,
- +};
- +
- +#define GPEX_NUM_IRQS 16
- +
- +static void create_bdif(VMAppleMachineState *vms, MemoryRegion *mem)
- +{
- + DeviceState *bdif;
- + SysBusDevice *bdif_sb;
- + DriveInfo *di_aux = drive_get(IF_PFLASH, 0, 0);
- + DriveInfo *di_root = drive_get(IF_PFLASH, 0, 1);
- +
- + if (!di_aux) {
- + error_report("No AUX device found. Please specify one as pflash drive");
- + exit(1);
- + }
- +
- + if (!di_root) {
- + /* Fall back to the first IF_VIRTIO device as root device */
- + di_root = drive_get(IF_VIRTIO, 0, 0);
- + }
- +
- + if (!di_root) {
- + error_report("No root device found. Please specify one as virtio drive");
- + exit(1);
- + }
- +
- + /* PV backdoor device */
- + bdif = qdev_new(TYPE_VMAPPLE_BDIF);
- + bdif_sb = SYS_BUS_DEVICE(bdif);
- + sysbus_mmio_map(bdif_sb, 0, vms->memmap[VMAPPLE_BDOOR].base);
- +
- + qdev_prop_set_drive(DEVICE(bdif), "aux", blk_by_legacy_dinfo(di_aux));
- + qdev_prop_set_drive(DEVICE(bdif), "root", blk_by_legacy_dinfo(di_root));
- +
- + sysbus_realize_and_unref(bdif_sb, &error_fatal);
- +}
- +
- +static void create_pvpanic(VMAppleMachineState *vms, MemoryRegion *mem)
- +{
- + SysBusDevice *cfg;
- +
- + vms->cfg = qdev_new(TYPE_PVPANIC_MMIO_DEVICE);
- + cfg = SYS_BUS_DEVICE(vms->cfg);
- + sysbus_mmio_map(cfg, 0, vms->memmap[VMAPPLE_PVPANIC].base);
- +
- + sysbus_realize_and_unref(cfg, &error_fatal);
- +}
- +
- +static void create_cfg(VMAppleMachineState *vms, MemoryRegion *mem)
- +{
- + SysBusDevice *cfg;
- + MachineState *machine = MACHINE(vms);
- + uint32_t rnd = 1;
- +
- + vms->cfg = qdev_new(TYPE_VMAPPLE_CFG);
- + cfg = SYS_BUS_DEVICE(vms->cfg);
- + sysbus_mmio_map(cfg, 0, vms->memmap[VMAPPLE_CONFIG].base);
- +
- + qemu_guest_getrandom_nofail(&rnd, sizeof(rnd));
- +
- + qdev_prop_set_uint32(vms->cfg, "nr-cpus", machine->smp.cpus);
- + qdev_prop_set_uint64(vms->cfg, "ecid", vms->uuid);
- + qdev_prop_set_uint64(vms->cfg, "ram-size", machine->ram_size);
- + qdev_prop_set_uint32(vms->cfg, "rnd", rnd);
- +
- + sysbus_realize_and_unref(cfg, &error_fatal);
- +}
- +
- +static void create_gfx(VMAppleMachineState *vms, MemoryRegion *mem)
- +{
- + int irq_gfx = vms->irqmap[VMAPPLE_APV_GFX];
- + int irq_iosfc = vms->irqmap[VMAPPLE_APV_IOSFC];
- + SysBusDevice *aes;
- +
- + aes = SYS_BUS_DEVICE(qdev_new("apple-gfx"));
- + sysbus_mmio_map(aes, 0, vms->memmap[VMAPPLE_APV_GFX].base);
- + sysbus_mmio_map(aes, 1, vms->memmap[VMAPPLE_APV_IOSFC].base);
- + sysbus_connect_irq(aes, 0, qdev_get_gpio_in(vms->gic, irq_gfx));
- + sysbus_connect_irq(aes, 1, qdev_get_gpio_in(vms->gic, irq_iosfc));
- + sysbus_realize_and_unref(aes, &error_fatal);
- +}
- +
- +static void create_aes(VMAppleMachineState *vms, MemoryRegion *mem)
- +{
- + int irq = vms->irqmap[VMAPPLE_AES_1];
- + SysBusDevice *aes;
- +
- + aes = SYS_BUS_DEVICE(qdev_new("apple-aes"));
- + sysbus_mmio_map(aes, 0, vms->memmap[VMAPPLE_AES_1].base);
- + sysbus_mmio_map(aes, 1, vms->memmap[VMAPPLE_AES_2].base);
- + sysbus_connect_irq(aes, 0, qdev_get_gpio_in(vms->gic, irq));
- + sysbus_realize_and_unref(aes, &error_fatal);
- +}
- +
- +static inline int arm_gic_ppi_index(int cpu_nr, int ppi_index)
- +{
- + return NUM_IRQS + cpu_nr * GIC_INTERNAL + ppi_index;
- +}
- +
- +static void create_gic(VMAppleMachineState *vms, MemoryRegion *mem)
- +{
- + MachineState *ms = MACHINE(vms);
- + /* We create a standalone GIC */
- + SysBusDevice *gicbusdev;
- + int i;
- + unsigned int smp_cpus = ms->smp.cpus;
- +
- + vms->gic = qdev_new(gicv3_class_name());
- + qdev_prop_set_uint32(vms->gic, "revision", 3);
- + qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus);
- + /*
- + * Note that the num-irq property counts both internal and external
- + * interrupts; there are always 32 of the former (mandated by GIC spec).
- + */
- + qdev_prop_set_uint32(vms->gic, "num-irq", NUM_IRQS + 32);
- +
- + uint32_t redist0_capacity =
- + vms->memmap[VMAPPLE_GIC_REDIST].size / GICV3_REDIST_SIZE;
- + uint32_t redist0_count = MIN(smp_cpus, redist0_capacity);
- +
- + qdev_prop_set_uint32(vms->gic, "len-redist-region-count", 1);
- + qdev_prop_set_uint32(vms->gic, "redist-region-count[0]", redist0_count);
- +
- + gicbusdev = SYS_BUS_DEVICE(vms->gic);
- + sysbus_realize_and_unref(gicbusdev, &error_fatal);
- + sysbus_mmio_map(gicbusdev, 0, vms->memmap[VMAPPLE_GIC_DIST].base);
- + sysbus_mmio_map(gicbusdev, 1, vms->memmap[VMAPPLE_GIC_REDIST].base);
- +
- + /*
- + * Wire the outputs from each CPU's generic timer and the GICv3
- + * maintenance interrupt signal to the appropriate GIC PPI inputs,
- + * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs.
- + */
- + for (i = 0; i < smp_cpus; i++) {
- + DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
- +
- + /* Map the virt timer to PPI 27 */
- + qdev_connect_gpio_out(cpudev, GTIMER_VIRT,
- + qdev_get_gpio_in(vms->gic,
- + arm_gic_ppi_index(i, 27)));
- +
- + /* Map the GIC IRQ and FIQ lines to CPU */
- + sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
- + sysbus_connect_irq(gicbusdev, i + smp_cpus,
- + qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
- + }
- +}
- +
- +static void create_uart(const VMAppleMachineState *vms, int uart,
- + MemoryRegion *mem, Chardev *chr)
- +{
- + hwaddr base = vms->memmap[uart].base;
- + int irq = vms->irqmap[uart];
- + DeviceState *dev = qdev_new(TYPE_PL011);
- + SysBusDevice *s = SYS_BUS_DEVICE(dev);
- +
- + qdev_prop_set_chr(dev, "chardev", chr);
- + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- + memory_region_add_subregion(mem, base,
- + sysbus_mmio_get_region(s, 0));
- + sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
- +}
- +
- +static void create_rtc(const VMAppleMachineState *vms)
- +{
- + hwaddr base = vms->memmap[VMAPPLE_RTC].base;
- + int irq = vms->irqmap[VMAPPLE_RTC];
- +
- + sysbus_create_simple("pl031", base, qdev_get_gpio_in(vms->gic, irq));
- +}
- +
- +static DeviceState *gpio_key_dev;
- +static void vmapple_powerdown_req(Notifier *n, void *opaque)
- +{
- + /* use gpio Pin 3 for power button event */
- + qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
- +}
- +
- +static void create_gpio_devices(const VMAppleMachineState *vms, int gpio,
- + MemoryRegion *mem)
- +{
- + DeviceState *pl061_dev;
- + hwaddr base = vms->memmap[gpio].base;
- + int irq = vms->irqmap[gpio];
- + SysBusDevice *s;
- +
- + pl061_dev = qdev_new("pl061");
- + /* Pull lines down to 0 if not driven by the PL061 */
- + qdev_prop_set_uint32(pl061_dev, "pullups", 0);
- + qdev_prop_set_uint32(pl061_dev, "pulldowns", 0xff);
- + s = SYS_BUS_DEVICE(pl061_dev);
- + sysbus_realize_and_unref(s, &error_fatal);
- + memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0));
- + sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
- + gpio_key_dev = sysbus_create_simple("gpio-key", -1,
- + qdev_get_gpio_in(pl061_dev, 3));
- +}
- +
- +static void vmapple_firmware_init(VMAppleMachineState *vms,
- + MemoryRegion *sysmem)
- +{
- + hwaddr size = vms->memmap[VMAPPLE_FIRMWARE].size;
- + hwaddr base = vms->memmap[VMAPPLE_FIRMWARE].base;
- + const char *bios_name;
- + int image_size;
- + char *fname;
- +
- + bios_name = MACHINE(vms)->firmware;
- + if (!bios_name) {
- + error_report("No firmware specified");
- + exit(1);
- + }
- +
- + fname = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- + if (!fname) {
- + error_report("Could not find ROM image '%s'", bios_name);
- + exit(1);
- + }
- +
- + memory_region_init_ram(&vms->fw_mr, NULL, "firmware", size, NULL);
- + image_size = load_image_mr(fname, &vms->fw_mr);
- +
- + g_free(fname);
- + if (image_size < 0) {
- + error_report("Could not load ROM image '%s'", bios_name);
- + exit(1);
- + }
- +
- + memory_region_add_subregion(get_system_memory(), base, &vms->fw_mr);
- +}
- +
- +static void create_pcie(VMAppleMachineState *vms)
- +{
- + hwaddr base_mmio = vms->memmap[VMAPPLE_PCIE_MMIO].base;
- + hwaddr size_mmio = vms->memmap[VMAPPLE_PCIE_MMIO].size;
- + hwaddr base_ecam = vms->memmap[VMAPPLE_PCIE_ECAM].base;
- + hwaddr size_ecam = vms->memmap[VMAPPLE_PCIE_ECAM].size;
- + int irq = vms->irqmap[VMAPPLE_PCIE];
- + MemoryRegion *mmio_alias;
- + MemoryRegion *mmio_reg;
- + MemoryRegion *ecam_alias;
- + MemoryRegion *ecam_reg;
- + DeviceState *dev;
- + int i;
- + PCIHostState *pci;
- + DeviceState *virtio_tablet;
- + DeviceState *virtio_keyboard;
- +
- + dev = qdev_new(TYPE_GPEX_HOST);
- + qdev_prop_set_uint32(dev, "nr-irqs", GPEX_NUM_IRQS);
- + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- +
- + /* Map only the first size_ecam bytes of ECAM space */
- + ecam_alias = g_new0(MemoryRegion, 1);
- + ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
- + memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
- + ecam_reg, 0, size_ecam);
- + memory_region_add_subregion(get_system_memory(), base_ecam, ecam_alias);
- +
- + /*
- + * Map the MMIO window from [0x50000000-0x7fff0000] in PCI space into
- + * system address space at [0x50000000-0x7fff0000].
- + */
- + mmio_alias = g_new0(MemoryRegion, 1);
- + mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
- + memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
- + mmio_reg, base_mmio, size_mmio);
- + memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias);
- +
- + for (i = 0; i < GPEX_NUM_IRQS; i++) {
- + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
- + qdev_get_gpio_in(vms->gic, irq + i));
- + gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
- + }
- +
- + pci = PCI_HOST_BRIDGE(dev);
- + vms->bus = pci->bus;
- + if (vms->bus) {
- + for (i = 0; i < nb_nics; i++) {
- + NICInfo *nd = &nd_table[i];
- +
- + if (!nd->model) {
- + nd->model = g_strdup("virtio");
- + }
- +
- + pci_nic_init_nofail(nd, pci->bus, nd->model, NULL);
- + }
- + }
- +
- + virtio_tablet = qdev_new("virtio-tablet-pci");
- + qdev_realize(virtio_tablet, BUS(pci->bus), &error_fatal);
- + object_unref(virtio_tablet);
- +
- + virtio_keyboard = qdev_new("virtio-keyboard-pci");
- + qdev_realize(virtio_keyboard, BUS(pci->bus), &error_fatal);
- + object_unref(virtio_keyboard);
- +}
- +
- +static void vmapple_reset(void *opaque)
- +{
- + VMAppleMachineState *vms = opaque;
- + hwaddr base = vms->memmap[VMAPPLE_FIRMWARE].base;
- +
- + cpu_set_pc(first_cpu, base);
- +}
- +
- +static void mach_vmapple_init(MachineState *machine)
- +{
- + VMAppleMachineState *vms = VMAPPLE_MACHINE(machine);
- + MachineClass *mc = MACHINE_GET_CLASS(machine);
- + const CPUArchIdList *possible_cpus;
- + MemoryRegion *sysmem = get_system_memory();
- + int n;
- + unsigned int smp_cpus = machine->smp.cpus;
- + unsigned int max_cpus = machine->smp.max_cpus;
- +
- + vms->memmap = memmap;
- +
- + possible_cpus = mc->possible_cpu_arch_ids(machine);
- + assert(possible_cpus->len == max_cpus);
- + for (n = 0; n < possible_cpus->len; n++) {
- + Object *cpu;
- + CPUState *cs;
- +
- + if (n >= smp_cpus) {
- + break;
- + }
- +
- + cpu = object_new(possible_cpus->cpus[n].type);
- + object_property_set_int(cpu, "mp-affinity",
- + possible_cpus->cpus[n].arch_id, NULL);
- +
- + cs = CPU(cpu);
- + cs->cpu_index = n;
- +
- + numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpu),
- + &error_fatal);
- +
- + object_property_set_bool(cpu, "has_el3", false, NULL);
- + object_property_set_bool(cpu, "has_el2", false, NULL);
- + object_property_set_int(cpu, "psci-conduit", QEMU_PSCI_CONDUIT_HVC,
- + NULL);
- +
- + /* Secondary CPUs start in PSCI powered-down state */
- + if (n > 0) {
- + object_property_set_bool(cpu, "start-powered-off", true, NULL);
- + }
- +
- + object_property_set_link(cpu, "memory", OBJECT(sysmem), &error_abort);
- + qdev_realize(DEVICE(cpu), NULL, &error_fatal);
- + object_unref(cpu);
- + }
- +
- + memory_region_add_subregion(sysmem, vms->memmap[VMAPPLE_MEM].base,
- + machine->ram);
- +
- + create_gic(vms, sysmem);
- + create_bdif(vms, sysmem);
- + create_pvpanic(vms, sysmem);
- + create_aes(vms, sysmem);
- + create_gfx(vms, sysmem);
- + create_uart(vms, VMAPPLE_UART, sysmem, serial_hd(0));
- + create_rtc(vms);
- + create_pcie(vms);
- +
- + create_gpio_devices(vms, VMAPPLE_GPIO, sysmem);
- +
- + vmapple_firmware_init(vms, sysmem);
- + create_cfg(vms, sysmem);
- +
- + /* connect powerdown request */
- + vms->powerdown_notifier.notify = vmapple_powerdown_req;
- + qemu_register_powerdown_notifier(&vms->powerdown_notifier);
- +
- + vms->bootinfo.ram_size = machine->ram_size;
- + vms->bootinfo.board_id = -1;
- + vms->bootinfo.loader_start = vms->memmap[VMAPPLE_MEM].base;
- + vms->bootinfo.skip_dtb_autoload = true;
- + vms->bootinfo.firmware_loaded = true;
- + arm_load_kernel(ARM_CPU(first_cpu), machine, &vms->bootinfo);
- +
- + qemu_register_reset(vmapple_reset, vms);
- +}
- +
- +static CpuInstanceProperties
- +vmapple_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
- +{
- + MachineClass *mc = MACHINE_GET_CLASS(ms);
- + const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
- +
- + assert(cpu_index < possible_cpus->len);
- + return possible_cpus->cpus[cpu_index].props;
- +}
- +
- +
- +static int64_t vmapple_get_default_cpu_node_id(const MachineState *ms, int idx)
- +{
- + return idx % ms->numa_state->num_nodes;
- +}
- +
- +static const CPUArchIdList *vmapple_possible_cpu_arch_ids(MachineState *ms)
- +{
- + int n;
- + unsigned int max_cpus = ms->smp.max_cpus;
- +
- + if (ms->possible_cpus) {
- + assert(ms->possible_cpus->len == max_cpus);
- + return ms->possible_cpus;
- + }
- +
- + ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
- + sizeof(CPUArchId) * max_cpus);
- + ms->possible_cpus->len = max_cpus;
- + for (n = 0; n < ms->possible_cpus->len; n++) {
- + ms->possible_cpus->cpus[n].type = ms->cpu_type;
- + ms->possible_cpus->cpus[n].arch_id =
- + arm_cpu_mp_affinity(n, GICV3_TARGETLIST_BITS);
- + ms->possible_cpus->cpus[n].props.has_thread_id = true;
- + ms->possible_cpus->cpus[n].props.thread_id = n;
- + }
- + return ms->possible_cpus;
- +}
- +
- +static void vmapple_get_uuid(Object *obj, Visitor *v, const char *name,
- + void *opaque, Error **errp)
- +{
- + VMAppleMachineState *vms = VMAPPLE_MACHINE(obj);
- + uint64_t value = be64_to_cpu(vms->uuid);
- +
- + visit_type_uint64(v, name, &value, errp);
- +}
- +
- +static void vmapple_set_uuid(Object *obj, Visitor *v, const char *name,
- + void *opaque, Error **errp)
- +{
- + VMAppleMachineState *vms = VMAPPLE_MACHINE(obj);
- + Error *error = NULL;
- + uint64_t value;
- +
- + visit_type_uint64(v, name, &value, &error);
- + if (error) {
- + error_propagate(errp, error);
- + return;
- + }
- +
- + vms->uuid = cpu_to_be64(value);
- +}
- +
- +static void vmapple_machine_class_init(ObjectClass *oc, void *data)
- +{
- + MachineClass *mc = MACHINE_CLASS(oc);
- +
- + mc->init = mach_vmapple_init;
- + mc->max_cpus = 32;
- + mc->block_default_type = IF_VIRTIO;
- + mc->no_cdrom = 1;
- + mc->pci_allow_0_address = true;
- + mc->minimum_page_bits = 12;
- + mc->possible_cpu_arch_ids = vmapple_possible_cpu_arch_ids;
- + mc->cpu_index_to_instance_props = vmapple_cpu_index_to_props;
- + if (hvf_enabled()) {
- + mc->default_cpu_type = ARM_CPU_TYPE_NAME("host");
- + } else {
- + mc->default_cpu_type = ARM_CPU_TYPE_NAME("max");
- + }
- + mc->get_default_cpu_node_id = vmapple_get_default_cpu_node_id;
- + mc->default_ram_id = "mach-vmapple.ram";
- +
- + object_register_sugar_prop(TYPE_VIRTIO_PCI, "disable-legacy",
- + "on", true);
- +
- + object_class_property_add(oc, "uuid", "uint64", vmapple_get_uuid,
- + vmapple_set_uuid, NULL, NULL);
- + object_class_property_set_description(oc, "uuid", "Machine UUID (SDOM)");
- +}
- +
- +static void vmapple_instance_init(Object *obj)
- +{
- + VMAppleMachineState *vms = VMAPPLE_MACHINE(obj);
- +
- + vms->irqmap = irqmap;
- +}
- +
- +static const TypeInfo vmapple_machine_info = {
- + .name = TYPE_VMAPPLE_MACHINE,
- + .parent = TYPE_MACHINE,
- + .abstract = true,
- + .instance_size = sizeof(VMAppleMachineState),
- + .class_size = sizeof(VMAppleMachineClass),
- + .class_init = vmapple_machine_class_init,
- + .instance_init = vmapple_instance_init,
- +};
- +
- +static void machvmapple_machine_init(void)
- +{
- + type_register_static(&vmapple_machine_info);
- +}
- +type_init(machvmapple_machine_init);
- +
- +static void vmapple_machine_8_1_options(MachineClass *mc)
- +{
- +}
- +DEFINE_VMAPPLE_MACHINE_AS_LATEST(8, 1)
- +
- diff --git a/hw/xtensa/virt.c b/hw/xtensa/virt.c
- index a6cf646e99..c23c540e87 100644
- --- a/hw/xtensa/virt.c
- +++ b/hw/xtensa/virt.c
- @@ -93,7 +93,7 @@ static void create_pcie(MachineState *ms, CPUXtensaState *env, int irq_base,
- /* Connect IRQ lines. */
- extints = xtensa_get_extints(env);
- - for (i = 0; i < GPEX_NUM_IRQS; i++) {
- + for (i = 0; i < PCI_NUM_PINS; i++) {
- void *q = extints[irq_base + i];
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, q);
- diff --git a/include/hw/misc/pvpanic.h b/include/hw/misc/pvpanic.h
- index fab94165d0..f9e7c1ea17 100644
- --- a/include/hw/misc/pvpanic.h
- +++ b/include/hw/misc/pvpanic.h
- @@ -20,6 +20,7 @@
- #define TYPE_PVPANIC_ISA_DEVICE "pvpanic"
- #define TYPE_PVPANIC_PCI_DEVICE "pvpanic-pci"
- +#define TYPE_PVPANIC_MMIO_DEVICE "pvpanic-mmio"
- #define PVPANIC_IOPORT_PROP "ioport"
- diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h
- index b0240bd768..098dc4d1cc 100644
- --- a/include/hw/pci-host/gpex.h
- +++ b/include/hw/pci-host/gpex.h
- @@ -32,8 +32,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(GPEXHost, GPEX_HOST)
- #define TYPE_GPEX_ROOT_DEVICE "gpex-root"
- OBJECT_DECLARE_SIMPLE_TYPE(GPEXRootState, GPEX_ROOT_DEVICE)
- -#define GPEX_NUM_IRQS 4
- -
- struct GPEXRootState {
- /*< private >*/
- PCIDevice parent_obj;
- @@ -51,8 +49,9 @@ struct GPEXHost {
- MemoryRegion io_mmio;
- MemoryRegion io_ioport_window;
- MemoryRegion io_mmio_window;
- - qemu_irq irq[GPEX_NUM_IRQS];
- - int irq_num[GPEX_NUM_IRQS];
- + uint32_t nr_irqs;
- + qemu_irq *irq;
- + int *irq_num;
- bool allow_unmapped_accesses;
- };
- diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
- index e4386ebb20..74e589a298 100644
- --- a/include/hw/pci/pci_ids.h
- +++ b/include/hw/pci/pci_ids.h
- @@ -188,6 +188,7 @@
- #define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020
- #define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b
- #define PCI_DEVICE_ID_APPLE_UNI_N_GMAC 0x0021
- +#define PCI_DEVICE_ID_APPLE_VIRTIO_BLK 0x1a00
- #define PCI_VENDOR_ID_SUN 0x108e
- #define PCI_DEVICE_ID_SUN_EBUS 0x1000
- diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
- index dafec432ce..7117ce754c 100644
- --- a/include/hw/virtio/virtio-blk.h
- +++ b/include/hw/virtio/virtio-blk.h
- @@ -46,6 +46,7 @@ struct VirtIOBlkConf
- uint32_t max_discard_sectors;
- uint32_t max_write_zeroes_sectors;
- bool x_enable_wce_if_config_wce;
- + uint32_t x_apple_type;
- };
- struct VirtIOBlockDataPlane;
- diff --git a/include/hw/vmapple/bdif.h b/include/hw/vmapple/bdif.h
- new file mode 100644
- index 0000000000..65ee43457b
- --- /dev/null
- +++ b/include/hw/vmapple/bdif.h
- @@ -0,0 +1,31 @@
- +/*
- + * VMApple Backdoor Interface
- + *
- + * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- + *
- + * This work is licensed under the terms of the GNU GPL, version 2 or later.
- + * See the COPYING file in the top-level directory.
- + */
- +
- +#ifndef HW_VMAPPLE_BDIF_H
- +#define HW_VMAPPLE_BDIF_H
- +
- +#include "hw/sysbus.h"
- +#include "qom/object.h"
- +
- +#define TYPE_VMAPPLE_BDIF "vmapple-bdif"
- +OBJECT_DECLARE_SIMPLE_TYPE(VMAppleBdifState, VMAPPLE_BDIF)
- +
- +struct VMAppleBdifState {
- + /* <private> */
- + SysBusDevice parent_obj;
- +
- + /* <public> */
- + BlockBackend *aux;
- + BlockBackend *root;
- + MemoryRegion mmio;
- +};
- +
- +#define VMAPPLE_BDIF_SIZE 0x00200000
- +
- +#endif /* HW_VMAPPLE_BDIF_H */
- diff --git a/include/hw/vmapple/cfg.h b/include/hw/vmapple/cfg.h
- new file mode 100644
- index 0000000000..3337064e44
- --- /dev/null
- +++ b/include/hw/vmapple/cfg.h
- @@ -0,0 +1,68 @@
- +/*
- + * VMApple Configuration Region
- + *
- + * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- + *
- + * This work is licensed under the terms of the GNU GPL, version 2 or later.
- + * See the COPYING file in the top-level directory.
- + */
- +
- +#ifndef HW_VMAPPLE_CFG_H
- +#define HW_VMAPPLE_CFG_H
- +
- +#include "hw/sysbus.h"
- +#include "qom/object.h"
- +#include "net/net.h"
- +
- +typedef struct VMAppleCfg {
- + uint32_t version; /* 0x000 */
- + uint32_t nr_cpus; /* 0x004 */
- + uint32_t unk1; /* 0x008 */
- + uint32_t unk2; /* 0x00c */
- + uint32_t unk3; /* 0x010 */
- + uint32_t unk4; /* 0x014 */
- + uint64_t ecid; /* 0x018 */
- + uint64_t ram_size; /* 0x020 */
- + uint32_t run_installer1; /* 0x028 */
- + uint32_t unk5; /* 0x02c */
- + uint32_t unk6; /* 0x030 */
- + uint32_t run_installer2; /* 0x034 */
- + uint32_t rnd; /* 0x038 */
- + uint32_t unk7; /* 0x03c */
- + MACAddr mac_en0; /* 0x040 */
- + uint8_t pad1[2];
- + MACAddr mac_en1; /* 0x048 */
- + uint8_t pad2[2];
- + MACAddr mac_wifi0; /* 0x050 */
- + uint8_t pad3[2];
- + MACAddr mac_bt0; /* 0x058 */
- + uint8_t pad4[2];
- + uint8_t reserved[0xa0]; /* 0x060 */
- + uint32_t cpu_ids[0x80]; /* 0x100 */
- + uint8_t scratch[0x200]; /* 0x180 */
- + char serial[32]; /* 0x380 */
- + char unk8[32]; /* 0x3a0 */
- + char model[32]; /* 0x3c0 */
- + uint8_t unk9[32]; /* 0x3e0 */
- + uint32_t unk10; /* 0x400 */
- + char soc_name[32]; /* 0x404 */
- +} VMAppleCfg;
- +
- +#define TYPE_VMAPPLE_CFG "vmapple-cfg"
- +OBJECT_DECLARE_SIMPLE_TYPE(VMAppleCfgState, VMAPPLE_CFG)
- +
- +struct VMAppleCfgState {
- + /* <private> */
- + SysBusDevice parent_obj;
- + VMAppleCfg cfg;
- +
- + /* <public> */
- + MemoryRegion mem;
- + char *serial;
- + char *model;
- + char *soc_name;
- +};
- +
- +#define VMAPPLE_CFG_SIZE 0x00010000
- +
- +#endif /* HW_VMAPPLE_CFG_H */
- diff --git a/include/standard-headers/linux/virtio_blk.h b/include/standard-headers/linux/virtio_blk.h
- index d7be3cf5e4..1630262121 100644
- --- a/include/standard-headers/linux/virtio_blk.h
- +++ b/include/standard-headers/linux/virtio_blk.h
- @@ -204,6 +204,9 @@ struct virtio_blk_config {
- /* Reset All zones command */
- #define VIRTIO_BLK_T_ZONE_RESET_ALL 26
- +/* Write zeroes command */
- +#define VIRTIO_BLK_T_APPLE1 0x10000
- +
- #ifndef VIRTIO_BLK_NO_LEGACY
- /* Barrier before this op. */
- #define VIRTIO_BLK_T_BARRIER 0x80000000
- diff --git a/include/sysemu/hvf_int.h b/include/sysemu/hvf_int.h
- index 718beddcdd..ee8103bee4 100644
- --- a/include/sysemu/hvf_int.h
- +++ b/include/sysemu/hvf_int.h
- @@ -40,7 +40,7 @@ typedef struct hvf_vcpu_caps {
- struct HVFState {
- AccelState parent;
- - hvf_slot slots[32];
- + hvf_slot slots[512];
- int num_slots;
- hvf_vcpu_caps *hvf_caps;
- diff --git a/meson.build b/meson.build
- index 98e68ef0b1..d34310b5eb 100644
- --- a/meson.build
- +++ b/meson.build
- @@ -224,7 +224,9 @@ qemu_ldflags = []
- if targetos == 'darwin'
- # Disable attempts to use ObjectiveC features in os/object.h since they
- # won't work when we're compiling with gcc as a C compiler.
- - qemu_common_flags += '-DOS_OBJECT_USE_OBJC=0'
- + if compiler.get_id() == 'gcc'
- + qemu_common_flags += '-DOS_OBJECT_USE_OBJC=0'
- + endif
- elif targetos == 'solaris'
- # needed for CMSG_ macros in sys/socket.h
- qemu_common_flags += '-D_XOPEN_SOURCE=600'
- @@ -605,6 +607,8 @@ socket = []
- version_res = []
- coref = []
- iokit = []
- +pvg = []
- +metal = []
- emulator_link_args = []
- nvmm =not_found
- hvf = not_found
- @@ -628,6 +632,8 @@ elif targetos == 'darwin'
- coref = dependency('appleframeworks', modules: 'CoreFoundation')
- iokit = dependency('appleframeworks', modules: 'IOKit', required: false)
- host_dsosuf = '.dylib'
- + pvg = dependency('appleframeworks', modules: 'ParavirtualizedGraphics')
- + metal = dependency('appleframeworks', modules: 'Metal')
- elif targetos == 'sunos'
- socket = [cc.find_library('socket'),
- cc.find_library('nsl'),
- @@ -3280,6 +3286,7 @@ if have_system
- 'hw/usb',
- 'hw/vfio',
- 'hw/virtio',
- + 'hw/vmapple',
- 'hw/watchdog',
- 'hw/xen',
- 'hw/gpio',
- diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
- index 8fce64bbf6..13dec00f37 100644
- --- a/target/arm/hvf/hvf.c
- +++ b/target/arm/hvf/hvf.c
- @@ -179,6 +179,7 @@ void hvf_arm_init_debug(void)
- #define SYSREG_OSLSR_EL1 SYSREG(2, 0, 1, 1, 4)
- #define SYSREG_OSDLR_EL1 SYSREG(2, 0, 1, 3, 4)
- #define SYSREG_CNTPCT_EL0 SYSREG(3, 3, 14, 0, 1)
- +#define SYSREG_CNTP_CTL_EL0 SYSREG(3, 3, 14, 2, 1)
- #define SYSREG_PMCR_EL0 SYSREG(3, 3, 9, 12, 0)
- #define SYSREG_PMUSERENR_EL0 SYSREG(3, 3, 9, 14, 0)
- #define SYSREG_PMCNTENSET_EL0 SYSREG(3, 3, 9, 12, 1)
- @@ -1551,6 +1552,12 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
- case SYSREG_OSLAR_EL1:
- env->cp15.oslsr_el1 = val & 1;
- break;
- + case SYSREG_CNTP_CTL_EL0:
- + /*
- + * Guests should not rely on the physical counter, but macOS emits
- + * disable writes to it. Let it do so, but ignore the requests.
- + */
- + break;
- case SYSREG_OSDLR_EL1:
- /* Dummy register */
- break;
Add Comment
Please, Sign In to add comment