apple-gfx-pci.m 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /*
  2. * QEMU Apple ParavirtualizedGraphics.framework device, PCI variant
  3. *
  4. * Copyright © 2023-2024 Phil Dennis-Jordan
  5. *
  6. * SPDX-License-Identifier: GPL-2.0-or-later
  7. *
  8. * ParavirtualizedGraphics.framework is a set of libraries that macOS provides
  9. * which implements 3d graphics passthrough to the host as well as a
  10. * proprietary guest communication channel to drive it. This device model
  11. * implements support to drive that library from within QEMU as a PCI device
  12. * aimed primarily at x86-64 macOS VMs.
  13. */
  14. #include "qemu/osdep.h"
  15. #include "hw/pci/pci_device.h"
  16. #include "hw/pci/msi.h"
  17. #include "apple-gfx.h"
  18. #include "trace.h"
  19. #import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
  20. OBJECT_DECLARE_SIMPLE_TYPE(AppleGFXPCIState, APPLE_GFX_PCI)
  21. struct AppleGFXPCIState {
  22. PCIDevice parent_obj;
  23. AppleGFXState common;
  24. };
  25. static const char *apple_gfx_pci_option_rom_path = NULL;
  26. static void apple_gfx_init_option_rom_path(void)
  27. {
  28. NSURL *option_rom_url = PGCopyOptionROMURL();
  29. const char *option_rom_path = option_rom_url.fileSystemRepresentation;
  30. apple_gfx_pci_option_rom_path = g_strdup(option_rom_path);
  31. [option_rom_url release];
  32. }
  33. static void apple_gfx_pci_init(Object *obj)
  34. {
  35. AppleGFXPCIState *s = APPLE_GFX_PCI(obj);
  36. if (!apple_gfx_pci_option_rom_path) {
  37. /*
  38. * The following is done on device not class init to avoid running
  39. * ObjC code before fork() in -daemonize mode.
  40. */
  41. PCIDeviceClass *pci = PCI_DEVICE_CLASS(object_get_class(obj));
  42. apple_gfx_init_option_rom_path();
  43. pci->romfile = apple_gfx_pci_option_rom_path;
  44. }
  45. apple_gfx_common_init(obj, &s->common, TYPE_APPLE_GFX_PCI);
  46. }
  47. typedef struct AppleGFXPCIInterruptJob {
  48. PCIDevice *device;
  49. uint32_t vector;
  50. } AppleGFXPCIInterruptJob;
  51. static void apple_gfx_pci_raise_interrupt(void *opaque)
  52. {
  53. AppleGFXPCIInterruptJob *job = opaque;
  54. if (msi_enabled(job->device)) {
  55. msi_notify(job->device, job->vector);
  56. }
  57. g_free(job);
  58. }
  59. static void apple_gfx_pci_interrupt(PCIDevice *dev, uint32_t vector)
  60. {
  61. AppleGFXPCIInterruptJob *job;
  62. trace_apple_gfx_raise_irq(vector);
  63. job = g_malloc0(sizeof(*job));
  64. job->device = dev;
  65. job->vector = vector;
  66. aio_bh_schedule_oneshot(qemu_get_aio_context(),
  67. apple_gfx_pci_raise_interrupt, job);
  68. }
  69. static void apple_gfx_pci_realize(PCIDevice *dev, Error **errp)
  70. {
  71. AppleGFXPCIState *s = APPLE_GFX_PCI(dev);
  72. int ret;
  73. pci_register_bar(dev, PG_PCI_BAR_MMIO,
  74. PCI_BASE_ADDRESS_SPACE_MEMORY, &s->common.iomem_gfx);
  75. ret = msi_init(dev, 0x0 /* config offset; 0 = find space */,
  76. PG_PCI_MAX_MSI_VECTORS, true /* msi64bit */,
  77. false /* msi_per_vector_mask */, errp);
  78. if (ret != 0) {
  79. return;
  80. }
  81. @autoreleasepool {
  82. PGDeviceDescriptor *desc = [PGDeviceDescriptor new];
  83. desc.raiseInterrupt = ^(uint32_t vector) {
  84. apple_gfx_pci_interrupt(dev, vector);
  85. };
  86. apple_gfx_common_realize(&s->common, DEVICE(dev), desc, errp);
  87. [desc release];
  88. desc = nil;
  89. }
  90. }
  91. static void apple_gfx_pci_reset(Object *obj, ResetType type)
  92. {
  93. AppleGFXPCIState *s = APPLE_GFX_PCI(obj);
  94. [s->common.pgdev reset];
  95. }
  96. static const Property apple_gfx_pci_properties[] = {
  97. DEFINE_PROP_ARRAY("display-modes", AppleGFXPCIState,
  98. common.num_display_modes, common.display_modes,
  99. qdev_prop_apple_gfx_display_mode, AppleGFXDisplayMode),
  100. };
  101. static void apple_gfx_pci_class_init(ObjectClass *klass, void *data)
  102. {
  103. DeviceClass *dc = DEVICE_CLASS(klass);
  104. PCIDeviceClass *pci = PCI_DEVICE_CLASS(klass);
  105. ResettableClass *rc = RESETTABLE_CLASS(klass);
  106. rc->phases.hold = apple_gfx_pci_reset;
  107. dc->desc = "macOS Paravirtualized Graphics PCI Display Controller";
  108. dc->hotpluggable = false;
  109. set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
  110. pci->vendor_id = PG_PCI_VENDOR_ID;
  111. pci->device_id = PG_PCI_DEVICE_ID;
  112. pci->class_id = PCI_CLASS_DISPLAY_OTHER;
  113. pci->realize = apple_gfx_pci_realize;
  114. device_class_set_props(dc, apple_gfx_pci_properties);
  115. }
  116. static const TypeInfo apple_gfx_pci_types[] = {
  117. {
  118. .name = TYPE_APPLE_GFX_PCI,
  119. .parent = TYPE_PCI_DEVICE,
  120. .instance_size = sizeof(AppleGFXPCIState),
  121. .class_init = apple_gfx_pci_class_init,
  122. .instance_init = apple_gfx_pci_init,
  123. .interfaces = (InterfaceInfo[]) {
  124. { INTERFACE_PCIE_DEVICE },
  125. { },
  126. },
  127. }
  128. };
  129. DEFINE_TYPES(apple_gfx_pci_types)