From: "Scott J. Goldman" <scottjgo@gmail.com>
To: qemu-devel@nongnu.org
Cc: alex@shazbot.org, clg@redhat.com, pbonzini@redhat.com,
rbolshakov@ddn.com, phil@philjordan.eu, mst@redhat.com,
john.levon@nutanix.com, thanos.makatos@nutanix.com,
qemu-s390x@nongnu.org, "Scott J. Goldman" <scottjg@umich.edu>,
"Scott J. Goldman" <scottjgo@gmail.com>
Subject: [RFC PATCH 08/10] vfio/apple: Add IOMMU container and PCI device
Date: Sun, 5 Apr 2026 00:28:52 -0700 [thread overview]
Message-ID: <20260405072857.66484-9-scottjgo@gmail.com> (raw)
In-Reply-To: <20260405072857.66484-1-scottjgo@gmail.com>
From: "Scott J. Goldman" <scottjg@umich.edu>
Add the core Apple VFIO backend: an IOMMU container type and a PCI
device type that together provide VFIO passthrough on macOS via the
VFIOUserPCIDriver DriverKit extension.
AppleVFIOContainer (container-apple.c):
Implements VFIOIOMMUClass for DMA map/unmap by calling through to the
dext client's register/unregister_dma functions. Synthesizes
VFIO_DEVICE_GET_INFO responses with appropriate flags for the
passthrough device.
VFIOApplePCIDevice (apple-device.c):
QOM type "vfio-apple-pci" subclassing VFIOPCIDevice. Provides the
full VFIODeviceIOOps implementation:
- Config space reads forwarded to the dext; writes filtered to block
BAR and status register reprogramming (macOS/DART owns those).
- PCI COMMAND register writes forwarded for bus-master/memory-space
enable.
- BAR regions directly mapped via IOConnectMapMemory64 and accessed
as host MMIO loads/stores.
- MSI/MSI-X interrupt delivery through a bitmap-poll model with
async GCD notification bridged to an EventNotifier.
- Device reset via the dext (IOPCIDevice::Reset FLR/hot-reset).
- Shared dext connection management for multi-function devices.
apple.h defines the shared types: AppleVFIOContainer, AppleVFIOState,
AppleVFIOBarMap, and VFIOApplePCIDevice.
Signed-off-by: Scott J. Goldman <scottjgo@gmail.com>
---
hw/vfio/apple-device.c | 945 ++++++++++++++++++++++++++++++++++++++
hw/vfio/apple.h | 74 +++
hw/vfio/container-apple.c | 241 ++++++++++
hw/vfio/meson.build | 6 +-
4 files changed, 1264 insertions(+), 2 deletions(-)
create mode 100644 hw/vfio/apple-device.c
create mode 100644 hw/vfio/apple.h
create mode 100644 hw/vfio/container-apple.c
diff --git a/hw/vfio/apple-device.c b/hw/vfio/apple-device.c
new file mode 100644
index 0000000000..9291ac845b
--- /dev/null
+++ b/hw/vfio/apple-device.c
@@ -0,0 +1,945 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Apple/macOS VFIO PCI device passthrough via DriverKit dext.
+ *
+ * Copyright (c) 2026 Scott J. Goldman
+ */
+
+#include "qemu/osdep.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/vfio.h>
+
+#include "apple-dext-client.h"
+#include "hw/vfio/apple.h"
+#include "hw/vfio/vfio-container.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/host-pci-mmio.h"
+#include "qemu/main-loop.h"
+
+typedef struct AppleVFIOSharedDext {
+ io_connect_t conn;
+ uint32_t refs;
+} AppleVFIOSharedDext;
+
+typedef struct AppleVFIODMAProbe {
+ uint64_t managed_bdf;
+ uint64_t host_bus;
+ uint64_t host_device;
+ uint64_t host_function;
+ DeviceState *match;
+} AppleVFIODMAProbe;
+
+static GHashTable *apple_vfio_shared_dexts;
+
+static inline guint apple_vfio_dext_key(uint8_t bus, uint8_t device,
+ uint8_t function)
+{
+ return ((guint)bus << 16) | ((guint)device << 8) | function;
+}
+
+static inline AppleVFIOContainer *apple_vfio_container(VFIODevice *vbasedev)
+{
+ return VFIO_IOMMU_APPLE(vbasedev->bcontainer);
+}
+
+static inline io_connect_t apple_vfio_connection(VFIODevice *vbasedev)
+{
+ AppleVFIOContainer *container = apple_vfio_container(vbasedev);
+
+ return container ? container->dext_conn : IO_OBJECT_NULL;
+}
+
+static void apple_vfio_find_dma_companion_cb(PCIBus *bus, PCIDevice *pdev,
+ void *opaque)
+{
+ AppleVFIODMAProbe *probe = opaque;
+ Error *err = NULL;
+ uint64_t managed_bdf;
+ uint64_t host_bus;
+ uint64_t host_device;
+ uint64_t host_function;
+
+ if (probe->match ||
+ !object_dynamic_cast(OBJECT(pdev), "apple-dma-pci")) {
+ return;
+ }
+
+ managed_bdf = object_property_get_uint(OBJECT(pdev), "managed-bdf", &err);
+ if (err) {
+ error_free(err);
+ return;
+ }
+
+ host_bus = object_property_get_uint(OBJECT(pdev), "x-apple-host-bus", &err);
+ if (err) {
+ error_free(err);
+ return;
+ }
+
+ host_device = object_property_get_uint(OBJECT(pdev),
+ "x-apple-host-device", &err);
+ if (err) {
+ error_free(err);
+ return;
+ }
+
+ host_function = object_property_get_uint(OBJECT(pdev),
+ "x-apple-host-function", &err);
+ if (err) {
+ error_free(err);
+ return;
+ }
+
+ if (managed_bdf == probe->managed_bdf &&
+ host_bus == probe->host_bus &&
+ host_device == probe->host_device &&
+ host_function == probe->host_function) {
+ probe->match = DEVICE(pdev);
+ }
+}
+
+static DeviceState *apple_vfio_find_dma_companion(VFIOApplePCIDevice *adev)
+{
+ VFIOPCIDevice *vdev = VFIO_PCI_DEVICE(adev);
+ PCIDevice *pdev = PCI_DEVICE(vdev);
+ AppleVFIODMAProbe probe = {
+ .managed_bdf = PCI_BUILD_BDF(pci_dev_bus_num(pdev), pdev->devfn),
+ .host_bus = vdev->host.bus,
+ .host_device = vdev->host.slot,
+ .host_function = vdev->host.function,
+ };
+
+ pci_for_each_device_under_bus(pci_device_root_bus(pdev),
+ apple_vfio_find_dma_companion_cb, &probe);
+ return probe.match;
+}
+
+static void apple_vfio_signal_irqfd(int fd)
+{
+ static const uint64_t value = 1;
+ ssize_t ret;
+
+ if (fd < 0) {
+ return;
+ }
+
+ do {
+ ret = write(fd, &value, sizeof(value));
+ } while (ret < 0 && errno == EINTR);
+}
+
+static void apple_vfio_deliver_irq(VFIOPCIDevice *vdev, uint32_t vector)
+{
+ switch (vdev->interrupt) {
+ case VFIO_INT_MSI:
+ case VFIO_INT_MSIX:
+ if (vector < vdev->nr_vectors && vdev->msi_vectors[vector].use) {
+ apple_vfio_signal_irqfd(
+ event_notifier_get_wfd(&vdev->msi_vectors[vector].interrupt));
+ }
+ break;
+ case VFIO_INT_INTx:
+ apple_vfio_signal_irqfd(
+ event_notifier_get_wfd(&vdev->intx.interrupt));
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * Called on a GCD dispatch queue when the dext signals pending interrupts.
+ * Just pokes the EventNotifier to wake the QEMU main loop.
+ */
+static void apple_vfio_irq_wakeup(void *opaque)
+{
+ VFIOApplePCIDevice *adev = opaque;
+
+ event_notifier_set(&adev->apple->irq_notifier);
+}
+
+/*
+ * QEMU main-loop fd handler: drain the pending-interrupt bitfield from
+ * the dext, deliver each flagged vector, then re-arm the async wait.
+ */
+static void apple_vfio_irq_handler(void *opaque)
+{
+ VFIOApplePCIDevice *adev = opaque;
+ VFIOPCIDevice *vdev = VFIO_PCI_DEVICE(adev);
+ VFIODevice *vbasedev = &vdev->vbasedev;
+ io_connect_t conn = apple_vfio_connection(vbasedev);
+ AppleVFIOState *apple = adev->apple;
+ uint64_t pending[4];
+ int word;
+
+ if (!event_notifier_test_and_clear(&apple->irq_notifier)) {
+ return;
+ }
+
+ if (conn == IO_OBJECT_NULL) {
+ return;
+ }
+
+ if (apple_dext_read_pending_irqs(conn, pending) != KERN_SUCCESS) {
+ apple_dext_interrupt_notify_rearm(apple->irq_notify);
+ return;
+ }
+
+ for (word = 0; word < 4; word++) {
+ uint64_t bits = pending[word];
+
+ while (bits) {
+ int bit = __builtin_ctzll(bits);
+ uint32_t vector = word * 64 + bit;
+
+ apple_vfio_deliver_irq(vdev, vector);
+ bits &= bits - 1;
+ }
+ }
+
+ apple_dext_interrupt_notify_rearm(apple->irq_notify);
+}
+
+bool apple_vfio_get_bar_info(VFIOApplePCIDevice *adev, uint8_t bar,
+ uint8_t *mem_idx, uint64_t *size,
+ uint8_t *type)
+{
+ io_connect_t conn = apple_vfio_connection(&VFIO_PCI_DEVICE(adev)->vbasedev);
+
+ if (conn != IO_OBJECT_NULL) {
+ return apple_dext_get_bar_info(conn, bar, mem_idx, size, type) ==
+ KERN_SUCCESS;
+ }
+
+ if (mem_idx) {
+ *mem_idx = 0;
+ }
+ if (size) {
+ *size = 0;
+ }
+ if (type) {
+ *type = 0;
+ }
+ return false;
+}
+
+static void apple_vfio_pci_init(VFIOApplePCIDevice *adev)
+{
+ VFIOPCIDevice *vdev = VFIO_PCI_DEVICE(adev);
+
+ /*
+ * On macOS, HVF can only map on 16kb page boundaries, so these quirk
+ * fixes end up breaking things. Likewise the performance enhancements
+ * there rely on kvm-specific features. Disable for now, but we should
+ * revisit this.
+ */
+ vdev->no_bar_quirks = true;
+}
+
+static bool apple_vfio_pci_pre_realize(VFIOApplePCIDevice *adev, Error **errp)
+{
+ VFIOPCIDevice *vdev = VFIO_PCI_DEVICE(adev);
+ VFIODevice *vbasedev = &vdev->vbasedev;
+
+ adev->apple = g_new0(AppleVFIOState, 1);
+
+ if (!vbasedev->name) {
+ vbasedev->name = g_strdup_printf("apple-%04x:%02x:%02x.%x",
+ vdev->host.domain,
+ vdev->host.bus,
+ vdev->host.slot,
+ vdev->host.function);
+ }
+
+ return true;
+}
+
+static bool apple_vfio_create_dma_companion(VFIOApplePCIDevice *adev,
+ Error **errp)
+{
+ VFIOPCIDevice *vdev = VFIO_PCI_DEVICE(adev);
+ PCIDevice *pdev = PCI_DEVICE(vdev);
+ DeviceState *dev;
+
+ if (adev->dma_companion_autocreated && adev->dma_companion) {
+ return true;
+ }
+
+ if (apple_vfio_find_dma_companion(adev) != NULL) {
+ return true;
+ }
+
+ dev = qdev_new("apple-dma-pci");
+ if (!object_property_set_uint(OBJECT(dev), "managed-bdf",
+ PCI_BUILD_BDF(pci_dev_bus_num(pdev),
+ pdev->devfn), errp) ||
+ !object_property_set_uint(OBJECT(dev), "x-apple-host-bus",
+ vdev->host.bus, errp) ||
+ !object_property_set_uint(OBJECT(dev), "x-apple-host-device",
+ vdev->host.slot, errp) ||
+ !object_property_set_uint(OBJECT(dev), "x-apple-host-function",
+ vdev->host.function, errp)) {
+ object_unref(OBJECT(dev));
+ return false;
+ }
+
+ if (!qdev_realize(dev, BUS(pci_get_bus(pdev)), errp)) {
+ object_unref(OBJECT(dev));
+ return false;
+ }
+
+ adev->dma_companion = dev;
+ adev->dma_companion_autocreated = true;
+ object_unref(OBJECT(dev));
+ return true;
+}
+
+static void apple_vfio_destroy_dma_companion(VFIOApplePCIDevice *adev)
+{
+ if (!adev->dma_companion_autocreated || adev->dma_companion == NULL) {
+ return;
+ }
+
+ object_unparent(OBJECT(adev->dma_companion));
+ adev->dma_companion = NULL;
+ adev->dma_companion_autocreated = false;
+}
+
+bool apple_vfio_device_setup(VFIOApplePCIDevice *adev, Error **errp)
+{
+ VFIODevice *vbasedev = &VFIO_PCI_DEVICE(adev)->vbasedev;
+ io_connect_t conn = apple_vfio_connection(vbasedev);
+ uint32_t num_vectors = 0;
+ kern_return_t kr;
+
+ if (conn == IO_OBJECT_NULL) {
+ error_setg(errp, "vfio-apple: missing dext connection");
+ return false;
+ }
+
+ kr = apple_dext_setup_interrupts(conn, &num_vectors);
+ if (kr != KERN_SUCCESS) {
+ error_setg(errp, "vfio-apple: failed to setup interrupts (kr=0x%x)",
+ kr);
+ return false;
+ }
+
+ adev->apple->num_irq_vectors = num_vectors;
+
+ if (event_notifier_init(&adev->apple->irq_notifier, false) < 0) {
+ error_setg(errp, "vfio-apple: failed to create IRQ event notifier");
+ return false;
+ }
+
+ qemu_set_fd_handler(event_notifier_get_fd(&adev->apple->irq_notifier),
+ apple_vfio_irq_handler, NULL, adev);
+
+ adev->apple->irq_notify =
+ apple_dext_interrupt_notify_create(conn, apple_vfio_irq_wakeup, adev);
+ if (!adev->apple->irq_notify) {
+ error_setg(errp,
+ "vfio-apple: failed to create IRQ async notification");
+ qemu_set_fd_handler(
+ event_notifier_get_fd(&adev->apple->irq_notifier),
+ NULL, NULL, NULL);
+ event_notifier_cleanup(&adev->apple->irq_notifier);
+ return false;
+ }
+
+ return true;
+}
+
+void apple_vfio_device_cleanup(VFIOApplePCIDevice *adev)
+{
+ AppleVFIOState *apple = adev->apple;
+
+ if (!apple) {
+ return;
+ }
+
+ if (apple->irq_notify) {
+ apple_dext_interrupt_notify_destroy(apple->irq_notify);
+ apple->irq_notify = NULL;
+
+ qemu_set_fd_handler(event_notifier_get_fd(&apple->irq_notifier),
+ NULL, NULL, NULL);
+ event_notifier_cleanup(&apple->irq_notifier);
+ }
+}
+
+static int apple_vfio_device_feature(VFIODevice *vdev,
+ struct vfio_device_feature *feat)
+{
+ return -ENOTTY;
+}
+
+static int apple_vfio_device_reset(VFIODevice *vbasedev)
+{
+ io_connect_t conn = apple_vfio_connection(vbasedev);
+
+ if (conn == IO_OBJECT_NULL) {
+ return -ENODEV;
+ }
+
+ return apple_dext_reset_device(conn) == KERN_SUCCESS ? 0 : -EIO;
+}
+
+static int apple_vfio_get_region_info(VFIODevice *vbasedev,
+ struct vfio_region_info *info,
+ int *fd)
+{
+ VFIOApplePCIDevice *adev = VFIO_APPLE_PCI(vbasedev->dev);
+ uint32_t index = info->index;
+ uint64_t size = 0;
+
+ if (fd) {
+ *fd = -1;
+ }
+
+ memset((char *)info + offsetof(struct vfio_region_info, flags), 0,
+ sizeof(*info) - offsetof(struct vfio_region_info, flags));
+
+ info->index = index;
+ info->flags = VFIO_REGION_INFO_FLAG_READ | VFIO_REGION_INFO_FLAG_WRITE;
+ info->offset = (uint64_t)index << 20;
+
+ switch (info->index) {
+ case VFIO_PCI_BAR0_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX:
+ if (!apple_vfio_get_bar_info(adev, info->index, NULL, &size, NULL)) {
+ size = 0;
+ }
+ info->size = size;
+ info->flags |= VFIO_REGION_INFO_FLAG_MMAP;
+ break;
+ case VFIO_PCI_CONFIG_REGION_INDEX:
+ info->size = PCIE_CONFIG_SPACE_SIZE;
+ break;
+ case VFIO_PCI_ROM_REGION_INDEX:
+ case VFIO_PCI_VGA_REGION_INDEX:
+ info->size = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int apple_vfio_get_irq_info(VFIODevice *vbasedev,
+ struct vfio_irq_info *info)
+{
+ VFIOApplePCIDevice *adev = VFIO_APPLE_PCI(vbasedev->dev);
+ VFIOPCIDevice *vdev = VFIO_PCI_DEVICE(adev);
+
+ switch (info->index) {
+ case VFIO_PCI_MSI_IRQ_INDEX:
+ info->flags = VFIO_IRQ_INFO_EVENTFD;
+ info->count = adev->apple->num_irq_vectors;
+ break;
+ case VFIO_PCI_MSIX_IRQ_INDEX:
+ info->flags = VFIO_IRQ_INFO_EVENTFD | VFIO_IRQ_INFO_NORESIZE;
+ info->count = vdev->msix ? vdev->msix->entries : 0;
+ break;
+ case VFIO_PCI_INTX_IRQ_INDEX:
+ info->flags = VFIO_IRQ_INFO_EVENTFD;
+ info->count = 1;
+ break;
+ case VFIO_PCI_ERR_IRQ_INDEX:
+ case VFIO_PCI_REQ_IRQ_INDEX:
+ /*
+ * Apple dext passthrough has no kernel-side AER or device-request
+ * notification currently; return count 0 to tell the core to skip
+ * these.
+ */
+ info->flags = 0;
+ info->count = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void apple_vfio_update_irq_mask(VFIODevice *vbasedev)
+{
+ VFIOApplePCIDevice *adev = VFIO_APPLE_PCI(vbasedev->dev);
+ VFIOPCIDevice *vdev = VFIO_PCI_DEVICE(adev);
+ io_connect_t conn = apple_vfio_connection(vbasedev);
+ uint64_t mask[4] = {0};
+ uint32_t i;
+
+ if (conn == IO_OBJECT_NULL) {
+ return;
+ }
+
+ switch (vdev->interrupt) {
+ case VFIO_INT_MSI:
+ case VFIO_INT_MSIX:
+ for (i = 0; i < vdev->nr_vectors; i++) {
+ if (vdev->msi_vectors[i].use) {
+ mask[i / 64] |= 1ULL << (i % 64);
+ }
+ }
+ break;
+ case VFIO_INT_INTx:
+ mask[0] = 1;
+ break;
+ default:
+ break;
+ }
+
+ apple_dext_set_irq_mask(conn, mask);
+}
+
+static int apple_vfio_set_irqs(VFIODevice *vbasedev, struct vfio_irq_set *irq)
+{
+ apple_vfio_update_irq_mask(vbasedev);
+ return 0;
+}
+
+static int apple_vfio_bar_read(VFIODevice *vbasedev, uint8_t nr, off_t off,
+ uint32_t size, void *data)
+{
+ VFIOApplePCIDevice *adev = VFIO_APPLE_PCI(vbasedev->dev);
+ AppleVFIOBarMap *bm = &adev->apple->bar_maps[nr];
+ const void *p;
+ uint64_t value;
+
+ if (!bm->addr || off + size > bm->size) {
+ error_report("vfio-apple: BAR%d read out of range or unmapped", nr);
+ return -EINVAL;
+ }
+
+ if (size != 1 && size != 2 && size != 4 && size != 8) {
+ return -EINVAL;
+ }
+
+ p = (const char *)bm->addr + off;
+ value = host_pci_ldn_le_p(p, size);
+ memcpy(data, &value, size);
+
+ return size;
+}
+
+static int apple_vfio_region_read(VFIODevice *vbasedev, uint8_t nr, off_t off,
+ uint32_t size, void *data)
+{
+ io_connect_t conn = apple_vfio_connection(vbasedev);
+ kern_return_t kr;
+ uint32_t legacy_size = 0;
+
+ if (nr != VFIO_PCI_CONFIG_REGION_INDEX) {
+ return apple_vfio_bar_read(vbasedev, nr, off, size, data);
+ }
+
+ if (conn == IO_OBJECT_NULL) {
+ return -ENODEV;
+ }
+
+ legacy_size = MIN(size, PCIE_CONFIG_SPACE_SIZE - off);
+
+ if (legacy_size == 1 || legacy_size == 2 || legacy_size == 4) {
+ uint64_t value = 0;
+
+ kr = apple_dext_config_read(conn, off, legacy_size, &value);
+ if (kr != KERN_SUCCESS) {
+ return -EIO;
+ }
+
+ memcpy(data, &value, legacy_size);
+ if (legacy_size < size) {
+ memset((uint8_t *)data + legacy_size, 0, size - legacy_size);
+ }
+ return size;
+ }
+
+ kr = apple_dext_config_read_block(conn, off, data, legacy_size);
+ if (kr != KERN_SUCCESS) {
+ return -EIO;
+ }
+ if (legacy_size < size) {
+ memset((uint8_t *)data + legacy_size, 0, size - legacy_size);
+ }
+ return size;
+}
+
+static bool apple_vfio_config_write_is_safe(off_t off, uint32_t size)
+{
+ off_t end = off + size;
+
+ /*
+ * Block writes that would reprogram the device's bus identity or
+ * address decoders. macOS / DART owns those registers; touching
+ * them from the guest breaks the IOKit mapping and the device
+ * "falls off the bus."
+ *
+ * Everything else (vendor capabilities, MSI/MSI-X, PCIe cap, etc.)
+ * is forwarded.
+ */
+
+ /* PCI_STATUS stays emulated/blocked */
+ if (off < PCI_STATUS + 2 && end > PCI_STATUS) {
+ return false;
+ }
+
+ /* BAR0-BAR5 */
+ if (off < PCI_BASE_ADDRESS_5 + 4 && end > PCI_BASE_ADDRESS_0) {
+ return false;
+ }
+
+ return true;
+}
+
+static int apple_vfio_forward_command_write(io_connect_t conn, off_t off,
+ uint32_t size, const void *data)
+{
+ const uint8_t *bytes = data;
+ off_t end = off + size;
+ off_t cmd_start = MAX(off, (off_t)PCI_COMMAND);
+ off_t cmd_end = MIN(end, (off_t)(PCI_COMMAND + 2));
+ off_t pos;
+
+ if (conn == IO_OBJECT_NULL) {
+ return -ENODEV;
+ }
+
+ for (pos = cmd_start; pos < cmd_end; pos++) {
+ uint64_t value = bytes[pos - off];
+ kern_return_t kr = apple_dext_config_write(conn, pos, 1, value);
+
+ if (kr != KERN_SUCCESS) {
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static int apple_vfio_bar_write(VFIODevice *vbasedev, uint8_t nr, off_t off,
+ uint32_t size, void *data)
+{
+ VFIOApplePCIDevice *adev = VFIO_APPLE_PCI(vbasedev->dev);
+ AppleVFIOBarMap *bm = &adev->apple->bar_maps[nr];
+ void *p;
+ uint64_t value = 0;
+
+ if (!bm->addr || off + size > bm->size) {
+ error_report("vfio-apple: BAR%d write out of range or unmapped", nr);
+ return -EINVAL;
+ }
+
+ if (size != 1 && size != 2 && size != 4 && size != 8) {
+ return -EINVAL;
+ }
+
+ p = (char *)bm->addr + off;
+ memcpy(&value, data, size);
+ host_pci_stn_le_p(p, size, value);
+
+ return size;
+}
+
+static int apple_vfio_region_write(VFIODevice *vbasedev, uint8_t nr, off_t off,
+ uint32_t size, void *data, bool post)
+{
+ io_connect_t conn = apple_vfio_connection(vbasedev);
+ uint64_t value = 0;
+ kern_return_t kr;
+ uint32_t legacy_size;
+
+ if (nr != VFIO_PCI_CONFIG_REGION_INDEX) {
+ return apple_vfio_bar_write(vbasedev, nr, off, size, data);
+ }
+
+ if (off < PCI_COMMAND + 2 && off + size > PCI_COMMAND) {
+ int ret = apple_vfio_forward_command_write(conn, off, size, data);
+
+ if (ret) {
+ return ret;
+ }
+
+ if (off >= PCI_COMMAND && off + size <= PCI_COMMAND + 2) {
+ return size;
+ }
+ }
+
+ if (!apple_vfio_config_write_is_safe(off, size)) {
+ return size;
+ }
+
+ if (conn == IO_OBJECT_NULL) {
+ return -ENODEV;
+ }
+
+ memcpy(&value, data, size);
+ legacy_size = MIN(size, PCIE_CONFIG_SPACE_SIZE - off);
+ if (!(legacy_size == 1 || legacy_size == 2 || legacy_size == 4)) {
+ return -EINVAL;
+ }
+
+ kr = apple_dext_config_write(conn, off, legacy_size, value);
+ if (kr != KERN_SUCCESS) {
+ return -EIO;
+ }
+ return size;
+}
+
+static int apple_vfio_region_map(VFIODevice *vbasedev, VFIORegion *region);
+static void apple_vfio_region_unmap(VFIODevice *vbasedev, VFIORegion *region);
+
+static int apple_vfio_region_map(VFIODevice *vbasedev, VFIORegion *region)
+{
+ VFIOApplePCIDevice *adev = VFIO_APPLE_PCI(vbasedev->dev);
+ VFIOPCIDevice *vdev = VFIO_PCI_DEVICE(adev);
+ io_connect_t conn = apple_vfio_connection(vbasedev);
+ int bar = region->nr;
+ VFIOBAR *vbar;
+ mach_vm_address_t local_addr = 0;
+ mach_vm_size_t bar_size = 0;
+ uint8_t bar_type = 0;
+ kern_return_t kr;
+ int i;
+
+ if (bar < VFIO_PCI_BAR0_REGION_INDEX || bar >= VFIO_PCI_ROM_REGION_INDEX) {
+ return 0;
+ }
+
+ vbar = &vdev->bars[bar];
+
+ if (conn == IO_OBJECT_NULL || !vbar->size || vbar->ioport) {
+ return 0;
+ }
+
+ if (bar > 0 && vdev->bars[bar - 1].mem64) {
+ return 0;
+ }
+
+ if (adev->apple->bar_maps[bar].addr != NULL) {
+ return 0;
+ }
+
+ kr = apple_dext_map_bar(conn, bar, &local_addr, &bar_size, &bar_type);
+ if (kr != KERN_SUCCESS) {
+ warn_report("vfio-apple: BAR%d map failed for %s: 0x%x",
+ bar, vbasedev->name, kr);
+ return -EIO;
+ }
+
+ if (bar_size > vbar->size) {
+ bar_size = vbar->size;
+ }
+
+ adev->apple->bar_maps[bar].addr = (void *)local_addr;
+ adev->apple->bar_maps[bar].size = bar_size;
+
+ /*
+ * Use the pre-computed mmap regions — already split around the MSI-X
+ * table/PBA hole by vfio_pci_fixup_msix_region() during realize.
+ * We just need to fill in the host pointers from our dext mapping.
+ */
+ for (i = 0; i < region->nr_mmaps; i++) {
+ region->mmaps[i].mmap = (char *)local_addr + region->mmaps[i].offset;
+ vfio_region_register_mmap(region, i);
+ }
+
+ return 0;
+}
+
+static void apple_vfio_region_unmap(VFIODevice *vbasedev, VFIORegion *region)
+{
+ VFIOApplePCIDevice *adev = VFIO_APPLE_PCI(vbasedev->dev);
+ io_connect_t conn = apple_vfio_connection(vbasedev);
+ int bar = region->nr;
+ AppleVFIOBarMap *bm;
+ int i;
+
+ if (bar < VFIO_PCI_BAR0_REGION_INDEX || bar >= VFIO_PCI_ROM_REGION_INDEX) {
+ return;
+ }
+
+ bm = &adev->apple->bar_maps[bar];
+
+ for (i = 0; i < region->nr_mmaps; i++) {
+ if (region->mmaps[i].mmap) {
+ vfio_region_unregister_mmap(region, i);
+ region->mmaps[i].mmap = NULL;
+ }
+ }
+
+ if (conn != IO_OBJECT_NULL && bm->addr != NULL) {
+ apple_dext_unmap_bar(conn, bar, (mach_vm_address_t)bm->addr);
+ }
+
+ bm->addr = NULL;
+ bm->size = 0;
+}
+
+VFIODeviceIOOps apple_vfio_device_io_ops = {
+ .device_feature = apple_vfio_device_feature,
+ .get_region_info = apple_vfio_get_region_info,
+ .get_irq_info = apple_vfio_get_irq_info,
+ .set_irqs = apple_vfio_set_irqs,
+ .device_reset = apple_vfio_device_reset,
+ .region_read = apple_vfio_region_read,
+ .region_write = apple_vfio_region_write,
+ .region_map = apple_vfio_region_map,
+ .region_unmap = apple_vfio_region_unmap,
+};
+
+bool apple_vfio_dext_publish(uint8_t bus, uint8_t device, uint8_t function,
+ io_connect_t conn)
+{
+ AppleVFIOSharedDext *shared;
+ guint key = apple_vfio_dext_key(bus, device, function);
+
+ if (!apple_vfio_shared_dexts) {
+ apple_vfio_shared_dexts =
+ g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
+ }
+
+ if (g_hash_table_lookup(apple_vfio_shared_dexts, GUINT_TO_POINTER(key))) {
+ return false;
+ }
+
+ shared = g_new0(AppleVFIOSharedDext, 1);
+ shared->conn = conn;
+ shared->refs = 1;
+ g_hash_table_insert(apple_vfio_shared_dexts, GUINT_TO_POINTER(key), shared);
+ return true;
+}
+
+io_connect_t apple_vfio_dext_lookup(uint8_t bus, uint8_t device,
+ uint8_t function)
+{
+ AppleVFIOSharedDext *shared;
+ guint key = apple_vfio_dext_key(bus, device, function);
+
+ if (!apple_vfio_shared_dexts) {
+ return IO_OBJECT_NULL;
+ }
+
+ shared = g_hash_table_lookup(apple_vfio_shared_dexts,
+ GUINT_TO_POINTER(key));
+ if (!shared) {
+ return IO_OBJECT_NULL;
+ }
+
+ shared->refs++;
+ return shared->conn;
+}
+
+void apple_vfio_dext_release(uint8_t bus, uint8_t device, uint8_t function,
+ io_connect_t conn)
+{
+ AppleVFIOSharedDext *shared;
+ guint key = apple_vfio_dext_key(bus, device, function);
+
+ if (!apple_vfio_shared_dexts) {
+ return;
+ }
+
+ shared = g_hash_table_lookup(apple_vfio_shared_dexts,
+ GUINT_TO_POINTER(key));
+ if (!shared || shared->conn != conn) {
+ return;
+ }
+
+ if (--shared->refs == 0) {
+ apple_dext_disconnect(conn);
+ g_hash_table_remove(apple_vfio_shared_dexts, GUINT_TO_POINTER(key));
+ }
+}
+
+/* ------------------------------------------------------------------ */
+/* QOM type: vfio-apple-pci */
+/* ------------------------------------------------------------------ */
+
+static void (*parent_realize)(PCIDevice *, Error **);
+static void (*parent_exit)(PCIDevice *);
+
+static void apple_vfio_pci_instance_init(Object *obj)
+{
+ VFIOApplePCIDevice *adev = VFIO_APPLE_PCI(obj);
+
+ apple_vfio_pci_init(adev);
+}
+
+static void apple_vfio_pci_realize_fn(PCIDevice *pdev, Error **errp)
+{
+ ERRP_GUARD();
+ VFIOApplePCIDevice *adev = VFIO_APPLE_PCI(pdev);
+
+ if (!apple_vfio_pci_pre_realize(adev, errp)) {
+ return;
+ }
+
+ parent_realize(pdev, errp);
+ if (*errp) {
+ g_clear_pointer(&adev->apple, g_free);
+ return;
+ }
+
+ if (!apple_vfio_create_dma_companion(adev, errp)) {
+ if (parent_exit) {
+ parent_exit(pdev);
+ }
+ g_clear_pointer(&adev->apple, g_free);
+ return;
+ }
+}
+
+static void apple_vfio_pci_exit_fn(PCIDevice *pdev)
+{
+ VFIOApplePCIDevice *adev = VFIO_APPLE_PCI(pdev);
+
+ apple_vfio_destroy_dma_companion(adev);
+
+ if (parent_exit) {
+ parent_exit(pdev);
+ }
+}
+
+static void apple_vfio_pci_finalize_fn(Object *obj)
+{
+ VFIOApplePCIDevice *adev = VFIO_APPLE_PCI(obj);
+
+ apple_vfio_device_cleanup(adev);
+ g_clear_pointer(&adev->apple, g_free);
+}
+
+static void apple_vfio_pci_class_init(ObjectClass *klass, const void *data)
+{
+ PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ parent_realize = pdc->realize;
+ parent_exit = pdc->exit;
+
+ pdc->realize = apple_vfio_pci_realize_fn;
+ pdc->exit = apple_vfio_pci_exit_fn;
+ dc->user_creatable = true;
+ dc->desc = "VFIO-based PCI device assignment (Apple/macOS)";
+}
+
+static const TypeInfo vfio_apple_pci_info = {
+ .name = TYPE_VFIO_APPLE_PCI,
+ .parent = TYPE_VFIO_PCI,
+ .instance_size = sizeof(VFIOApplePCIDevice),
+ .instance_init = apple_vfio_pci_instance_init,
+ .instance_finalize = apple_vfio_pci_finalize_fn,
+ .class_init = apple_vfio_pci_class_init,
+};
+
+static void register_vfio_apple_pci_type(void)
+{
+ type_register_static(&vfio_apple_pci_info);
+}
+
+type_init(register_vfio_apple_pci_type)
diff --git a/hw/vfio/apple.h b/hw/vfio/apple.h
new file mode 100644
index 0000000000..81d4bd2b66
--- /dev/null
+++ b/hw/vfio/apple.h
@@ -0,0 +1,74 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Apple/macOS VFIO passthrough common definitions.
+ *
+ * Copyright (c) 2026 Scott J. Goldman
+ */
+
+#ifndef HW_VFIO_APPLE_H
+#define HW_VFIO_APPLE_H
+
+#include <stdint.h>
+
+#include "hw/vfio/pci.h"
+#include "hw/vfio/vfio-container.h"
+#include "qapi/error.h"
+#include "qemu/event_notifier.h"
+
+#ifdef CONFIG_DARWIN
+#include <IOKit/IOKitLib.h>
+#else
+typedef uintptr_t io_connect_t;
+#define IO_OBJECT_NULL ((io_connect_t)0)
+#endif
+
+OBJECT_DECLARE_SIMPLE_TYPE(AppleVFIOContainer, VFIO_IOMMU_APPLE)
+
+struct AppleVFIOContainer {
+ VFIOContainer parent_obj;
+ io_connect_t dext_conn;
+ uint8_t host_bus;
+ uint8_t host_device;
+ uint8_t host_function;
+};
+
+typedef struct AppleDextInterruptNotify AppleDextInterruptNotify;
+
+typedef struct AppleVFIOBarMap {
+ void *addr;
+ size_t size;
+} AppleVFIOBarMap;
+
+typedef struct AppleVFIOState {
+ AppleDextInterruptNotify *irq_notify;
+ EventNotifier irq_notifier;
+ uint32_t num_irq_vectors;
+ AppleVFIOBarMap bar_maps[PCI_ROM_SLOT];
+} AppleVFIOState;
+
+OBJECT_DECLARE_SIMPLE_TYPE(VFIOApplePCIDevice, VFIO_APPLE_PCI)
+
+struct VFIOApplePCIDevice {
+ VFIOPCIDevice parent_obj;
+ AppleVFIOState *apple;
+ DeviceState *dma_companion;
+ bool dma_companion_autocreated;
+};
+
+extern VFIODeviceIOOps apple_vfio_device_io_ops;
+
+bool apple_vfio_device_setup(VFIOApplePCIDevice *adev, Error **errp);
+void apple_vfio_device_cleanup(VFIOApplePCIDevice *adev);
+bool apple_vfio_get_bar_info(VFIOApplePCIDevice *adev, uint8_t bar,
+ uint8_t *mem_idx, uint64_t *size,
+ uint8_t *type);
+
+bool apple_vfio_dext_publish(uint8_t bus, uint8_t device, uint8_t function,
+ io_connect_t conn);
+io_connect_t apple_vfio_dext_lookup(uint8_t bus, uint8_t device,
+ uint8_t function);
+void apple_vfio_dext_release(uint8_t bus, uint8_t device, uint8_t function,
+ io_connect_t conn);
+
+#endif /* HW_VFIO_APPLE_H */
diff --git a/hw/vfio/container-apple.c b/hw/vfio/container-apple.c
new file mode 100644
index 0000000000..5a5c55b622
--- /dev/null
+++ b/hw/vfio/container-apple.c
@@ -0,0 +1,241 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Apple/macOS VFIO IOMMU container backend.
+ *
+ * Copyright (c) 2026 Scott J. Goldman
+ */
+
+#include "qemu/osdep.h"
+
+#include <linux/vfio.h>
+
+#include "apple-dext-client.h"
+#include "hw/vfio/apple.h"
+#include "hw/vfio/vfio-device.h"
+#include "hw/vfio/vfio-listener.h"
+#include "qapi/error.h"
+#include "system/ramblock.h"
+
+static bool apple_vfio_setup(VFIOContainer *bcontainer, Error **errp)
+{
+ bcontainer->pgsizes = qemu_real_host_page_size();
+ bcontainer->dma_max_mappings = UINT_MAX;
+ bcontainer->dirty_pages_supported = false;
+ bcontainer->max_dirty_bitmap_size = 0;
+ bcontainer->dirty_pgsizes = 0;
+ return true;
+}
+
+/*
+ * DMA map/unmap are no-ops: Apple passthrough handles DMA mapping through
+ * the companion apple-dma-pci device which talks to the dext directly,
+ * bypassing the IOMMU container's DMA path. The stubs are required because
+ * the VFIO listener asserts they are non-NULL.
+ */
+static int apple_vfio_dma_map(const VFIOContainer *bcontainer, hwaddr iova,
+ uint64_t size, void *vaddr, bool readonly,
+ MemoryRegion *mr)
+{
+ return 0;
+}
+
+static int apple_vfio_dma_unmap(const VFIOContainer *bcontainer, hwaddr iova,
+ uint64_t size, IOMMUTLBEntry *iotlb,
+ bool unmap_all)
+{
+ return 0;
+}
+
+static int apple_vfio_set_dirty_page_tracking(const VFIOContainer *bcontainer,
+ bool start, Error **errp)
+{
+ error_setg_errno(errp, ENOTSUP, "vfio-apple does not support migration");
+ return -ENOTSUP;
+}
+
+static int apple_vfio_query_dirty_bitmap(const VFIOContainer *bcontainer,
+ VFIOBitmap *vbmap, hwaddr iova,
+ hwaddr size, uint64_t backend_flag,
+ Error **errp)
+{
+ error_setg_errno(errp, ENOTSUP, "vfio-apple does not support migration");
+ return -ENOTSUP;
+}
+
+static int apple_vfio_pci_hot_reset(VFIODevice *vbasedev, bool single)
+{
+ return 0;
+}
+
+static AppleVFIOContainer *apple_vfio_container_connect(AddressSpace *as,
+ VFIODevice *vbasedev,
+ Error **errp)
+{
+ VFIOPCIDevice *vdev = VFIO_PCI_DEVICE(vbasedev->dev);
+ AppleVFIOContainer *container;
+ VFIOContainer *bcontainer;
+ VFIOAddressSpace *space;
+ VFIOIOMMUClass *vioc;
+ int ret;
+
+ space = vfio_address_space_get(as);
+ container = VFIO_IOMMU_APPLE(object_new(TYPE_VFIO_IOMMU_APPLE));
+ bcontainer = VFIO_IOMMU(container);
+ vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
+
+ container->host_bus = vdev->host.bus;
+ container->host_device = vdev->host.slot;
+ container->host_function = vdev->host.function;
+
+ ret = ram_block_uncoordinated_discard_disable(true);
+ if (ret) {
+ error_setg_errno(errp, -ret, "Cannot set discarding of RAM broken");
+ goto fail_unref;
+ }
+
+ container->dext_conn = apple_dext_connect(container->host_bus,
+ container->host_device,
+ container->host_function);
+ if (container->dext_conn == IO_OBJECT_NULL) {
+ error_setg(errp,
+ "vfio-apple: could not connect to dext for host PCI "
+ "%02x:%02x.%x",
+ container->host_bus, container->host_device,
+ container->host_function);
+ goto fail_discards;
+ }
+
+ if (apple_dext_claim(container->dext_conn) != KERN_SUCCESS) {
+ error_setg(errp,
+ "vfio-apple: failed to claim dext-backed PCI device "
+ "%02x:%02x.%x",
+ container->host_bus, container->host_device,
+ container->host_function);
+ goto fail_release_conn;
+ }
+
+ if (!apple_vfio_dext_publish(container->host_bus, container->host_device,
+ container->host_function,
+ container->dext_conn)) {
+ error_setg(errp,
+ "vfio-apple: duplicate dext owner for host PCI %02x:%02x.%x",
+ container->host_bus, container->host_device,
+ container->host_function);
+ goto fail_release_conn;
+ }
+
+ if (!vioc->setup(bcontainer, errp)) {
+ goto fail_shared_conn;
+ }
+
+ vfio_address_space_insert(space, bcontainer);
+
+ if (!vfio_listener_register(bcontainer, errp)) {
+ goto fail_address_space;
+ }
+
+ bcontainer->initialized = true;
+ return container;
+
+fail_address_space:
+ vfio_listener_unregister(bcontainer);
+ QLIST_REMOVE(bcontainer, next);
+ bcontainer->space = NULL;
+fail_shared_conn:
+ apple_vfio_dext_release(container->host_bus, container->host_device,
+ container->host_function, container->dext_conn);
+ container->dext_conn = IO_OBJECT_NULL;
+fail_discards:
+ ram_block_uncoordinated_discard_disable(false);
+fail_unref:
+ object_unref(container);
+ vfio_address_space_put(space);
+ return NULL;
+
+fail_release_conn:
+ apple_dext_disconnect(container->dext_conn);
+ container->dext_conn = IO_OBJECT_NULL;
+ goto fail_discards;
+}
+
+static void apple_vfio_container_disconnect(AppleVFIOContainer *container)
+{
+ VFIOContainer *bcontainer = VFIO_IOMMU(container);
+ VFIOAddressSpace *space = bcontainer->space;
+
+ ram_block_uncoordinated_discard_disable(false);
+ vfio_listener_unregister(bcontainer);
+
+ apple_vfio_dext_release(container->host_bus, container->host_device,
+ container->host_function, container->dext_conn);
+ container->dext_conn = IO_OBJECT_NULL;
+
+ object_unref(container);
+ vfio_address_space_put(space);
+}
+
+static bool apple_vfio_attach_device(const char *name, VFIODevice *vbasedev,
+ AddressSpace *as, Error **errp)
+{
+ VFIOApplePCIDevice *adev = VFIO_APPLE_PCI(vbasedev->dev);
+ AppleVFIOContainer *container;
+ struct vfio_device_info info = {
+ .argsz = sizeof(info),
+ .flags = VFIO_DEVICE_FLAGS_PCI | VFIO_DEVICE_FLAGS_RESET,
+ .num_regions = VFIO_PCI_NUM_REGIONS,
+ .num_irqs = VFIO_PCI_NUM_IRQS,
+ };
+
+ container = apple_vfio_container_connect(as, vbasedev, errp);
+ if (!container) {
+ return false;
+ }
+
+ vbasedev->fd = -1;
+ vbasedev->io_ops = &apple_vfio_device_io_ops;
+ vfio_device_prepare(vbasedev, VFIO_IOMMU(container), &info);
+
+ if (!apple_vfio_device_setup(adev, errp)) {
+ vfio_device_unprepare(vbasedev);
+ apple_vfio_container_disconnect(container);
+ return false;
+ }
+
+ return true;
+}
+
+static void apple_vfio_detach_device(VFIODevice *vbasedev)
+{
+ VFIOApplePCIDevice *adev = VFIO_APPLE_PCI(vbasedev->dev);
+ AppleVFIOContainer *container = VFIO_IOMMU_APPLE(vbasedev->bcontainer);
+
+ apple_vfio_device_cleanup(adev);
+ vfio_device_unprepare(vbasedev);
+ apple_vfio_container_disconnect(container);
+}
+
+static void vfio_iommu_apple_class_init(ObjectClass *klass, const void *data)
+{
+ VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass);
+
+ vioc->setup = apple_vfio_setup;
+ vioc->dma_map = apple_vfio_dma_map;
+ vioc->dma_unmap = apple_vfio_dma_unmap;
+ vioc->attach_device = apple_vfio_attach_device;
+ vioc->detach_device = apple_vfio_detach_device;
+ vioc->set_dirty_page_tracking = apple_vfio_set_dirty_page_tracking;
+ vioc->query_dirty_bitmap = apple_vfio_query_dirty_bitmap;
+ vioc->pci_hot_reset = apple_vfio_pci_hot_reset;
+}
+
+static const TypeInfo apple_vfio_types[] = {
+ {
+ .name = TYPE_VFIO_IOMMU_APPLE,
+ .parent = TYPE_VFIO_IOMMU,
+ .instance_size = sizeof(AppleVFIOContainer),
+ .class_init = vfio_iommu_apple_class_init,
+ },
+};
+
+DEFINE_TYPES(apple_vfio_types)
diff --git a/hw/vfio/meson.build b/hw/vfio/meson.build
index 965c8e5b80..473f8669f9 100644
--- a/hw/vfio/meson.build
+++ b/hw/vfio/meson.build
@@ -40,6 +40,8 @@ system_ss.add(when: 'CONFIG_VFIO_PCI', if_true: files(
# Apple VFIO backend
if host_os == 'darwin'
system_ss.add(when: 'CONFIG_VFIO',
- if_true: [files('apple-dext-client.c'),
- coref, iokit])
+ if_true: [files('apple-device.c',
+ 'container-apple.c',
+ 'apple-dext-client.c'),
+ coref, iokit])
endif
--
2.50.1 (Apple Git-155)
next prev parent reply other threads:[~2026-04-05 7:30 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-05 7:28 [RFC PATCH 00/10] vfio: PCI device passthrough on Apple Silicon Macs Scott J. Goldman
2026-04-05 7:28 ` [RFC PATCH 01/10] vfio/pci: Use the write side of EventNotifier for IRQ signaling Scott J. Goldman
2026-04-05 7:28 ` [RFC PATCH 02/10] accel/hvf: avoid executable mappings for RAM-device memory Scott J. Goldman
2026-04-22 17:05 ` Philippe Mathieu-Daudé
2026-04-05 7:28 ` [RFC PATCH 03/10] vfio: Allow building on Darwin hosts Scott J. Goldman
2026-04-05 7:28 ` [RFC PATCH 04/10] vfio: Prepare existing code for Apple VFIO backend Scott J. Goldman
2026-04-05 7:28 ` [RFC PATCH 05/10] vfio: Add region_map and region_unmap callbacks to VFIODeviceIOOps Scott J. Goldman
2026-04-05 7:28 ` [RFC PATCH 06/10] vfio: Add device_reset callback " Scott J. Goldman
2026-04-05 7:28 ` [RFC PATCH 07/10] vfio/apple: Add DriverKit dext client library Scott J. Goldman
2026-04-05 7:28 ` Scott J. Goldman [this message]
2026-04-05 7:28 ` [RFC PATCH 09/10] vfio/apple: Add apple-dma-pci companion device Scott J. Goldman
2026-04-05 7:28 ` [RFC PATCH 10/10] docs: Add vfio-apple documentation and MAINTAINERS entry Scott J. Goldman
2026-04-05 8:01 ` [RFC PATCH 00/10] vfio: PCI device passthrough on Apple Silicon Macs Mohamed Mediouni
2026-04-05 8:14 ` Mohamed Mediouni
2026-04-05 23:20 ` Scott J. Goldman
2026-04-06 0:16 ` Mohamed Mediouni
2026-04-08 7:02 ` Scott J. Goldman
2026-04-08 8:33 ` Mohamed Mediouni
2026-04-08 19:09 ` Mohamed Mediouni
2026-04-08 20:45 ` Scott J. Goldman
2026-04-08 22:12 ` Mohamed Mediouni
2026-04-08 23:33 ` Scott J. Goldman
2026-04-09 0:02 ` Mohamed Mediouni
2026-04-05 10:36 ` BALATON Zoltan
2026-04-05 18:16 ` Scott J. Goldman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260405072857.66484-9-scottjgo@gmail.com \
--to=scottjgo@gmail.com \
--cc=alex@shazbot.org \
--cc=clg@redhat.com \
--cc=john.levon@nutanix.com \
--cc=mst@redhat.com \
--cc=pbonzini@redhat.com \
--cc=phil@philjordan.eu \
--cc=qemu-devel@nongnu.org \
--cc=qemu-s390x@nongnu.org \
--cc=rbolshakov@ddn.com \
--cc=scottjg@umich.edu \
--cc=thanos.makatos@nutanix.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.