public inbox for qemu-devel@nongnu.org
 help / color / mirror / Atom feed
* [PATCH 0/2] hvf: map granule abstraction and macOS 26 4KB IPA
@ 2026-03-09 21:49 Lucas Amaral
  2026-03-09 21:49 ` [PATCH 1/2] accel/hvf: introduce map granule abstraction Lucas Amaral
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Lucas Amaral @ 2026-03-09 21:49 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, agraf, Lucas Amaral

macOS ARM64 requires 16KB alignment for hv_vm_map(), but the guest
kernel uses 4KB pages.  When virtio-gpu blob BAR offsets are not
16KB-aligned, the interior-mapping path fails, falling back to slow
MMIO emulation.

This series introduces:

1. A map granule abstraction (hvf_set/get_map_granule) replacing
   hardcoded qemu_real_host_page_size() calls in HVF memory mapping.
   Non-aligned regions return early instead of proceeding with
   add=false (which attempted an unnecessary unmap).

2. macOS 26 4KB IPA granule support via hv_vm_config_set_ipa_granule(),
   which allows HVF to map at 4KB granularity, matching the guest
   kernel.  Gated behind MAC_OS_VERSION_26_0 availability checks.

Dependencies: none.
Independent of: hvf-isv0-emulation and virtio-gpu-venus-nogl series.
All three QEMU series touch disjoint files and can be merged in any
order.

Lucas Amaral (2):
  accel/hvf: introduce map granule abstraction
  target/arm/hvf: set 4KB IPA granule on macOS 26

 accel/hvf/hvf-all.c  | 21 ++++++++++++++++++---
 include/system/hvf.h | 15 +++++++++++++++
 target/arm/hvf/hvf.c | 14 ++++++++++++++
 3 files changed, 47 insertions(+), 3 deletions(-)

-- 
2.52.0



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/2] accel/hvf: introduce map granule abstraction
  2026-03-09 21:49 [PATCH 0/2] hvf: map granule abstraction and macOS 26 4KB IPA Lucas Amaral
@ 2026-03-09 21:49 ` Lucas Amaral
  2026-03-09 21:49 ` [PATCH 2/2] target/arm/hvf: set 4KB IPA granule on macOS 26 Lucas Amaral
  2026-03-11  2:27 ` [PATCH v2 0/2] hvf: map granule abstraction and configurable IPA Lucas Amaral
  2 siblings, 0 replies; 13+ messages in thread
From: Lucas Amaral @ 2026-03-09 21:49 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, agraf, Lucas Amaral

Replace hardcoded qemu_real_host_page_size() calls in HVF memory
mapping with a configurable map granule (hvf_set/get_map_granule).

On macOS ARM64, the host page size is 16KB, but the guest kernel
typically uses 4KB pages.  The map granule determines the minimum
alignment for hv_vm_map() and hv_vm_protect().

Default behavior is unchanged (returns host page size).  A subsequent
commit will configure 4KB granule on macOS 26+.

Also fix the non-aligned region path in hvf_set_phys_mem() to return
early instead of proceeding with add=false, which would attempt an
unnecessary unmap of a region that was never mapped.

Signed-off-by: Lucas Amaral <lucaaamaral@gmail.com>
---
 accel/hvf/hvf-all.c  | 21 ++++++++++++++++++---
 include/system/hvf.h | 15 +++++++++++++++
 2 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c
index 033c677..ccff626 100644
--- a/accel/hvf/hvf-all.c
+++ b/accel/hvf/hvf-all.c
@@ -23,6 +23,21 @@
 
 bool hvf_allowed;
 
+static uint64_t hvf_map_granule;
+
+void hvf_set_map_granule(uint64_t size)
+{
+    hvf_map_granule = size;
+}
+
+uint64_t hvf_get_map_granule(void)
+{
+    if (!hvf_map_granule) {
+        return qemu_real_host_page_size();
+    }
+    return hvf_map_granule;
+}
+
 const char *hvf_return_string(hv_return_t ret)
 {
     switch (ret) {
@@ -54,7 +69,7 @@ void assert_hvf_ok_impl(hv_return_t ret, const char *file, unsigned int line,
 static void do_hv_vm_protect(hwaddr start, size_t size,
                              hv_memory_flags_t flags)
 {
-    intptr_t page_mask = qemu_real_host_page_mask();
+    intptr_t page_mask = -(intptr_t)hvf_get_map_granule();
     hv_return_t ret;
 
     trace_hvf_vm_protect(start, size, flags,
@@ -84,7 +99,7 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
     MemoryRegion *area = section->mr;
     bool writable = !area->readonly && !area->rom_device;
     hv_memory_flags_t flags;
-    uint64_t page_size = qemu_real_host_page_size();
+    uint64_t page_size = hvf_get_map_granule();
     uint64_t gpa = section->offset_within_address_space;
     uint64_t size = int128_get64(section->size);
     hv_return_t ret;
@@ -105,7 +120,7 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
     if (!QEMU_IS_ALIGNED(size, page_size) ||
         !QEMU_IS_ALIGNED(gpa, page_size)) {
         /* Not page aligned, so we can not map as RAM */
-        add = false;
+        return;
     }
 
     if (!add) {
diff --git a/include/system/hvf.h b/include/system/hvf.h
index d3dcf08..d1b702b 100644
--- a/include/system/hvf.h
+++ b/include/system/hvf.h
@@ -36,4 +36,19 @@ typedef struct HVFState HVFState;
 DECLARE_INSTANCE_CHECKER(HVFState, HVF_STATE,
                          TYPE_HVF_ACCEL)
 
+#ifdef CONFIG_HVF_IS_POSSIBLE
+/*
+ * Minimum alignment for hv_vm_map(). Returns host page size (16KB on
+ * macOS ARM64), or 4KB when HVF 4KB IPA granule is configured (macOS 26+).
+ */
+void hvf_set_map_granule(uint64_t size);
+uint64_t hvf_get_map_granule(void);
+#else
+static inline void hvf_set_map_granule(uint64_t size) {}
+static inline uint64_t hvf_get_map_granule(void)
+{
+    return qemu_real_host_page_size();
+}
+#endif
+
 #endif
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/2] target/arm/hvf: set 4KB IPA granule on macOS 26
  2026-03-09 21:49 [PATCH 0/2] hvf: map granule abstraction and macOS 26 4KB IPA Lucas Amaral
  2026-03-09 21:49 ` [PATCH 1/2] accel/hvf: introduce map granule abstraction Lucas Amaral
@ 2026-03-09 21:49 ` Lucas Amaral
  2026-03-10  1:25   ` Mohamed Mediouni
  2026-03-11  2:27 ` [PATCH v2 0/2] hvf: map granule abstraction and configurable IPA Lucas Amaral
  2 siblings, 1 reply; 13+ messages in thread
From: Lucas Amaral @ 2026-03-09 21:49 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, agraf, Lucas Amaral

macOS 26 introduces hv_vm_config_set_ipa_granule() which allows
configuring 4KB IPA granularity for HVF virtual machines.  This
enables hv_vm_map() to accept 4KB-aligned addresses, matching
the guest kernel's page size.

Without this, virtio-gpu blob BAR offsets that are 4KB-aligned but
not 16KB-aligned cannot be mapped into the guest, falling back to
slow MMIO emulation.

Gated behind MAC_OS_VERSION_26_0 compile-time and __builtin_available
runtime checks.  Falls back to the default 16KB granule on older
macOS versions.

Signed-off-by: Lucas Amaral <lucaaamaral@gmail.com>
---
 target/arm/hvf/hvf.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 87ddcdb..b71a98a 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -960,6 +960,20 @@ hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range)
     }
     chosen_ipa_bit_size = pa_range;
 
+#ifdef MAC_OS_VERSION_26_0
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0
+    if (__builtin_available(macOS 26, *)) {
+        ret = hv_vm_config_set_ipa_granule(config, HV_IPA_GRANULE_4KB);
+        if (ret != HV_SUCCESS) {
+            error_report("HVF: failed to set 4KB IPA granule: %s",
+                         hvf_return_string(ret));
+            goto cleanup;
+        }
+        hvf_set_map_granule(4096);
+    }
+#endif
+#endif
+
     ret = hv_vm_create(config);
 
 cleanup:
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/2] target/arm/hvf: set 4KB IPA granule on macOS 26
  2026-03-09 21:49 ` [PATCH 2/2] target/arm/hvf: set 4KB IPA granule on macOS 26 Lucas Amaral
@ 2026-03-10  1:25   ` Mohamed Mediouni
  0 siblings, 0 replies; 13+ messages in thread
From: Mohamed Mediouni @ 2026-03-10  1:25 UTC (permalink / raw)
  To: Lucas Amaral; +Cc: qemu-devel, qemu-arm, agraf



> On 9. Mar 2026, at 22:49, Lucas Amaral <lucaaamaral@gmail.com> wrote:
> 
> macOS 26 introduces hv_vm_config_set_ipa_granule() which allows
> configuring 4KB IPA granularity for HVF virtual machines.  This
> enables hv_vm_map() to accept 4KB-aligned addresses, matching
> the guest kernel's page size.
> 
> Without this, virtio-gpu blob BAR offsets that are 4KB-aligned but
> not 16KB-aligned cannot be mapped into the guest, falling back to
> slow MMIO emulation.
> 
> Gated behind MAC_OS_VERSION_26_0 compile-time and __builtin_available
> runtime checks.  Falls back to the default 16KB granule on older
> macOS versions.
> 
> Signed-off-by: Lucas Amaral <lucaaamaral@gmail.com>
> ---
> target/arm/hvf/hvf.c | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
> 
> diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
> index 87ddcdb..b71a98a 100644
> --- a/target/arm/hvf/hvf.c
> +++ b/target/arm/hvf/hvf.c
> @@ -960,6 +960,20 @@ hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range)
>     }
>     chosen_ipa_bit_size = pa_range;
> 
> +#ifdef MAC_OS_VERSION_26_0
> +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0
> +    if (__builtin_available(macOS 26, *)) {
> +        ret = hv_vm_config_set_ipa_granule(config, HV_IPA_GRANULE_4KB);
> +        if (ret != HV_SUCCESS) {
> +            error_report("HVF: failed to set 4KB IPA granule: %s",
> +                         hvf_return_string(ret));
> +            goto cleanup;
> +        }
> +        hvf_set_map_granule(4096);
> +    }
> +#endif
> +#endif

Hello,

Not really happy about having this as a default… I see a double digit perf impact on compilation workloads here.
So having this as an optional, off by default option sounds best.

Thank you,
-Mohamed
> +
>     ret = hv_vm_create(config);
> 
> cleanup:
> -- 
> 2.52.0
> 
> 



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 0/2] hvf: map granule abstraction and configurable IPA
  2026-03-09 21:49 [PATCH 0/2] hvf: map granule abstraction and macOS 26 4KB IPA Lucas Amaral
  2026-03-09 21:49 ` [PATCH 1/2] accel/hvf: introduce map granule abstraction Lucas Amaral
  2026-03-09 21:49 ` [PATCH 2/2] target/arm/hvf: set 4KB IPA granule on macOS 26 Lucas Amaral
@ 2026-03-11  2:27 ` Lucas Amaral
  2026-03-11  2:27   ` [PATCH v2 1/2] accel/hvf: introduce map granule abstraction and IPA property Lucas Amaral
                     ` (2 more replies)
  2 siblings, 3 replies; 13+ messages in thread
From: Lucas Amaral @ 2026-03-11  2:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Lucas Amaral

macOS ARM64 requires 16KB alignment for hv_vm_map(), but the guest
kernel uses 4KB pages.  When virtio-gpu blob BAR offsets are not
16KB-aligned, the interior-mapping path fails, falling back to slow
MMIO emulation.

This series introduces:

1. A map granule abstraction (hvf_set/get_map_granule) replacing
   hardcoded qemu_real_host_page_size() calls in HVF memory mapping.
   Non-aligned regions return early instead of proceeding with
   add=false (which attempted an unnecessary unmap).
   An 'ipa-granule' property (auto, 4k, 16k) on the HVF accelerator
   object allows opt-in configuration:

     -accel hvf,ipa-granule=4k

2. macOS 26 IPA granule support via hv_vm_config_set_ipa_granule(),
   reading the ipa-granule property to select HV_IPA_GRANULE_4KB or
   HV_IPA_GRANULE_16KB.  Falls back with a warning on macOS < 26.
   Warns if the resolved granule exceeds the guest page size (Venus
   blob mapping safety check).

Dependencies: none.

Changes v1 → v2 (Mohamed Mosaad review):
- Replace hardcoded 4KB with configurable ipa-granule property
  (auto, 4k, 16k) on the HVF accelerator object.
- 'auto' defaults to host page size; explicit values opt in.
- Add fallback warning when macOS < 26 can't honor the request.
- Add Venus blob mapping safety warning (moved from venus-nogl
  series to keep cross-series independence).
- Use KiB constants instead of magic numbers.

Lucas Amaral (2):
  accel/hvf: introduce map granule abstraction and IPA property
  target/arm/hvf: configure IPA granule on macOS 26

 accel/hvf/hvf-all.c      | 67 ++++++++++++++++++++++++++++++++++++++--
 include/system/hvf.h     | 15 +++++++++
 include/system/hvf_int.h |  1 +
 target/arm/hvf/hvf.c     | 49 +++++++++++++++++++++++++++++
 4 files changed, 129 insertions(+), 3 deletions(-)

--
2.52.0



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 1/2] accel/hvf: introduce map granule abstraction and IPA property
  2026-03-11  2:27 ` [PATCH v2 0/2] hvf: map granule abstraction and configurable IPA Lucas Amaral
@ 2026-03-11  2:27   ` Lucas Amaral
  2026-03-11  4:38     ` Mohamed Mediouni
  2026-03-11  2:27   ` [PATCH v2 2/2] target/arm/hvf: configure IPA granule on macOS 26 Lucas Amaral
  2026-03-15  3:41   ` [PATCH v3 0/3] hvf: map granule abstraction, configurable IPA, and MAP_FIXED alignment fix Lucas Amaral
  2 siblings, 1 reply; 13+ messages in thread
From: Lucas Amaral @ 2026-03-11  2:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Lucas Amaral

Replace hardcoded qemu_real_host_page_size() in HVF memory mapping
with a configurable map granule.  Non-aligned regions now return
early instead of proceeding with add=false.

Add an 'ipa-granule' property (auto, 4k, 16k) on the HVF accelerator
object for aarch64, allowing the user to select the IPA page granule
for HVF stage-2 address translation:

  -accel hvf,ipa-granule=4k

'auto' (the default) resolves to the host page size (16KB on macOS
ARM64).  The actual HVF configuration is handled by the arch-specific
hvf_arch_vm_create() in a subsequent patch.

Signed-off-by: Lucas Amaral <lucaaamaral@gmail.com>
---
 accel/hvf/hvf-all.c      | 67 ++++++++++++++++++++++++++++++++++++++--
 include/system/hvf.h     | 15 +++++++++
 include/system/hvf_int.h |  1 +
 3 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c
index 033c677..d94926b 100644
--- a/accel/hvf/hvf-all.c
+++ b/accel/hvf/hvf-all.c
@@ -10,6 +10,8 @@
 
 #include "qemu/osdep.h"
 #include "qemu/error-report.h"
+#include "qemu/units.h"
+#include "qapi/error.h"
 #include "accel/accel-ops.h"
 #include "exec/cpu-common.h"
 #include "system/address-spaces.h"
@@ -23,6 +25,21 @@
 
 bool hvf_allowed;
 
+static uint64_t hvf_map_granule;
+
+void hvf_set_map_granule(uint64_t size)
+{
+    hvf_map_granule = size;
+}
+
+uint64_t hvf_get_map_granule(void)
+{
+    if (!hvf_map_granule) {
+        return qemu_real_host_page_size();
+    }
+    return hvf_map_granule;
+}
+
 const char *hvf_return_string(hv_return_t ret)
 {
     switch (ret) {
@@ -54,7 +71,7 @@ void assert_hvf_ok_impl(hv_return_t ret, const char *file, unsigned int line,
 static void do_hv_vm_protect(hwaddr start, size_t size,
                              hv_memory_flags_t flags)
 {
-    intptr_t page_mask = qemu_real_host_page_mask();
+    intptr_t page_mask = -(intptr_t)hvf_get_map_granule();
     hv_return_t ret;
 
     trace_hvf_vm_protect(start, size, flags,
@@ -84,7 +101,7 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
     MemoryRegion *area = section->mr;
     bool writable = !area->readonly && !area->rom_device;
     hv_memory_flags_t flags;
-    uint64_t page_size = qemu_real_host_page_size();
+    uint64_t page_size = hvf_get_map_granule();
     uint64_t gpa = section->offset_within_address_space;
     uint64_t size = int128_get64(section->size);
     hv_return_t ret;
@@ -105,7 +122,7 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
     if (!QEMU_IS_ALIGNED(size, page_size) ||
         !QEMU_IS_ALIGNED(gpa, page_size)) {
         /* Not page aligned, so we can not map as RAM */
-        add = false;
+        return;
     }
 
     if (!add) {
@@ -187,6 +204,11 @@ static int hvf_accel_init(AccelState *as, MachineState *ms)
     int pa_range = 36;
     MachineClass *mc = MACHINE_GET_CLASS(ms);
 
+    /* Resolve ipa-granule=auto → host page size */
+    if (!s->ipa_granule) {
+        s->ipa_granule = qemu_real_host_page_size();
+    }
+    hvf_set_map_granule(s->ipa_granule);
 
     if (mc->get_physical_address_range) {
         pa_range = mc->get_physical_address_range(ms,
@@ -217,6 +239,37 @@ static int hvf_gdbstub_sstep_flags(AccelState *as)
     return SSTEP_ENABLE | SSTEP_NOIRQ;
 }
 
+#ifdef __aarch64__
+static char *hvf_get_ipa_granule(Object *obj, Error **errp)
+{
+    HVFState *s = HVF_STATE(obj);
+
+    if (s->ipa_granule == 4 * KiB) {
+        return g_strdup("4k");
+    }
+    if (s->ipa_granule == 16 * KiB) {
+        return g_strdup("16k");
+    }
+    return g_strdup("auto");
+}
+
+static void hvf_set_ipa_granule(Object *obj, const char *value, Error **errp)
+{
+    HVFState *s = HVF_STATE(obj);
+
+    if (!strcmp(value, "auto")) {
+        s->ipa_granule = 0;
+    } else if (!strcmp(value, "4k")) {
+        s->ipa_granule = 4 * KiB;
+    } else if (!strcmp(value, "16k")) {
+        s->ipa_granule = 16 * KiB;
+    } else {
+        error_setg(errp, "invalid ipa-granule: '%s' (use auto, 4k, 16k)",
+                   value);
+    }
+}
+#endif /* __aarch64__ */
+
 static void hvf_accel_class_init(ObjectClass *oc, const void *data)
 {
     AccelClass *ac = ACCEL_CLASS(oc);
@@ -224,6 +277,14 @@ static void hvf_accel_class_init(ObjectClass *oc, const void *data)
     ac->init_machine = hvf_accel_init;
     ac->allowed = &hvf_allowed;
     ac->gdbstub_supported_sstep_flags = hvf_gdbstub_sstep_flags;
+
+#ifdef __aarch64__
+    object_class_property_add_str(oc, "ipa-granule",
+                                  hvf_get_ipa_granule,
+                                  hvf_set_ipa_granule);
+    object_class_property_set_description(oc, "ipa-granule",
+        "IPA granule for HVF stage-2 translation (auto, 4k, 16k)");
+#endif
 }
 
 static const TypeInfo hvf_accel_type = {
diff --git a/include/system/hvf.h b/include/system/hvf.h
index d3dcf08..d1b702b 100644
--- a/include/system/hvf.h
+++ b/include/system/hvf.h
@@ -36,4 +36,19 @@ typedef struct HVFState HVFState;
 DECLARE_INSTANCE_CHECKER(HVFState, HVF_STATE,
                          TYPE_HVF_ACCEL)
 
+#ifdef CONFIG_HVF_IS_POSSIBLE
+/*
+ * Minimum alignment for hv_vm_map(). Returns host page size (16KB on
+ * macOS ARM64), or 4KB when HVF 4KB IPA granule is configured (macOS 26+).
+ */
+void hvf_set_map_granule(uint64_t size);
+uint64_t hvf_get_map_granule(void);
+#else
+static inline void hvf_set_map_granule(uint64_t size) {}
+static inline uint64_t hvf_get_map_granule(void)
+{
+    return qemu_real_host_page_size();
+}
+#endif
+
 #endif
diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h
index 2621164..4c1caba 100644
--- a/include/system/hvf_int.h
+++ b/include/system/hvf_int.h
@@ -38,6 +38,7 @@ struct HVFState {
 
     hvf_vcpu_caps *hvf_caps;
     uint64_t vtimer_offset;
+    uint32_t ipa_granule;
     QTAILQ_HEAD(, hvf_sw_breakpoint) hvf_sw_breakpoints;
 };
 extern HVFState *hvf_state;
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 2/2] target/arm/hvf: configure IPA granule on macOS 26
  2026-03-11  2:27 ` [PATCH v2 0/2] hvf: map granule abstraction and configurable IPA Lucas Amaral
  2026-03-11  2:27   ` [PATCH v2 1/2] accel/hvf: introduce map granule abstraction and IPA property Lucas Amaral
@ 2026-03-11  2:27   ` Lucas Amaral
  2026-03-11  4:41     ` Mohamed Mediouni
  2026-03-15  3:41   ` [PATCH v3 0/3] hvf: map granule abstraction, configurable IPA, and MAP_FIXED alignment fix Lucas Amaral
  2 siblings, 1 reply; 13+ messages in thread
From: Lucas Amaral @ 2026-03-11  2:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Lucas Amaral

Read the ipa-granule property (set by hvf_accel_init) and configure
the HVF stage-2 translation granule via hv_vm_config_set_ipa_granule()
on macOS 26+.  When ipa-granule=4k, use HV_IPA_GRANULE_4KB to allow
HVF to map memory at 4KB granularity, matching 4KB-page guests.

If macOS < 26 and a sub-host-page granule was requested, warn and
fall back to the host page size (16KB).

After resolution, warn if the map granule exceeds the guest page size,
as Venus blob BAR mappings require page-aligned offsets.

Signed-off-by: Lucas Amaral <lucaaamaral@gmail.com>
---
 target/arm/hvf/hvf.c | 49 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 7952b01..a6f139d 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -11,7 +11,9 @@
 
 #include "qemu/osdep.h"
 #include "qemu/error-report.h"
+#include "qemu/units.h"
 #include "qemu/log.h"
+#include "exec/target_page.h"
 
 #include "system/runstate.h"
 #include "system/hvf.h"
@@ -960,6 +962,53 @@ hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range)
     }
     chosen_ipa_bit_size = pa_range;
 
+    /*
+     * Configure IPA granule from the ipa-granule property.
+     * hvf_get_map_granule() was set by hvf_accel_init() before this call.
+     */
+    {
+        uint64_t granule = hvf_get_map_granule();
+        bool granule_set = false;
+
+#ifdef MAC_OS_VERSION_26_0
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0
+        if (__builtin_available(macOS 26, *)) {
+            hv_ipa_granule_t hv_gran = (granule <= 4 * KiB)
+                ? HV_IPA_GRANULE_4KB : HV_IPA_GRANULE_16KB;
+            ret = hv_vm_config_set_ipa_granule(config, hv_gran);
+            if (ret != HV_SUCCESS) {
+                error_report("HVF: failed to set IPA granule: %s",
+                             hvf_return_string(ret));
+                goto cleanup;
+            }
+            granule_set = true;
+        }
+#endif
+#endif
+
+        if (!granule_set && granule < qemu_real_host_page_size()) {
+            warn_report("HVF: ipa-granule=%zuKB requested but macOS < 26; "
+                        "falling back to host page size (%zuKB)",
+                        (size_t)(granule / KiB),
+                        (size_t)(qemu_real_host_page_size() / KiB));
+            hvf_set_map_granule(qemu_real_host_page_size());
+        }
+
+        /*
+         * Venus blob mapping safety: warn if the resolved map granule
+         * exceeds the guest page size, as virtio-gpu blob BAR mappings
+         * require page-aligned offsets and would hang otherwise.
+         */
+        if (hvf_get_map_granule() > qemu_target_page_size()) {
+            warn_report("HVF map granule (%zu) > guest page size (%zu); "
+                        "Venus blob BAR mappings may hang. "
+                        "Consider ipa-granule=4k (requires macOS 26+) or "
+                        "guest F_BLOB_ALIGNMENT support.",
+                        (size_t)hvf_get_map_granule(),
+                        qemu_target_page_size());
+        }
+    }
+
     ret = hv_vm_create(config);
 
 cleanup:
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 1/2] accel/hvf: introduce map granule abstraction and IPA property
  2026-03-11  2:27   ` [PATCH v2 1/2] accel/hvf: introduce map granule abstraction and IPA property Lucas Amaral
@ 2026-03-11  4:38     ` Mohamed Mediouni
  0 siblings, 0 replies; 13+ messages in thread
From: Mohamed Mediouni @ 2026-03-11  4:38 UTC (permalink / raw)
  To: Lucas Amaral; +Cc: qemu-devel, qemu-arm



> On 11. Mar 2026, at 03:27, Lucas Amaral <lucaaamaral@gmail.com> wrote:
> 
> Replace hardcoded qemu_real_host_page_size() in HVF memory mapping
> with a configurable map granule.  Non-aligned regions now return
> early instead of proceeding with add=false.
> 
> Add an 'ipa-granule' property (auto, 4k, 16k) on the HVF accelerator
> object for aarch64, allowing the user to select the IPA page granule
> for HVF stage-2 address translation:
> 
>  -accel hvf,ipa-granule=4k
> 
> 'auto' (the default) resolves to the host page size (16KB on macOS
> ARM64).  The actual HVF configuration is handled by the arch-specific
> hvf_arch_vm_create() in a subsequent patch.
> 
> Signed-off-by: Lucas Amaral <lucaaamaral@gmail.com>
> ---
> accel/hvf/hvf-all.c      | 67 ++++++++++++++++++++++++++++++++++++++--
> include/system/hvf.h     | 15 +++++++++
> include/system/hvf_int.h |  1 +
> 3 files changed, 80 insertions(+), 3 deletions(-)
> 
> diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c
> index 033c677..d94926b 100644
> --- a/accel/hvf/hvf-all.c
> +++ b/accel/hvf/hvf-all.c
> @@ -10,6 +10,8 @@
> 
> #include "qemu/osdep.h"
> #include "qemu/error-report.h"
> +#include "qemu/units.h"
> +#include "qapi/error.h"
> #include "accel/accel-ops.h"
> #include "exec/cpu-common.h"
> #include "system/address-spaces.h"
> @@ -23,6 +25,21 @@
> 
> bool hvf_allowed;
> 
> +static uint64_t hvf_map_granule;
> +
> +void hvf_set_map_granule(uint64_t size)
> +{
> +    hvf_map_granule = size;
> +}
> +
> +uint64_t hvf_get_map_granule(void)
> +{
> +    if (!hvf_map_granule) {
> +        return qemu_real_host_page_size();
> +    }
> +    return hvf_map_granule;
> +}
> +
> const char *hvf_return_string(hv_return_t ret)
> {
>     switch (ret) {
> @@ -54,7 +71,7 @@ void assert_hvf_ok_impl(hv_return_t ret, const char *file, unsigned int line,
> static void do_hv_vm_protect(hwaddr start, size_t size,
>                              hv_memory_flags_t flags)
> {
> -    intptr_t page_mask = qemu_real_host_page_mask();
> +    intptr_t page_mask = -(intptr_t)hvf_get_map_granule();
>     hv_return_t ret;
> 
>     trace_hvf_vm_protect(start, size, flags,
> @@ -84,7 +101,7 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
>     MemoryRegion *area = section->mr;
>     bool writable = !area->readonly && !area->rom_device;
>     hv_memory_flags_t flags;
> -    uint64_t page_size = qemu_real_host_page_size();
> +    uint64_t page_size = hvf_get_map_granule();
>     uint64_t gpa = section->offset_within_address_space;
>     uint64_t size = int128_get64(section->size);
>     hv_return_t ret;
> @@ -105,7 +122,7 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
>     if (!QEMU_IS_ALIGNED(size, page_size) ||
>         !QEMU_IS_ALIGNED(gpa, page_size)) {
>         /* Not page aligned, so we can not map as RAM */
> -        add = false;
> +        return;
>     }
> 
>     if (!add) {
> @@ -187,6 +204,11 @@ static int hvf_accel_init(AccelState *as, MachineState *ms)
>     int pa_range = 36;
>     MachineClass *mc = MACHINE_GET_CLASS(ms);
> 
> +    /* Resolve ipa-granule=auto → host page size */
> +    if (!s->ipa_granule) {
> +        s->ipa_granule = qemu_real_host_page_size();
> +    }
> +    hvf_set_map_granule(s->ipa_granule);
> 
>     if (mc->get_physical_address_range) {
>         pa_range = mc->get_physical_address_range(ms,
> @@ -217,6 +239,37 @@ static int hvf_gdbstub_sstep_flags(AccelState *as)
>     return SSTEP_ENABLE | SSTEP_NOIRQ;
> }
> 
> +#ifdef __aarch64__
Hello,

checkpatch will warn on this, maybe this should be in a separate potential hvf_arch_accel_init?

> +static char *hvf_get_ipa_granule(Object *obj, Error **errp)
> +{
> +    HVFState *s = HVF_STATE(obj);
> +
> +    if (s->ipa_granule == 4 * KiB) {
> +        return g_strdup("4k");
> +    }
> +    if (s->ipa_granule == 16 * KiB) {
> +        return g_strdup("16k");
> +    }
> +    return g_strdup("auto");
> +}
> +
> +static void hvf_set_ipa_granule(Object *obj, const char *value, Error **errp)
> +{
> +    HVFState *s = HVF_STATE(obj);
> +
> +    if (!strcmp(value, "auto")) {
> +        s->ipa_granule = 0;
> +    } else if (!strcmp(value, "4k")) {
> +        s->ipa_granule = 4 * KiB;
> +    } else if (!strcmp(value, "16k")) {
> +        s->ipa_granule = 16 * KiB;
> +    } else {
> +        error_setg(errp, "invalid ipa-granule: '%s' (use auto, 4k, 16k)",
> +                   value);
> +    }
> +}
> +#endif /* __aarch64__ */
> +
> static void hvf_accel_class_init(ObjectClass *oc, const void *data)
> {
>     AccelClass *ac = ACCEL_CLASS(oc);
> @@ -224,6 +277,14 @@ static void hvf_accel_class_init(ObjectClass *oc, const void *data)
>     ac->init_machine = hvf_accel_init;
>     ac->allowed = &hvf_allowed;
>     ac->gdbstub_supported_sstep_flags = hvf_gdbstub_sstep_flags;
> +
> +#ifdef __aarch64__
> +    object_class_property_add_str(oc, "ipa-granule",
> +                                  hvf_get_ipa_granule,
> +                                  hvf_set_ipa_granule);
> +    object_class_property_set_description(oc, "ipa-granule",
> +        "IPA granule for HVF stage-2 translation (auto, 4k, 16k)");
> +#endif
> }
> 
> static const TypeInfo hvf_accel_type = {
> diff --git a/include/system/hvf.h b/include/system/hvf.h
> index d3dcf08..d1b702b 100644
> --- a/include/system/hvf.h
> +++ b/include/system/hvf.h
> @@ -36,4 +36,19 @@ typedef struct HVFState HVFState;
> DECLARE_INSTANCE_CHECKER(HVFState, HVF_STATE,
>                          TYPE_HVF_ACCEL)
> 
> +#ifdef CONFIG_HVF_IS_POSSIBLE
> +/*
> + * Minimum alignment for hv_vm_map(). Returns host page size (16KB on
> + * macOS ARM64), or 4KB when HVF 4KB IPA granule is configured (macOS 26+).
> + */
> +void hvf_set_map_granule(uint64_t size);
> +uint64_t hvf_get_map_granule(void);
> +#else
> +static inline void hvf_set_map_granule(uint64_t size) {}
> +static inline uint64_t hvf_get_map_granule(void)
> +{
> +    return qemu_real_host_page_size();
> +}
> +#endif
> +
> #endif
> diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h
> index 2621164..4c1caba 100644
> --- a/include/system/hvf_int.h
> +++ b/include/system/hvf_int.h
> @@ -38,6 +38,7 @@ struct HVFState {
> 
>     hvf_vcpu_caps *hvf_caps;
>     uint64_t vtimer_offset;
> +    uint32_t ipa_granule;
>     QTAILQ_HEAD(, hvf_sw_breakpoint) hvf_sw_breakpoints;
> };
> extern HVFState *hvf_state;
> -- 
> 2.52.0
> 
> 



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 2/2] target/arm/hvf: configure IPA granule on macOS 26
  2026-03-11  2:27   ` [PATCH v2 2/2] target/arm/hvf: configure IPA granule on macOS 26 Lucas Amaral
@ 2026-03-11  4:41     ` Mohamed Mediouni
  0 siblings, 0 replies; 13+ messages in thread
From: Mohamed Mediouni @ 2026-03-11  4:41 UTC (permalink / raw)
  To: Lucas Amaral; +Cc: qemu-devel, qemu-arm



> On 11. Mar 2026, at 03:27, Lucas Amaral <lucaaamaral@gmail.com> wrote:
> 
> Read the ipa-granule property (set by hvf_accel_init) and configure
> the HVF stage-2 translation granule via hv_vm_config_set_ipa_granule()
> on macOS 26+.  When ipa-granule=4k, use HV_IPA_GRANULE_4KB to allow
> HVF to map memory at 4KB granularity, matching 4KB-page guests.
> 
> If macOS < 26 and a sub-host-page granule was requested, warn and
> fall back to the host page size (16KB).
> 
> After resolution, warn if the map granule exceeds the guest page size,
> as Venus blob BAR mappings require page-aligned offsets.
> 
> Signed-off-by: Lucas Amaral <lucaaamaral@gmail.com>
> ---
> target/arm/hvf/hvf.c | 49 ++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 49 insertions(+)
> 
> diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
> index 7952b01..a6f139d 100644
> --- a/target/arm/hvf/hvf.c
> +++ b/target/arm/hvf/hvf.c
> @@ -11,7 +11,9 @@
> 
> #include "qemu/osdep.h"
> #include "qemu/error-report.h"
> +#include "qemu/units.h"
> #include "qemu/log.h"
> +#include "exec/target_page.h"
> 
> #include "system/runstate.h"
> #include "system/hvf.h"
> @@ -960,6 +962,53 @@ hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range)
>     }
>     chosen_ipa_bit_size = pa_range;
> 
> +    /*
> +     * Configure IPA granule from the ipa-granule property.
> +     * hvf_get_map_granule() was set by hvf_accel_init() before this call.
> +     */
> +    {
> +        uint64_t granule = hvf_get_map_granule();
> +        bool granule_set = false;
> +
> +#ifdef MAC_OS_VERSION_26_0
> +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0
Cosmetic:

#if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 260000)

To match hvf_sme_stubs.h
> 
> +        if (__builtin_available(macOS 26, *)) {
> +            hv_ipa_granule_t hv_gran = (granule <= 4 * KiB)
> +                ? HV_IPA_GRANULE_4KB : HV_IPA_GRANULE_16KB;
> +            ret = hv_vm_config_set_ipa_granule(config, hv_gran);
> +            if (ret != HV_SUCCESS) {
> +                error_report("HVF: failed to set IPA granule: %s",
> +                             hvf_return_string(ret));
> +                goto cleanup;
> +            }
> +            granule_set = true;
> +        }
…and a single endif
> +#endif
> +#endif
> +
> +        if (!granule_set && granule < qemu_real_host_page_size()) {
> +            warn_report("HVF: ipa-granule=%zuKB requested but macOS < 26; "
> +                        "falling back to host page size (%zuKB)",
> +                        (size_t)(granule / KiB),
> +                        (size_t)(qemu_real_host_page_size() / KiB));
> +            hvf_set_map_granule(qemu_real_host_page_size());
> +        }
> +        /*
> +         * Venus blob mapping safety: warn if the resolved map granule
> +         * exceeds the guest page size, as virtio-gpu blob BAR mappings
> +         * require page-aligned offsets and would hang otherwise.
> +         */
> +        if (hvf_get_map_granule() > qemu_target_page_size()) {
> +            warn_report("HVF map granule (%zu) > guest page size (%zu); "
> +                        "Venus blob BAR mappings may hang. "
> +                        "Consider ipa-granule=4k (requires macOS 26+) or "
> +                        "guest F_BLOB_ALIGNMENT support.",
> +                        (size_t)hvf_get_map_granule(),
> +                        qemu_target_page_size());
> +        }
The warning below doesn’t have much sense to have here I think.
At least not in this form.

With that warning removed: 

Reviewed-by: Mohamed Mediouni <mohamed@unpredictable.fr>
> +    }
> +
>     ret = hv_vm_create(config);
> 
> cleanup:
> -- 
> 2.52.0
> 
> 



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 0/3] hvf: map granule abstraction, configurable IPA, and MAP_FIXED alignment fix
  2026-03-11  2:27 ` [PATCH v2 0/2] hvf: map granule abstraction and configurable IPA Lucas Amaral
  2026-03-11  2:27   ` [PATCH v2 1/2] accel/hvf: introduce map granule abstraction and IPA property Lucas Amaral
  2026-03-11  2:27   ` [PATCH v2 2/2] target/arm/hvf: configure IPA granule on macOS 26 Lucas Amaral
@ 2026-03-15  3:41   ` Lucas Amaral
  2026-03-15  3:41     ` [PATCH 1/3] virtio-gpu: validate host page alignment for MAP_FIXED blobs Lucas Amaral
                       ` (2 more replies)
  2 siblings, 3 replies; 13+ messages in thread
From: Lucas Amaral @ 2026-03-15  3:41 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Lucas Amaral

Fix a bug in the MAP_FIXED blob mapping path (introduced by 4eb0aace)
where non-host-page-aligned offsets cause mmap(MAP_FIXED) to fail with
EINVAL.  This affects any host where the page size exceeds the guest's
(ARM64 with 16KB/64KB pages, macOS ARM64).

This series introduces:

1. MAP_FIXED alignment validation in virtio-gpu: check that both
   offset and blob size are aligned to the host page size before
   calling virgl_renderer_resource_map_fixed().  When not aligned,
   fall through to the subregion method (which works at any
   alignment).

2. A map granule abstraction (hvf_set/get_map_granule) replacing
   hardcoded qemu_real_host_page_size() calls in HVF memory mapping.
   Non-aligned regions return early instead of proceeding with
   add=false (which attempted an unnecessary unmap).
   An 'ipa-granule' property (auto, 4k, 16k) on the HVF accelerator
   object allows opt-in configuration:

     -accel hvf,ipa-granule=4k

   The property follows the kvm_arch_accel_class_init() pattern:
   ARM registers the property in hvf_arch_accel_class_init(), x86
   provides an empty stub.

3. macOS 26 IPA granule support via hv_vm_config_set_ipa_granule(),
   reading the ipa-granule property to select HV_IPA_GRANULE_4KB or
   HV_IPA_GRANULE_16KB.  Falls back with a warning on macOS < 26.

Dependencies: none.

Changes v2 → v3:
  - Rebased on current master
  - Add MAP_FIXED alignment validation (new patch 1)
  - Move #ifdef __aarch64__ property code into hvf_arch_accel_class_init
    following kvm_arch_accel_class_init() pattern (x86 empty stub)
  - Use MAC_OS_VERSION_26_0 named constant
  - Remove Venus blob mapping warning

Changes v1 → v2 (Mohamed Mosaad review):
  - Replace hardcoded 4KB with configurable ipa-granule property
    (auto, 4k, 16k) on the HVF accelerator object.
  - 'auto' defaults to host page size; explicit values opt in.
  - Add fallback warning when macOS < 26 can't honor the request.
  - Add Venus blob mapping safety warning.
  - Use KiB constants instead of magic numbers.

Lucas Amaral (3):
  virtio-gpu: validate host page alignment for MAP_FIXED blobs
  accel/hvf: introduce map granule abstraction and IPA property
  target/arm/hvf: configure IPA granule on macOS 26

 accel/hvf/hvf-all.c           | 30 +++++++++++++--
 hw/display/virtio-gpu-virgl.c | 45 +++++++++++++---------
 include/system/hvf.h          | 15 ++++++++
 include/system/hvf_int.h      |  2 +
 target/arm/hvf/hvf.c          | 72 +++++++++++++++++++++++++++++++++++
 target/i386/hvf/hvf.c         |  4 ++
 6 files changed, 147 insertions(+), 21 deletions(-)

--
2.52.0



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/3] virtio-gpu: validate host page alignment for MAP_FIXED blobs
  2026-03-15  3:41   ` [PATCH v3 0/3] hvf: map granule abstraction, configurable IPA, and MAP_FIXED alignment fix Lucas Amaral
@ 2026-03-15  3:41     ` Lucas Amaral
  2026-03-15  3:41     ` [PATCH 2/3] accel/hvf: introduce map granule abstraction and IPA property Lucas Amaral
  2026-03-15  3:41     ` [PATCH 3/3] target/arm/hvf: configure IPA granule on macOS 26 Lucas Amaral
  2 siblings, 0 replies; 13+ messages in thread
From: Lucas Amaral @ 2026-03-15  3:41 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Lucas Amaral

Commit 4eb0aace ("virtio-gpu: Support mapping hostmem blobs with
map_fixed") uses mmap(MAP_FIXED) to map blob resources into a
pre-allocated hostmem region.  Both the offset and size passed to
mmap must be aligned to the host page size, but the code does not
validate this.

On hosts where qemu_real_host_page_size() exceeds the guest's page
size (e.g. ARM64 with 16KB or 64KB pages, macOS ARM64), the guest
may provide blob offsets aligned to its own page size (4KB) but not
to the host's.  This causes mmap(MAP_FIXED) to fail with EINVAL,
and the subsequent unmap (which also uses mmap MAP_FIXED) fails the
same way, producing:

  virtio_gpu_virgl_unmap_resource_blob: failed to unmap(fixed)
  virgl resource: Invalid argument

Add an alignment check before attempting MAP_FIXED.  When the offset
or blob size is not host-page-aligned, skip the MAP_FIXED path and
fall through to the existing subregion method, which handles any
alignment.

Fixes: 4eb0aace ("virtio-gpu: Support mapping hostmem blobs with map_fixed")
Signed-off-by: Lucas Amaral <lucaaamaral@gmail.com>
---
 hw/display/virtio-gpu-virgl.c | 45 +++++++++++++++++++++--------------
 1 file changed, 27 insertions(+), 18 deletions(-)

diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index b7a2d160..f6583b48 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -185,25 +185,34 @@ virtio_gpu_virgl_map_resource_blob(VirtIOGPU *g,
         return -EBUSY;
     }
 
-    ret = virgl_renderer_resource_map_fixed(res->base.resource_id,
-                                            gl->hostmem_mmap + offset);
-    switch (ret) {
-    case 0:
-        res->map_fixed = gl->hostmem_mmap + offset;
-        return 0;
-
-    case -EOPNOTSUPP:
-        /*
-         * MAP_FIXED is unsupported by this resource.
-         * Mapping falls back to a blob subregion method in that case.
-         */
-        break;
+    /*
+     * MAP_FIXED requires host-page-aligned offset and size.  Hosts with
+     * page sizes larger than the guest's (e.g. 16KB on ARM64) may receive
+     * non-aligned blob offsets.  Fall through to the subregion method when
+     * alignment requirements are not met.
+     */
+    if (QEMU_IS_ALIGNED(offset, qemu_real_host_page_size()) &&
+        QEMU_IS_ALIGNED(res->base.blob_size, qemu_real_host_page_size())) {
+        ret = virgl_renderer_resource_map_fixed(res->base.resource_id,
+                                                gl->hostmem_mmap + offset);
+        switch (ret) {
+        case 0:
+            res->map_fixed = gl->hostmem_mmap + offset;
+            return 0;
+
+        case -EOPNOTSUPP:
+            /*
+             * MAP_FIXED is unsupported by this resource.
+             * Mapping falls back to a blob subregion method in that case.
+             */
+            break;
 
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "%s: failed to map(fixed) virgl resource: %s\n",
-                      __func__, strerror(-ret));
-        return ret;
+        default:
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: failed to map(fixed) virgl resource: %s\n",
+                          __func__, strerror(-ret));
+            return ret;
+        }
     }
 #endif
 
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/3] accel/hvf: introduce map granule abstraction and IPA property
  2026-03-15  3:41   ` [PATCH v3 0/3] hvf: map granule abstraction, configurable IPA, and MAP_FIXED alignment fix Lucas Amaral
  2026-03-15  3:41     ` [PATCH 1/3] virtio-gpu: validate host page alignment for MAP_FIXED blobs Lucas Amaral
@ 2026-03-15  3:41     ` Lucas Amaral
  2026-03-15  3:41     ` [PATCH 3/3] target/arm/hvf: configure IPA granule on macOS 26 Lucas Amaral
  2 siblings, 0 replies; 13+ messages in thread
From: Lucas Amaral @ 2026-03-15  3:41 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Lucas Amaral, Lucas Amaral

Add a map granule abstraction that decouples HVF memory mapping
alignment from the host page size.  On ARM64, Apple Silicon supports
stage-2 translation with 4KB page granules regardless of the host OS
page size (16KB on macOS).  This allows running guests with 4KB pages
without interior mapping failures.

Introduce hvf_set_map_granule()/hvf_get_map_granule() in hvf-all.c
to replace hard-coded qemu_real_host_page_size() references in
do_hv_vm_protect() and hvf_set_phys_mem().  When the granule is not
explicitly configured, fall back to host page size to preserve the
previous behaviour.

Add an "ipa-granule" accelerator property (auto, 4k, 16k) following
the established kvm_arch_accel_class_init() pattern: ARM registers
the property in hvf_arch_accel_class_init(), x86 provides an empty
stub.  This avoids #ifdef __aarch64__ in common code while keeping
a single hvf-all.c shared by both targets.

Fix hvf_set_phys_mem() to return early for non-aligned regions instead
of clearing the add flag, which previously fell through to an
incorrect unmap of a region that was never mapped.

Signed-off-by: Lucas Amaral <lucas@lucasamaral.com>
---
 accel/hvf/hvf-all.c      | 30 +++++++++++++++++++++++++++---
 include/system/hvf.h     | 15 +++++++++++++++
 include/system/hvf_int.h |  2 ++
 target/arm/hvf/hvf.c     | 40 ++++++++++++++++++++++++++++++++++++++++
 target/i386/hvf/hvf.c    |  4 ++++
 5 files changed, 88 insertions(+), 3 deletions(-)

diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c
index 5f357c6d..d745fefd 100644
--- a/accel/hvf/hvf-all.c
+++ b/accel/hvf/hvf-all.c
@@ -10,6 +10,8 @@
 
 #include "qemu/osdep.h"
 #include "qemu/error-report.h"
+#include "qemu/units.h"
+#include "qapi/error.h"
 #include "accel/accel-ops.h"
 #include "exec/cpu-common.h"
 #include "system/address-spaces.h"
@@ -22,6 +24,21 @@
 
 bool hvf_allowed;
 
+static uint64_t hvf_map_granule;
+
+void hvf_set_map_granule(uint64_t size)
+{
+    hvf_map_granule = size;
+}
+
+uint64_t hvf_get_map_granule(void)
+{
+    if (!hvf_map_granule) {
+        return qemu_real_host_page_size();
+    }
+    return hvf_map_granule;
+}
+
 const char *hvf_return_string(hv_return_t ret)
 {
     switch (ret) {
@@ -53,7 +70,7 @@ void assert_hvf_ok_impl(hv_return_t ret, const char *file, unsigned int line,
 static void do_hv_vm_protect(hwaddr start, size_t size,
                              hv_memory_flags_t flags)
 {
-    intptr_t page_mask = qemu_real_host_page_mask();
+    intptr_t page_mask = -(intptr_t)hvf_get_map_granule();
     hv_return_t ret;
 
     trace_hvf_vm_protect(start, size, flags,
@@ -83,7 +100,7 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
     MemoryRegion *area = section->mr;
     bool writable = !area->readonly && !area->rom_device;
     hv_memory_flags_t flags;
-    uint64_t page_size = qemu_real_host_page_size();
+    uint64_t page_size = hvf_get_map_granule();
     uint64_t gpa = section->offset_within_address_space;
     uint64_t size = int128_get64(section->size);
     hv_return_t ret;
@@ -104,7 +121,7 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
     if (!QEMU_IS_ALIGNED(size, page_size) ||
         !QEMU_IS_ALIGNED(gpa, page_size)) {
         /* Not page aligned, so we can not map as RAM */
-        add = false;
+        return;
     }
 
     if (!add) {
@@ -186,6 +203,11 @@ static int hvf_accel_init(AccelState *as, MachineState *ms)
     int pa_range = 36;
     MachineClass *mc = MACHINE_GET_CLASS(ms);
 
+    /* Resolve ipa-granule=auto → host page size */
+    if (!s->ipa_granule) {
+        s->ipa_granule = qemu_real_host_page_size();
+    }
+    hvf_set_map_granule(s->ipa_granule);
 
     if (mc->get_physical_address_range) {
         pa_range = mc->get_physical_address_range(ms,
@@ -223,6 +245,8 @@ static void hvf_accel_class_init(ObjectClass *oc, const void *data)
     ac->init_machine = hvf_accel_init;
     ac->allowed = &hvf_allowed;
     ac->gdbstub_supported_sstep_flags = hvf_gdbstub_sstep_flags;
+
+    hvf_arch_accel_class_init(oc);
 }
 
 static const TypeInfo hvf_accel_type = {
diff --git a/include/system/hvf.h b/include/system/hvf.h
index d3dcf088..3c4c3b89 100644
--- a/include/system/hvf.h
+++ b/include/system/hvf.h
@@ -36,4 +36,19 @@ typedef struct HVFState HVFState;
 DECLARE_INSTANCE_CHECKER(HVFState, HVF_STATE,
                          TYPE_HVF_ACCEL)
 
+#ifdef CONFIG_HVF_IS_POSSIBLE
+/*
+ * Minimum alignment for hv_vm_map().  Returns the configured IPA granule
+ * or host page size if not set.
+ */
+void hvf_set_map_granule(uint64_t size);
+uint64_t hvf_get_map_granule(void);
+#else
+static inline void hvf_set_map_granule(uint64_t size) {}
+static inline uint64_t hvf_get_map_granule(void)
+{
+    return qemu_real_host_page_size();
+}
+#endif
+
 #endif
diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h
index 2621164c..9589b022 100644
--- a/include/system/hvf_int.h
+++ b/include/system/hvf_int.h
@@ -38,6 +38,7 @@ struct HVFState {
 
     hvf_vcpu_caps *hvf_caps;
     uint64_t vtimer_offset;
+    uint32_t ipa_granule;
     QTAILQ_HEAD(, hvf_sw_breakpoint) hvf_sw_breakpoints;
 };
 extern HVFState *hvf_state;
@@ -57,6 +58,7 @@ void assert_hvf_ok_impl(hv_return_t ret, const char *file, unsigned int line,
 const char *hvf_return_string(hv_return_t ret);
 int hvf_arch_init(void);
 hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range);
+void hvf_arch_accel_class_init(ObjectClass *oc);
 uint32_t hvf_arch_get_default_ipa_bit_size(void);
 uint32_t hvf_arch_get_max_ipa_bit_size(void);
 void hvf_kick_vcpu_thread(CPUState *cpu);
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 5fc8f6bb..1ba5bbf3 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -12,6 +12,8 @@
 #include "qemu/osdep.h"
 #include "qemu/error-report.h"
 #include "qemu/log.h"
+#include "qemu/units.h"
+#include "qapi/error.h"
 
 #include "system/runstate.h"
 #include "system/hvf.h"
@@ -1218,6 +1220,44 @@ void hvf_arch_vcpu_destroy(CPUState *cpu)
     assert_hvf_ok(ret);
 }
 
+static char *hvf_get_ipa_granule(Object *obj, Error **errp)
+{
+    HVFState *s = HVF_STATE(obj);
+
+    if (s->ipa_granule == 4 * KiB) {
+        return g_strdup("4k");
+    }
+    if (s->ipa_granule == 16 * KiB) {
+        return g_strdup("16k");
+    }
+    return g_strdup("auto");
+}
+
+static void hvf_set_ipa_granule(Object *obj, const char *value, Error **errp)
+{
+    HVFState *s = HVF_STATE(obj);
+
+    if (!strcmp(value, "auto")) {
+        s->ipa_granule = 0;
+    } else if (!strcmp(value, "4k")) {
+        s->ipa_granule = 4 * KiB;
+    } else if (!strcmp(value, "16k")) {
+        s->ipa_granule = 16 * KiB;
+    } else {
+        error_setg(errp, "invalid ipa-granule: '%s' (use auto, 4k, 16k)",
+                   value);
+    }
+}
+
+void hvf_arch_accel_class_init(ObjectClass *oc)
+{
+    object_class_property_add_str(oc, "ipa-granule",
+                                  hvf_get_ipa_granule,
+                                  hvf_set_ipa_granule);
+    object_class_property_set_description(oc, "ipa-granule",
+        "IPA granule for HVF stage-2 translation (auto, 4k, 16k)");
+}
+
 hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range)
 {
     hv_return_t ret;
diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c
index c0d028b1..565c79b3 100644
--- a/target/i386/hvf/hvf.c
+++ b/target/i386/hvf/hvf.c
@@ -228,6 +228,10 @@ int hvf_arch_init(void)
     return 0;
 }
 
+void hvf_arch_accel_class_init(ObjectClass *oc)
+{
+}
+
 /* 48-bit on all Intel Macs. Function currently unused. */
 uint32_t hvf_arch_get_default_ipa_bit_size(void)
 {
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/3] target/arm/hvf: configure IPA granule on macOS 26
  2026-03-15  3:41   ` [PATCH v3 0/3] hvf: map granule abstraction, configurable IPA, and MAP_FIXED alignment fix Lucas Amaral
  2026-03-15  3:41     ` [PATCH 1/3] virtio-gpu: validate host page alignment for MAP_FIXED blobs Lucas Amaral
  2026-03-15  3:41     ` [PATCH 2/3] accel/hvf: introduce map granule abstraction and IPA property Lucas Amaral
@ 2026-03-15  3:41     ` Lucas Amaral
  2 siblings, 0 replies; 13+ messages in thread
From: Lucas Amaral @ 2026-03-15  3:41 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Lucas Amaral, Lucas Amaral

Read the ipa-granule property (set by hvf_accel_init) and configure
the HVF stage-2 translation granule via hv_vm_config_set_ipa_granule()
on macOS 26+.  When ipa-granule=4k, use HV_IPA_GRANULE_4KB to allow
HVF to map memory at 4KB granularity, matching 4KB-page guests on
hosts with larger page sizes.

If macOS < 26 and a sub-host-page granule was requested, warn and
fall back to the host page size.

Signed-off-by: Lucas Amaral <lucas@lucasamaral.com>
---
 target/arm/hvf/hvf.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 1ba5bbf3..e3b1e3e1 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -1269,6 +1269,38 @@ hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range)
     }
     chosen_ipa_bit_size = pa_range;
 
+    /*
+     * Configure IPA granule from the ipa-granule property.
+     * hvf_get_map_granule() was set by hvf_accel_init() before this call.
+     */
+    {
+        uint64_t granule = hvf_get_map_granule();
+        bool granule_set = false;
+
+#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
+    (__MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0)
+        if (__builtin_available(macOS 26, *)) {
+            hv_ipa_granule_t hv_gran = (granule <= 4 * KiB)
+                ? HV_IPA_GRANULE_4KB : HV_IPA_GRANULE_16KB;
+            ret = hv_vm_config_set_ipa_granule(config, hv_gran);
+            if (ret != HV_SUCCESS) {
+                error_report("HVF: failed to set IPA granule: %s",
+                             hvf_return_string(ret));
+                goto cleanup;
+            }
+            granule_set = true;
+        }
+#endif
+
+        if (!granule_set && granule < qemu_real_host_page_size()) {
+            warn_report("HVF: ipa-granule=%zuKB requested but macOS < 26; "
+                        "falling back to host page size (%zuKB)",
+                        (size_t)(granule / KiB),
+                        (size_t)(qemu_real_host_page_size() / KiB));
+            hvf_set_map_granule(qemu_real_host_page_size());
+        }
+    }
+
     ret = hv_vm_create(config);
 
 cleanup:
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2026-03-15  3:43 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-09 21:49 [PATCH 0/2] hvf: map granule abstraction and macOS 26 4KB IPA Lucas Amaral
2026-03-09 21:49 ` [PATCH 1/2] accel/hvf: introduce map granule abstraction Lucas Amaral
2026-03-09 21:49 ` [PATCH 2/2] target/arm/hvf: set 4KB IPA granule on macOS 26 Lucas Amaral
2026-03-10  1:25   ` Mohamed Mediouni
2026-03-11  2:27 ` [PATCH v2 0/2] hvf: map granule abstraction and configurable IPA Lucas Amaral
2026-03-11  2:27   ` [PATCH v2 1/2] accel/hvf: introduce map granule abstraction and IPA property Lucas Amaral
2026-03-11  4:38     ` Mohamed Mediouni
2026-03-11  2:27   ` [PATCH v2 2/2] target/arm/hvf: configure IPA granule on macOS 26 Lucas Amaral
2026-03-11  4:41     ` Mohamed Mediouni
2026-03-15  3:41   ` [PATCH v3 0/3] hvf: map granule abstraction, configurable IPA, and MAP_FIXED alignment fix Lucas Amaral
2026-03-15  3:41     ` [PATCH 1/3] virtio-gpu: validate host page alignment for MAP_FIXED blobs Lucas Amaral
2026-03-15  3:41     ` [PATCH 2/3] accel/hvf: introduce map granule abstraction and IPA property Lucas Amaral
2026-03-15  3:41     ` [PATCH 3/3] target/arm/hvf: configure IPA granule on macOS 26 Lucas Amaral

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox