123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- /*
- * QEMU Apple ParavirtualizedGraphics.framework device, PCI variant
- *
- * Copyright © 2023-2024 Phil Dennis-Jordan
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- *
- * 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 as a PCI device
- * aimed primarily at x86-64 macOS VMs.
- */
- #include "qemu/osdep.h"
- #include "hw/pci/pci_device.h"
- #include "hw/pci/msi.h"
- #include "apple-gfx.h"
- #include "trace.h"
- #import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
- OBJECT_DECLARE_SIMPLE_TYPE(AppleGFXPCIState, APPLE_GFX_PCI)
- struct AppleGFXPCIState {
- PCIDevice parent_obj;
- AppleGFXState common;
- };
- static const char *apple_gfx_pci_option_rom_path = NULL;
- static void apple_gfx_init_option_rom_path(void)
- {
- NSURL *option_rom_url = PGCopyOptionROMURL();
- const char *option_rom_path = option_rom_url.fileSystemRepresentation;
- apple_gfx_pci_option_rom_path = g_strdup(option_rom_path);
- [option_rom_url release];
- }
- static void apple_gfx_pci_init(Object *obj)
- {
- AppleGFXPCIState *s = APPLE_GFX_PCI(obj);
- if (!apple_gfx_pci_option_rom_path) {
- /*
- * The following is done on device not class init to avoid running
- * ObjC code before fork() in -daemonize mode.
- */
- PCIDeviceClass *pci = PCI_DEVICE_CLASS(object_get_class(obj));
- apple_gfx_init_option_rom_path();
- pci->romfile = apple_gfx_pci_option_rom_path;
- }
- apple_gfx_common_init(obj, &s->common, TYPE_APPLE_GFX_PCI);
- }
- typedef struct AppleGFXPCIInterruptJob {
- PCIDevice *device;
- uint32_t vector;
- } AppleGFXPCIInterruptJob;
- static void apple_gfx_pci_raise_interrupt(void *opaque)
- {
- AppleGFXPCIInterruptJob *job = opaque;
- if (msi_enabled(job->device)) {
- msi_notify(job->device, job->vector);
- }
- g_free(job);
- }
- static void apple_gfx_pci_interrupt(PCIDevice *dev, uint32_t vector)
- {
- AppleGFXPCIInterruptJob *job;
- trace_apple_gfx_raise_irq(vector);
- job = g_malloc0(sizeof(*job));
- job->device = dev;
- job->vector = vector;
- aio_bh_schedule_oneshot(qemu_get_aio_context(),
- apple_gfx_pci_raise_interrupt, job);
- }
- static void apple_gfx_pci_realize(PCIDevice *dev, Error **errp)
- {
- AppleGFXPCIState *s = APPLE_GFX_PCI(dev);
- int ret;
- pci_register_bar(dev, PG_PCI_BAR_MMIO,
- PCI_BASE_ADDRESS_SPACE_MEMORY, &s->common.iomem_gfx);
- ret = msi_init(dev, 0x0 /* config offset; 0 = find space */,
- PG_PCI_MAX_MSI_VECTORS, true /* msi64bit */,
- false /* msi_per_vector_mask */, errp);
- if (ret != 0) {
- return;
- }
- @autoreleasepool {
- PGDeviceDescriptor *desc = [PGDeviceDescriptor new];
- desc.raiseInterrupt = ^(uint32_t vector) {
- apple_gfx_pci_interrupt(dev, vector);
- };
- apple_gfx_common_realize(&s->common, DEVICE(dev), desc, errp);
- [desc release];
- desc = nil;
- }
- }
- static void apple_gfx_pci_reset(Object *obj, ResetType type)
- {
- AppleGFXPCIState *s = APPLE_GFX_PCI(obj);
- [s->common.pgdev reset];
- }
- static const Property apple_gfx_pci_properties[] = {
- DEFINE_PROP_ARRAY("display-modes", AppleGFXPCIState,
- common.num_display_modes, common.display_modes,
- qdev_prop_apple_gfx_display_mode, AppleGFXDisplayMode),
- };
- static void apple_gfx_pci_class_init(ObjectClass *klass, void *data)
- {
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *pci = PCI_DEVICE_CLASS(klass);
- ResettableClass *rc = RESETTABLE_CLASS(klass);
- rc->phases.hold = apple_gfx_pci_reset;
- dc->desc = "macOS Paravirtualized Graphics PCI Display Controller";
- dc->hotpluggable = false;
- set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
- pci->vendor_id = PG_PCI_VENDOR_ID;
- pci->device_id = PG_PCI_DEVICE_ID;
- pci->class_id = PCI_CLASS_DISPLAY_OTHER;
- pci->realize = apple_gfx_pci_realize;
- device_class_set_props(dc, apple_gfx_pci_properties);
- }
- static const TypeInfo apple_gfx_pci_types[] = {
- {
- .name = TYPE_APPLE_GFX_PCI,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(AppleGFXPCIState),
- .class_init = apple_gfx_pci_class_init,
- .instance_init = apple_gfx_pci_init,
- .interfaces = (InterfaceInfo[]) {
- { INTERFACE_PCIE_DEVICE },
- { },
- },
- }
- };
- DEFINE_TYPES(apple_gfx_pci_types)
|