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 <mohamed@unpredictable.fr>
---
hw/display/apple-gfx-mmio.m | 62 ++++++++++++++++++++++++++++---------
hw/display/apple-gfx.h | 18 +++++++++++
hw/display/apple-gfx.m | 43 ++++++++++++++++++++++++-
3 files changed, 107 insertions(+), 16 deletions(-)
diff --git a/hw/display/apple-gfx-mmio.m b/hw/display/apple-gfx-mmio.m
index 58beaadd1f..323dcfe8cd 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
@@ -182,20 +190,34 @@ static bool apple_gfx_mmio_unmap_surface_memory(void *ptr)
PGIOSurfaceHostDeviceDescriptor *iosfc_desc =
[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);
- };
+ PGMemoryMapDescriptor* memory_map_descriptor;
+
+ /*
+ * The legacy memory management API is no longer present
+ * for the IOSurface mapper as of macOS 15.4.
+ */
+ if (@available(macOS 15.4, *)) {
+ 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 +245,23 @@ static void apple_gfx_mmio_realize(DeviceState *dev, Error **errp)
};
desc.usingIOSurfaceMapper = true;
- s->pgiosfc = apple_gfx_prepare_iosurface_host_device(s);
+ desc.enableArgumentBuffers = true;
+ /*
+ * 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..72b360454e 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,12 @@ 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 e0a765fcb1..92404d20bf 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"
@@ -596,6 +597,37 @@ 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_const,
+ hwaddr offset_in_region, void *opaque) {
+ MemoryRegion *mr = (MemoryRegion *)mr_const;
+ PGGuestPhysicalRange_t range;
+ PGMemoryMapDescriptor *memory_map_descriptor = opaque;
+ if (memory_access_is_direct(mr, true, MEMTXATTRS_UNSPECIFIED)) {
+ range.physicalAddress = start;
+ range.physicalLength = len;
+ range.hostAddress = memory_region_get_ram_ptr(mr);
+ [memory_map_descriptor addRange:range];
+ memory_region_ref(mr);
+ }
+ 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;
+}
+
static void apple_gfx_register_task_mapping_handlers(AppleGFXState *s,
PGDeviceDescriptor *desc)
{
@@ -763,7 +795,16 @@ 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 {
+ apple_gfx_register_task_mapping_handlers(s, desc);
+ }
s->cursor_show = true;
--
2.50.1 (Apple Git-155)
On 2026/03/06 23:52, 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 <mohamed@unpredictable.fr>
> ---
> hw/display/apple-gfx-mmio.m | 62 ++++++++++++++++++++++++++++---------
> hw/display/apple-gfx.h | 18 +++++++++++
> hw/display/apple-gfx.m | 43 ++++++++++++++++++++++++-
> 3 files changed, 107 insertions(+), 16 deletions(-)
>
> diff --git a/hw/display/apple-gfx-mmio.m b/hw/display/apple-gfx-mmio.m
> index 58beaadd1f..323dcfe8cd 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
>
> @@ -182,20 +190,34 @@ static bool apple_gfx_mmio_unmap_surface_memory(void *ptr)
> PGIOSurfaceHostDeviceDescriptor *iosfc_desc =
> [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);
> - };
> + PGMemoryMapDescriptor* memory_map_descriptor;
This should be:
PGMemoryMapDescriptor *memory_map_descriptor
scripts/checkpatch.pl enforces this, but sadly this script does not
support Objective-C.
Also, docs/devel/style.rst says "Mixed declarations (interleaving
statements and declarations within blocks) are generally not allowed;
declarations should be at the beginning of blocks." Moving this to the
if block below will fix it.
> +
> + /*
> + * The legacy memory management API is no longer present
> + * for the IOSurface mapper as of macOS 15.4.
> + */
> + if (@available(macOS 15.4, *)) {
> + 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 +245,23 @@ static void apple_gfx_mmio_realize(DeviceState *dev, Error **errp)
> };
>
> desc.usingIOSurfaceMapper = true;
> - s->pgiosfc = apple_gfx_prepare_iosurface_host_device(s);
> + desc.enableArgumentBuffers = true;
> + /*
> + * 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..72b360454e 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,12 @@ 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 e0a765fcb1..92404d20bf 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"
> @@ -596,6 +597,37 @@ 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_const,
> + hwaddr offset_in_region, void *opaque) {
> + MemoryRegion *mr = (MemoryRegion *)mr_const;
flatview_for_each_range() should be changed to pass non-const pointers
instead.
Regards,
Akihiko Odaki
> + PGGuestPhysicalRange_t range;
> + PGMemoryMapDescriptor *memory_map_descriptor = opaque;
> + if (memory_access_is_direct(mr, true, MEMTXATTRS_UNSPECIFIED)) {
> + range.physicalAddress = start;
> + range.physicalLength = len;
> + range.hostAddress = memory_region_get_ram_ptr(mr);
> + [memory_map_descriptor addRange:range];
> + memory_region_ref(mr);
> + }
> + 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;
> +}
> +
> static void apple_gfx_register_task_mapping_handlers(AppleGFXState *s,
> PGDeviceDescriptor *desc)
> {
> @@ -763,7 +795,16 @@ 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 {
> + apple_gfx_register_task_mapping_handlers(s, desc);
> + }
>
> s->cursor_show = true;
>
+Peter/Paolo
On 7/3/26 04:08, Akihiko Odaki wrote:
> On 2026/03/06 23:52, 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 <mohamed@unpredictable.fr>
>> ---
>> hw/display/apple-gfx-mmio.m | 62 ++++++++++++++++++++++++++++---------
>> hw/display/apple-gfx.h | 18 +++++++++++
>> hw/display/apple-gfx.m | 43 ++++++++++++++++++++++++-
>> 3 files changed, 107 insertions(+), 16 deletions(-)
>> diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
>> index e0a765fcb1..92404d20bf 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"
>> @@ -596,6 +597,37 @@ 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_const,
>> + hwaddr offset_in_region, void
>> *opaque) {
>> + MemoryRegion *mr = (MemoryRegion *)mr_const;
>
> flatview_for_each_range() should be changed to pass non-const pointers
> instead.
flatview_for_each_range() was added in commit fb5ef4eeecd ("memory: Add
FlatView foreach function") with memory fuzzing in mind, so const MR was
the correct choice then IMO.
FlatView is more of an internal memory API, I'm not sure it should be
used by hw/ layer.
$ git grep -w flatview_for_each_range
hw/core/loader.c:1656: flatview_for_each_range(fv, find_rom_cb, &cbdata);
semihosting/arm-compat-semi.c:158: flatview_for_each_range(fv,
find_ram_cb, &info);
tests/qtest/fuzz/generic_fuzz.c:310:
flatview_for_each_range(view, get_io_address_cb , &cb_info);
Semihosting is special, as it the ROM loader helper, and fuzzing code.
We provide MemoryRegionSection, MemoryListener and RamDiscardListener
APIs. Maybe one of them is more appropriate here? See:
* A #RamDiscardManager coordinates which parts of specific RAM
* #MemoryRegion regions are currently populated to be used/accessed
* by the VM, notifying after parts were discarded (freeing up memory)
* and before parts will be populated (consuming memory), to be used/
* accessed by the VM.
Could this be what this code needs to do?
> Regards,
> Akihiko Odaki
>
>> + PGGuestPhysicalRange_t range;
>> + PGMemoryMapDescriptor *memory_map_descriptor = opaque;
>> + if (memory_access_is_direct(mr, true, MEMTXATTRS_UNSPECIFIED)) {
>> + range.physicalAddress = start;
>> + range.physicalLength = len;
>> + range.hostAddress = memory_region_get_ram_ptr(mr);
>> + [memory_map_descriptor addRange:range];
>> + memory_region_ref(mr);
>> + }
>> + 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;
>> +}
On 2026/03/10 7:21, Philippe Mathieu-Daudé wrote:
> +Peter/Paolo
>
> On 7/3/26 04:08, Akihiko Odaki wrote:
>> On 2026/03/06 23:52, 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 <mohamed@unpredictable.fr>
>>> ---
>>> hw/display/apple-gfx-mmio.m | 62 ++++++++++++++++++++++++++++---------
>>> hw/display/apple-gfx.h | 18 +++++++++++
>>> hw/display/apple-gfx.m | 43 ++++++++++++++++++++++++-
>>> 3 files changed, 107 insertions(+), 16 deletions(-)
>
>
>>> diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
>>> index e0a765fcb1..92404d20bf 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"
>>> @@ -596,6 +597,37 @@ 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_const,
>>> + hwaddr offset_in_region, void
>>> *opaque) {
>>> + MemoryRegion *mr = (MemoryRegion *)mr_const;
>>
>> flatview_for_each_range() should be changed to pass non-const pointers
>> instead.
>
> flatview_for_each_range() was added in commit fb5ef4eeecd ("memory: Add
> FlatView foreach function") with memory fuzzing in mind, so const MR was
> the correct choice then IMO.
>
> FlatView is more of an internal memory API, I'm not sure it should be
> used by hw/ layer.
>
> $ git grep -w flatview_for_each_range
> hw/core/loader.c:1656: flatview_for_each_range(fv, find_rom_cb,
> &cbdata);
> semihosting/arm-compat-semi.c:158: flatview_for_each_range(fv,
> find_ram_cb, &info);
> tests/qtest/fuzz/generic_fuzz.c:310: flatview_for_each_range(view,
> get_io_address_cb , &cb_info);
>
> Semihosting is special, as it the ROM loader helper, and fuzzing code.
>
>
> We provide MemoryRegionSection, MemoryListener and RamDiscardListener
> APIs. Maybe one of them is more appropriate here? See:
>
> * A #RamDiscardManager coordinates which parts of specific RAM
> * #MemoryRegion regions are currently populated to be used/accessed
> * by the VM, notifying after parts were discarded (freeing up memory)
> * and before parts will be populated (consuming memory), to be used/
> * accessed by the VM.
>
> Could this be what this code needs to do?
The problem here is that the reverse-engineered interface is
insufficient to keep the memory map synchronized so it can only populate
the memory map during initialization. flatview_for_each_range() fits for
this purpose.
Ideally the interface may be reverse-engineered more thoroughly to
synchronize the memory map at runtime but that needs more work.
>
>> Regards,
>> Akihiko Odaki
>>
>>> + PGGuestPhysicalRange_t range;
>>> + PGMemoryMapDescriptor *memory_map_descriptor = opaque;
>>> + if (memory_access_is_direct(mr, true, MEMTXATTRS_UNSPECIFIED)) {
>>> + range.physicalAddress = start;
>>> + range.physicalLength = len;
>>> + range.hostAddress = memory_region_get_ram_ptr(mr);
>>> + [memory_map_descriptor addRange:range];
>>> + memory_region_ref(mr);
>>> + }
>>> + 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;
>>> +}
On Tue, Mar 10, 2026 at 03:55:41PM +0900, Akihiko Odaki wrote:
> On 2026/03/10 7:21, Philippe Mathieu-Daudé wrote:
> > +Peter/Paolo
> >
> > On 7/3/26 04:08, Akihiko Odaki wrote:
> > > On 2026/03/06 23:52, 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 <mohamed@unpredictable.fr>
> > > > ---
> > > > hw/display/apple-gfx-mmio.m | 62 ++++++++++++++++++++++++++++---------
> > > > hw/display/apple-gfx.h | 18 +++++++++++
> > > > hw/display/apple-gfx.m | 43 ++++++++++++++++++++++++-
> > > > 3 files changed, 107 insertions(+), 16 deletions(-)
> >
> >
> > > > diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
> > > > index e0a765fcb1..92404d20bf 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"
> > > > @@ -596,6 +597,37 @@ 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_const,
> > > > + hwaddr offset_in_region, void
> > > > *opaque) {
> > > > + MemoryRegion *mr = (MemoryRegion *)mr_const;
> > >
> > > flatview_for_each_range() should be changed to pass non-const
> > > pointers instead.
> >
> > flatview_for_each_range() was added in commit fb5ef4eeecd ("memory: Add
> > FlatView foreach function") with memory fuzzing in mind, so const MR was
> > the correct choice then IMO.
> >
> > FlatView is more of an internal memory API, I'm not sure it should be
> > used by hw/ layer.
> >
> > $ git grep -w flatview_for_each_range
> > hw/core/loader.c:1656: flatview_for_each_range(fv, find_rom_cb,
> > &cbdata);
> > semihosting/arm-compat-semi.c:158: flatview_for_each_range(fv,
> > find_ram_cb, &info);
> > tests/qtest/fuzz/generic_fuzz.c:310: flatview_for_each_range(view,
> > get_io_address_cb , &cb_info);
> >
> > Semihosting is special, as it the ROM loader helper, and fuzzing code.
> >
> >
> > We provide MemoryRegionSection, MemoryListener and RamDiscardListener
> > APIs. Maybe one of them is more appropriate here? See:
> >
> > * A #RamDiscardManager coordinates which parts of specific RAM
> > * #MemoryRegion regions are currently populated to be used/accessed
> > * by the VM, notifying after parts were discarded (freeing up memory)
> > * and before parts will be populated (consuming memory), to be used/
> > * accessed by the VM.
> >
> > Could this be what this code needs to do?
>
> The problem here is that the reverse-engineered interface is insufficient to
> keep the memory map synchronized so it can only populate the memory map
> during initialization. flatview_for_each_range() fits for this purpose.
>
> Ideally the interface may be reverse-engineered more thoroughly to
> synchronize the memory map at runtime but that needs more work.
IIUC we could still use memory_listener_register(), and I agree with Phil
it might be good to avoid exporting flatview API further to hw/ if ever
possible.
memory_listener_register() will properly replay all the memory regions
similarly when adding the new listener, via region_add().
Thanks,
--
Peter Xu
On 2026/03/11 1:20, Peter Xu wrote:
> On Tue, Mar 10, 2026 at 03:55:41PM +0900, Akihiko Odaki wrote:
>> On 2026/03/10 7:21, Philippe Mathieu-Daudé wrote:
>>> +Peter/Paolo
>>>
>>> On 7/3/26 04:08, Akihiko Odaki wrote:
>>>> On 2026/03/06 23:52, 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 <mohamed@unpredictable.fr>
>>>>> ---
>>>>> hw/display/apple-gfx-mmio.m | 62 ++++++++++++++++++++++++++++---------
>>>>> hw/display/apple-gfx.h | 18 +++++++++++
>>>>> hw/display/apple-gfx.m | 43 ++++++++++++++++++++++++-
>>>>> 3 files changed, 107 insertions(+), 16 deletions(-)
>>>
>>>
>>>>> diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
>>>>> index e0a765fcb1..92404d20bf 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"
>>>>> @@ -596,6 +597,37 @@ 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_const,
>>>>> + hwaddr offset_in_region, void
>>>>> *opaque) {
>>>>> + MemoryRegion *mr = (MemoryRegion *)mr_const;
>>>>
>>>> flatview_for_each_range() should be changed to pass non-const
>>>> pointers instead.
>>>
>>> flatview_for_each_range() was added in commit fb5ef4eeecd ("memory: Add
>>> FlatView foreach function") with memory fuzzing in mind, so const MR was
>>> the correct choice then IMO.
>>>
>>> FlatView is more of an internal memory API, I'm not sure it should be
>>> used by hw/ layer.
>>>
>>> $ git grep -w flatview_for_each_range
>>> hw/core/loader.c:1656: flatview_for_each_range(fv, find_rom_cb,
>>> &cbdata);
>>> semihosting/arm-compat-semi.c:158: flatview_for_each_range(fv,
>>> find_ram_cb, &info);
>>> tests/qtest/fuzz/generic_fuzz.c:310: flatview_for_each_range(view,
>>> get_io_address_cb , &cb_info);
>>>
>>> Semihosting is special, as it the ROM loader helper, and fuzzing code.
>>>
>>>
>>> We provide MemoryRegionSection, MemoryListener and RamDiscardListener
>>> APIs. Maybe one of them is more appropriate here? See:
>>>
>>> * A #RamDiscardManager coordinates which parts of specific RAM
>>> * #MemoryRegion regions are currently populated to be used/accessed
>>> * by the VM, notifying after parts were discarded (freeing up memory)
>>> * and before parts will be populated (consuming memory), to be used/
>>> * accessed by the VM.
>>>
>>> Could this be what this code needs to do?
>>
>> The problem here is that the reverse-engineered interface is insufficient to
>> keep the memory map synchronized so it can only populate the memory map
>> during initialization. flatview_for_each_range() fits for this purpose.
>>
>> Ideally the interface may be reverse-engineered more thoroughly to
>> synchronize the memory map at runtime but that needs more work.
>
> IIUC we could still use memory_listener_register(), and I agree with Phil
> it might be good to avoid exporting flatview API further to hw/ if ever
> possible.
>
> memory_listener_register() will properly replay all the memory regions
> similarly when adding the new listener, via region_add().
That makes a point but calling memory_listener_register() and
memory_listener_unregister() immediately after that (since we don't want
be notified for future updates) is a bit weird.
It's practically not a problem, so if Phil agrees with using
memory_listener_register() then I guess it's the way to go.
Regards,
Akihiko Odaki
> On 10. Mar 2026, at 07:55, Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> wrote:
>
> On 2026/03/10 7:21, Philippe Mathieu-Daudé wrote:
>> +Peter/Paolo
>> On 7/3/26 04:08, Akihiko Odaki wrote:
>>> On 2026/03/06 23:52, 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 <mohamed@unpredictable.fr>
>>>> ---
>>>> hw/display/apple-gfx-mmio.m | 62 ++++++++++++++++++++++++++++---------
>>>> hw/display/apple-gfx.h | 18 +++++++++++
>>>> hw/display/apple-gfx.m | 43 ++++++++++++++++++++++++-
>>>> 3 files changed, 107 insertions(+), 16 deletions(-)
>>>> diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
>>>> index e0a765fcb1..92404d20bf 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"
>>>> @@ -596,6 +597,37 @@ 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_const,
>>>> + hwaddr offset_in_region, void *opaque) {
>>>> + MemoryRegion *mr = (MemoryRegion *)mr_const;
>>>
>>> flatview_for_each_range() should be changed to pass non-const pointers instead.
>> flatview_for_each_range() was added in commit fb5ef4eeecd ("memory: Add
>> FlatView foreach function") with memory fuzzing in mind, so const MR was
>> the correct choice then IMO.
>> FlatView is more of an internal memory API, I'm not sure it should be
>> used by hw/ layer.
>> $ git grep -w flatview_for_each_range
>> hw/core/loader.c:1656: flatview_for_each_range(fv, find_rom_cb, &cbdata);
>> semihosting/arm-compat-semi.c:158: flatview_for_each_range(fv, find_ram_cb, &info);
>> tests/qtest/fuzz/generic_fuzz.c:310: flatview_for_each_range(view, get_io_address_cb , &cb_info);
>> Semihosting is special, as it the ROM loader helper, and fuzzing code.
>> We provide MemoryRegionSection, MemoryListener and RamDiscardListener
>> APIs. Maybe one of them is more appropriate here? See:
>> * A #RamDiscardManager coordinates which parts of specific RAM
>> * #MemoryRegion regions are currently populated to be used/accessed
>> * by the VM, notifying after parts were discarded (freeing up memory)
>> * and before parts will be populated (consuming memory), to be used/
>> * accessed by the VM.
>> Could this be what this code needs to do?
>
> The problem here is that the reverse-engineered interface is insufficient to keep the memory map synchronized so it can only populate the memory map during initialization. flatview_for_each_range() fits for this purpose.
>
> Ideally the interface may be reverse-engineered more thoroughly to synchronize the memory map at runtime but that needs more work.
>
Hello,
Unfortunately there’s no such interface anymore/no notifiers from what I gathered. The new interface has a resetWithMemoryMap
call but that resets the state and use again has to go through the VM save/restore path…
Well, the legacy path is still there for outside of the PGIOSurfaceHostDevice path but that’s just because it’s public
API on x86, and is going away really soon + it blocks sandboxing…
I guess it’s good enough for the macOS use case - and any potential ballooning handleable via purgeable memory...
>>> Regards,
>>> Akihiko Odaki
>>>
>>>> + PGGuestPhysicalRange_t range;
>>>> + PGMemoryMapDescriptor *memory_map_descriptor = opaque;
>>>> + if (memory_access_is_direct(mr, true, MEMTXATTRS_UNSPECIFIED)) {
>>>> + range.physicalAddress = start;
>>>> + range.physicalLength = len;
>>>> + range.hostAddress = memory_region_get_ram_ptr(mr);
>>>> + [memory_map_descriptor addRange:range];
>>>> + memory_region_ref(mr);
>>>> + }
>>>> + 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;
>>>> +}
>
© 2016 - 2026 Red Hat, Inc.