hw/display/apple-gfx: Adds PCI implementation

This change wires up the PCI variant of the paravirtualised
graphics device, mainly useful for x86-64 macOS guests, implemented
by macOS's ParavirtualizedGraphics.framework. It builds on code
shared with the vmapple/mmio variant of the PVG device.

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Message-ID: <20241223221645.29911-4-phil@philjordan.eu>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
This commit is contained in:
Phil Dennis-Jordan 2024-07-15 23:06:57 +02:00 committed by Philippe Mathieu-Daudé
parent 2352159c97
commit b21f17cce5
4 changed files with 157 additions and 0 deletions

View file

@ -149,3 +149,7 @@ config MAC_PVG_MMIO
bool
depends on MAC_PVG && AARCH64
config MAC_PVG_PCI
bool
depends on MAC_PVG && PCI
default y if PCI_DEVICES

151
hw/display/apple-gfx-pci.m Normal file
View file

@ -0,0 +1,151 @@
/*
* 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 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;
/* TODO: Property for setting mode list */
}
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)

View file

@ -14,6 +14,7 @@
#include "ui/surface.h"
#define TYPE_APPLE_GFX_MMIO "apple-gfx-mmio"
#define TYPE_APPLE_GFX_PCI "apple-gfx-pci"
@class PGDeviceDescriptor;
@protocol PGDevice;

View file

@ -63,6 +63,7 @@ system_ss.add(when: 'CONFIG_ATI_VGA', if_true: [files('ati.c', 'ati_2d.c', 'ati_
if host_os == 'darwin'
system_ss.add(when: 'CONFIG_MAC_PVG', if_true: [files('apple-gfx.m'), pvg, metal])
system_ss.add(when: 'CONFIG_MAC_PVG_PCI', if_true: [files('apple-gfx-pci.m'), pvg, metal])
if cpu == 'aarch64'
system_ss.add(when: 'CONFIG_MAC_PVG_MMIO', if_true: [files('apple-gfx-mmio.m'), pvg, metal])
endif