> On 17. Sep 2026, at 22:37, Akihiko Odaki <[email protected]> wrote:
>
> On 2026/09/16 19:00, Mohamed Mediouni wrote:
>> Follow changes in memory management introduced on macOS 15.4.
>> The legacy memory management API has been removed for the IOSurface mapper
>> on that macOS version.
>> Also enable process isolation for a sandboxed GPU process when on a new OS.
>> Signed-off-by: Mohamed Mediouni <[email protected]>
>> ---
>> hw/display/apple-gfx-mmio.m | 58 ++++++++++++++++++------
>> hw/display/apple-gfx.h | 16 +++++++
>> hw/display/apple-gfx.m | 90 ++++++++++++++++++++++++++++++++-----
>> 3 files changed, 138 insertions(+), 26 deletions(-)
>> diff --git a/hw/display/apple-gfx-mmio.m b/hw/display/apple-gfx-mmio.m
>> index 58beaadd1f..19e2d38a1e 100644
>> --- a/hw/display/apple-gfx-mmio.m
>> +++ b/hw/display/apple-gfx-mmio.m
>> @@ -19,6 +19,7 @@
>> #include "hw/core/irq.h"
>> #include "apple-gfx.h"
>> #include "trace.h"
>> +#include "system/address-spaces.h"
>> #import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
>> @@ -36,12 +37,19 @@ typedef bool(^IOSFCMapMemory)(uint64_t phys, uint64_t
>> len, bool ro, void **va,
>> @interface PGDeviceDescriptor (IOSurfaceMapper)
>> @property (readwrite, nonatomic) bool usingIOSurfaceMapper;
>> +@property (readwrite, nonatomic) bool enableArgumentBuffers;
>> +@property (readwrite, nonatomic) bool enableProcessIsolation;
>> +@property (readwrite, nonatomic) bool enableProtectedContent;
>> +
>> +@property (readwrite, nonatomic, copy, nullable) PGMemoryMapDescriptor*
>> memoryMapDescriptor;
>> @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) PGMemoryMapDescriptor*
>> memoryMapDescriptor;
>> +@property (readwrite, nonatomic) unsigned long long mmioLength;
>> @property (readwrite, nonatomic, copy, nullable) IOSFCRaiseInterrupt
>> raiseInterrupt;
>> @end
>> @@ -183,19 +191,32 @@ static bool apple_gfx_mmio_unmap_surface_memory(void
>> *ptr)
>> [PGIOSurfaceHostDeviceDescriptor new];
>> PGIOSurfaceHostDevice *iosfc_host_dev;
>> - iosfc_desc.mapMemory =
>> - ^bool(uint64_t phys, uint64_t len, bool ro, void **va, void *e,
>> void *f) {
>> - *va = apple_gfx_mmio_map_surface_memory(phys, len, ro);
>> -
>> - trace_apple_gfx_iosfc_map_memory(phys, len, ro, va, e, f, *va);
>> -
>> - return *va != NULL;
>> - };
>> -
>> - iosfc_desc.unmapMemory =
>> - ^bool(void *va, void *b, void *c, void *d, void *e, void *f) {
>> - return apple_gfx_mmio_unmap_surface_memory(va);
>> - };
>> + /*
>> + * The legacy memory management API is no longer present
>> + * for the IOSurface mapper as of macOS 15.4.
>> + */
>> + if (@available(macOS 15.4, *)) {
>> + PGMemoryMapDescriptor *memory_map_descriptor =
>> [PGMemoryMapDescriptor new];
>> + FlatView* fv = address_space_to_flatview(&address_space_memory);
>> + flatview_for_each_range(fv, apple_gfx_register_memory_cb,
>> memory_map_descriptor);
>> + /* the device model defines this as a single-page MMIO region,
>> hence 16KB */
>> + iosfc_desc.mmioLength = 0x10000;
>> + iosfc_desc.memoryMapDescriptor = memory_map_descriptor;
>> + } else {
>> + iosfc_desc.mapMemory =
>> + ^bool(uint64_t phys, uint64_t len, bool ro, void **va, void *e,
>> void *f) {
>> + *va = apple_gfx_mmio_map_surface_memory(phys, len, ro);
>> +
>> + trace_apple_gfx_iosfc_map_memory(phys, len, ro, va, e, f,
>> *va);
>> +
>> + return *va != NULL;
>> + };
>> +
>> + iosfc_desc.unmapMemory =
>> + ^bool(void *va, void *b, void *c, void *d, void *e, void *f) {
>> + return apple_gfx_mmio_unmap_surface_memory(va);
>> + };
>> + }
>> iosfc_desc.raiseInterrupt = ^bool(uint32_t vector) {
>> trace_apple_gfx_iosfc_raise_irq(vector);
>> @@ -223,13 +244,22 @@ static void apple_gfx_mmio_realize(DeviceState *dev,
>> Error **errp)
>> };
>> desc.usingIOSurfaceMapper = true;
>> - s->pgiosfc = apple_gfx_prepare_iosurface_host_device(s);
>> + /*
>> + * Process isolation needs PGMemoryMapDescriptor instead of
>> + * the legacy memory management interface present in releases
>> + * older than macOS 15.4.
>> + */
>> + if (@available(macOS 15.4, *)) {
>> + desc.enableProcessIsolation = true;
>> + }
>> if (!apple_gfx_common_realize(&s->common, dev, desc, errp)) {
>> [s->pgiosfc release];
>> s->pgiosfc = nil;
>> }
>> + s->pgiosfc = apple_gfx_prepare_iosurface_host_device(s);
>> +
>> [desc release];
>> desc = nil;
>> }
>> diff --git a/hw/display/apple-gfx.h b/hw/display/apple-gfx.h
>> index 3197bd853d..384aee0c5f 100644
>> --- a/hw/display/apple-gfx.h
>> +++ b/hw/display/apple-gfx.h
>> @@ -12,6 +12,7 @@
>> #include "system/memory.h"
>> #include "hw/core/qdev-properties.h"
>> #include "ui/surface.h"
>> +#include "objc/NSObject.h"
>> #define TYPE_APPLE_GFX_MMIO "apple-gfx-mmio"
>> #define TYPE_APPLE_GFX_PCI "apple-gfx-pci"
>> @@ -23,6 +24,17 @@
>> @protocol MTLTexture;
>> @protocol MTLCommandQueue;
>> +typedef struct PGGuestPhysicalRange_s
>> +{
>> + uint64_t physicalAddress;
>> + uint64_t physicalLength;
>> + void *hostAddress;
>> +} PGGuestPhysicalRange_t;
>> +
>> +@interface PGMemoryMapDescriptor : NSObject
>> +-(void)addRange:(PGGuestPhysicalRange_t) range;
>> +@end
>> +
>> typedef QTAILQ_HEAD(, PGTask_s) PGTaskList;
>> typedef struct AppleGFXDisplayMode {
>> @@ -68,6 +80,10 @@ void *apple_gfx_host_ptr_for_gpa_range(uint64_t
>> guest_physical,
>> uint64_t length, bool read_only,
>> MemoryRegion **mapping_in_region);
>> +bool apple_gfx_register_memory_cb(Int128 start, Int128 len,
>> + const MemoryRegion *mr,
>> + hwaddr offset_in_region, void *opaque);
>> +
>> extern const PropertyInfo qdev_prop_apple_gfx_display_mode;
>> #endif
>> diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
>> index be0061b9db..4ef8f6dbf3 100644
>> --- a/hw/display/apple-gfx.m
>> +++ b/hw/display/apple-gfx.m
>> @@ -21,6 +21,7 @@
>> #include "system/address-spaces.h"
>> #include "system/dma.h"
>> #include "migration/blocker.h"
>> +#include "system/memory.h"
>> #include "ui/console.h"
>> #include "apple-gfx.h"
>> #include "trace.h"
>> @@ -79,6 +80,7 @@ static dispatch_queue_t get_background_queue(void)
>> GPtrArray *mapped_regions;
>> };
>> +API_OBSOLETED("Legacy ParavirtualizedGraphics", macos(11.0, 27.0, 27.0))
>
> git am detected trailing whitespaces:
>
> $ b4 shazam [email protected]
> Looking up [email protected]
> Checking for newer revisions
> Grabbing search results from lore.kernel.org
> Analyzing 15 messages in the thread
> Looking for additional code-review trailers on lore.kernel.org
> Analyzing 94 code-review messages
> Checking attestation on all messages, may take a moment...
> ---
> ✓ [PATCH RFC v8 1/10] target/arm/emulate: add ISV=0 emulation library with
> load/store immediate
> ✓ [PATCH RFC v8 2/10] target/arm/emulate: add load/store register offset
> ✓ [PATCH RFC v8 3/10] target/arm/emulate: add load/store pair
> ✓ [PATCH RFC v8 4/10] target/arm/hvf, whpx: wire ISV=0 emulation for data
> aborts
> ✓ [PATCH RFC v8 5/10] vmapple: apple-gfx: make it work on the latest macOS
> release
> ✓ [PATCH RFC v8 6/10] hw/vmapple: aes: convert MAX_LEN to a #define
> ✓ [PATCH RFC v8 7/10] Revert "hw/arm: Do not build VMapple machine by
> default"
> ✓ [PATCH RFC v8 8/10] vmapple: add gicv2m
> ✓ [PATCH RFC v8 9/10] vmapple, gicv2m: add macOS compat quirk
> ✓ [PATCH RFC v8 10/10] hw/vmapple: virtio-blk: allow FileVault off
> ---
> ✓ Signed: DKIM/unpredictable.fr
> ---
> Total patches: 10
> ---
> Applying: target/arm/emulate: add ISV=0 emulation library with load/store
> immediate
> Applying: target/arm/emulate: add load/store register offset
> Applying: target/arm/emulate: add load/store pair
> Applying: target/arm/hvf, whpx: wire ISV=0 emulation for data aborts
> Applying: vmapple: apple-gfx: make it work on the latest macOS release
> Applying: hw/vmapple: aes: convert MAX_LEN to a #define
> Applying: Revert "hw/arm: Do not build VMapple machine by default"
> Applying: vmapple: add gicv2m
> Applying: vmapple, gicv2m: add macOS compat quirk
> Applying: hw/vmapple: virtio-blk: allow FileVault off
> /home/me/q/var/qemu/.git/rebase-apply/patch:90: trailing whitespace.
> /*
> /home/me/q/var/qemu/.git/rebase-apply/patch:166: trailing whitespace.
> API_OBSOLETED("Legacy ParavirtualizedGraphics", macos(11.0, 27.0, 27.0))
> /home/me/q/var/qemu/.git/rebase-apply/patch:272: trailing whitespace.
> /*
> /home/me/q/var/qemu/.git/rebase-apply/patch:275: trailing whitespace.
> * on macOS 15.4 onwards.
> warning: 4 lines add whitespace errors.
>
>> static PGTask_t *apple_gfx_new_task(AppleGFXState *s, uint64_t len)
>> {
>> mach_vm_address_t task_mem;
>> @@ -102,6 +104,7 @@ static dispatch_queue_t get_background_queue(void)
>> return task;
>> }
>> +API_OBSOLETED("Legacy ParavirtualizedGraphics", macos(11.0, 27.0, 27.0))
>> static void apple_gfx_destroy_task(AppleGFXState *s, PGTask_t *task)
>> {
>> GPtrArray *regions = task->mapped_regions;
>> @@ -151,6 +154,7 @@ static void apple_gfx_destroy_task(AppleGFXState *s,
>> PGTask_t *task)
>> return host_ptr;
>> }
>> +API_OBSOLETED("Legacy ParavirtualizedGraphics", macos(11.0, 27.0, 27.0))
>> static bool apple_gfx_task_map_memory(AppleGFXState *s, PGTask_t *task,
>> uint64_t virtual_offset,
>> PGPhysicalMemoryRange_t *ranges,
>> @@ -207,6 +211,7 @@ static bool apple_gfx_task_map_memory(AppleGFXState *s,
>> PGTask_t *task,
>> return success;
>> }
>> +API_OBSOLETED("Legacy ParavirtualizedGraphics", macos(11.0, 27.0, 27.0))
>> static void apple_gfx_task_unmap_memory(AppleGFXState *s, PGTask_t *task,
>> uint64_t virtual_offset, uint64_t
>> length)
>> {
>> @@ -596,6 +601,36 @@ void apple_gfx_common_init(Object *obj, AppleGFXState
>> *s, const char* obj_name)
>> /* TODO: PVG framework supports serialising device state: integrate it!
>> */
>> }
>> +@interface PGDeviceDescriptor (IOSurfaceMapper)
>> +@property (readwrite, nonatomic, copy, nullable) PGMemoryMapDescriptor*
>> memoryMapDescriptor;
>> +@end
>> +
>> +bool apple_gfx_register_memory_cb(Int128 start, Int128 len,
>> + const MemoryRegion *mr,
>> + hwaddr offset_in_region, void *opaque) {
>> + PGGuestPhysicalRange_t range;
>> + PGMemoryMapDescriptor *memory_map_descriptor = opaque;
>> + if (memory_access_is_direct(mr, true, MEMTXATTRS_UNSPECIFIED)) {
>> + range.physicalAddress = start;
>
> Please convert Int128 through its helpers. This assigns Int128 directly into
> the two uint64_t fields. With CONFIG_TCG_INTERPRETER, QEMU deliberately
> represents Int128 as a structure, even on hosts supporting native __int128.
> Both assignments fail compilation. A focused Clang check using the actual
> QEMU headers reproduced the incompatible-type errors; int128_get64() provides
> the intended checked conversion.
>
>> + range.physicalLength = len;
>> + range.hostAddress = memory_region_get_ram_ptr(mr);
>
> The FlatView slice offset, offset_in_region, needs to be honored when
> registering RAM.
>
> For apple-gfx-pci, ordinary PC RAM above 4 GiB aliases machine->ram starting
> at below_4g_mem_size; GPU accesses to that range now alias low RAM instead.
> Other clipped FlatView ranges have the same problem. The previous mapping
> path adds the translated offset correctly.
>
>> + [memory_map_descriptor addRange:range];
>> + }
>> + return false;
>> +}
>> +
>> +static void apple_gfx_register_memory(AppleGFXState *s,
>> + PGDeviceDescriptor
>> *desc)
>> +{
>> + PGMemoryMapDescriptor* memoryMapDescriptor = [PGMemoryMapDescriptor
>> new];
>> +
>> + FlatView* fv = address_space_to_flatview(&address_space_memory);
>> + flatview_for_each_range(fv, apple_gfx_register_memory_cb,
>> memoryMapDescriptor);
>> +
>> + desc.memoryMapDescriptor = memoryMapDescriptor;
>> +}
>> +
>> +API_OBSOLETED("Legacy ParavirtualizedGraphics", macos(11.0, 27.0, 27.0))
>> static void apple_gfx_register_task_mapping_handlers(AppleGFXState *s,
>> PGDeviceDescriptor
>> *desc)
>> {
>> @@ -667,16 +702,25 @@ static void new_frame_handler_bh(void *opaque)
>> BQL_LOCK_GUARD();
>> set_mode(s, sizeInPixels.x, sizeInPixels.y);
>> };
>> - disp_desc.cursorGlyphHandler = ^(NSBitmapImageRep *glyph,
>> - PGDisplayCoord_t hotspot) {
>> - AppleGFXSetCursorGlyphJob *job = g_malloc0(sizeof(*job));
>> - job->s = s;
>> - job->glyph = glyph;
>> - job->hotspot = hotspot;
>> - [glyph retain];
>> - aio_bh_schedule_oneshot(qemu_get_aio_context(),
>> - set_cursor_glyph, job);
>> - };
>> +
>> + if (@available(macOS 27.0, *)) {
>> +
>> + } else {
>> +#ifndef __MAC_27_0
>> + disp_desc.cursorGlyphHandler = ^(NSBitmapImageRep *glyph,
>> + PGDisplayCoord_t hotspot) {
>> + AppleGFXSetCursorGlyphJob *job = g_malloc0(sizeof(*job));
>> + job->s = s;
>> + job->glyph = glyph;
>> + job->hotspot = hotspot;
>> + [glyph retain];
>> + aio_bh_schedule_oneshot(qemu_get_aio_context(),
>> + set_cursor_glyph, job);
>> + };
>> +#else
>> + abort();
>> +#endif
>
> I wonder what is this #ifdefs for. It tests SDK macro __MAC_27_0, whereas the
> surrounding @available tests the runtime OS. A binary built with that SDK
> aborts during display realization on every pre-27 host, including macOS 26.
> Older hosts also encounter explicit aborts in the memory/device fallback
> paths. Turning supported runtime fallback paths into unconditional process
> termination depending when SDK is available does not look correct.
Hi,
Obsoleted APIs aren’t accessible from a newer SDK even for targeting older OS
versions.
The compiler blocks it even when I use an if (@available) for the newer version
before…
If you have an idea on how to work around that it’d be great.
>
> Regards,
> Akihiko Odaki
>
>> + }
>> disp_desc.cursorShowHandler = ^(BOOL show) {
>> trace_apple_gfx_cursor_show(show);
>> qatomic_set(&s->cursor_show, show);
>> @@ -763,11 +807,33 @@ bool apple_gfx_common_realize(AppleGFXState *s,
>> DeviceState *dev,
>> desc.device = s->mtl;
>> - apple_gfx_register_task_mapping_handlers(s, desc);
>> + /*
>> + * The legacy memory management interface doesn't allow for
>> + * vGPU sandboxing. As such, always use the new interface
>> + * on macOS 15.4 onwards.
>> + */
>> + if (@available(macOS 15.4, *)) {
>> + apple_gfx_register_memory(s, desc);
>> + } else {
>> +#ifndef __MAC_27_0
>> + apple_gfx_register_task_mapping_handlers(s, desc);
>> +#else
>> + abort();
>> +#endif
>> + }
>> s->cursor_show = true;
>> - s->pgdev = PGNewDeviceWithDescriptor(desc);
>> + if (@available(macOS 15.2, *)) {
>> + s->pgdev = PGCreateDeviceWithDescriptor(desc);
>> + }
>> + else {
>> +#ifndef __MAC_27_0
>> + s->pgdev = PGNewDeviceWithDescriptor(desc);
>> +#else
>> + abort();
>> +#endif
>> + }
>> disp_desc = apple_gfx_prepare_display_descriptor(s);
>> /*