The IPA granule is the smallest page size hv_vm_map() support. For Venus, we need to support 4KiB pages. macOS 26 introduces a public API for setting the granule size. We can only use this when compiled with macOS 26 SDK and run on macOS 26+. Otherwise, we fall back to an older, private, API which achieves the same purpose.
Signed-off-by: Joelle van Dyne <[email protected]> --- include/system/hvf_int.h | 4 +++- accel/hvf/hvf-all.c | 42 ++++++++++++++++++++++++++++++++- target/arm/hvf/hvf.c | 50 +++++++++++++++++++++++++++++++++++++++- target/i386/hvf/hvf.c | 10 +++++++- 4 files changed, 102 insertions(+), 4 deletions(-) diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h index 1d2616595cd..881e16e31b6 100644 --- a/include/system/hvf_int.h +++ b/include/system/hvf_int.h @@ -63,6 +63,7 @@ struct HVFState { hvf_vcpu_caps *hvf_caps; uint64_t vtimer_offset; + uint32_t ipa_granule_size; QTAILQ_HEAD(, hvf_sw_breakpoint) hvf_sw_breakpoints; }; extern HVFState *hvf_state; @@ -82,7 +83,8 @@ void assert_hvf_ok_impl(hv_return_t ret, const char *file, unsigned int line, #define assert_hvf_ok(EX) assert_hvf_ok_impl((EX), __FILE__, __LINE__, #EX) 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); +hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range, + uint32_t ipa_granule_size); hvf_slot *hvf_find_overlap_slot(uint64_t, uint64_t); void hvf_kick_vcpu_thread(CPUState *cpu); diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c index a898359777c..7ebfc9bbe58 100644 --- a/accel/hvf/hvf-all.c +++ b/accel/hvf/hvf-all.c @@ -17,6 +17,8 @@ #include "system/hvf_int.h" #include "hw/core/cpu.h" #include "hw/boards.h" +#include "qapi/error.h" +#include "qapi/visitor.h" #include "trace.h" bool hvf_allowed; @@ -152,6 +154,10 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add) } } + if (hvf_state->ipa_granule_size) { + page_size = hvf_state->ipa_granule_size; + } + if (!QEMU_IS_ALIGNED(int128_get64(section->size), page_size) || !QEMU_IS_ALIGNED(section->offset_within_address_space, page_size)) { if (add) { @@ -316,7 +322,7 @@ static int hvf_accel_init(AccelState *as, MachineState *ms) } } - ret = hvf_arch_vm_create(ms, (uint32_t)pa_range); + ret = hvf_arch_vm_create(ms, (uint32_t)pa_range, s->ipa_granule_size); if (ret == HV_DENIED) { error_report("Could not access HVF. Is the executable signed" " with com.apple.security.hypervisor entitlement?"); @@ -340,6 +346,34 @@ static int hvf_gdbstub_sstep_flags(AccelState *as) return SSTEP_ENABLE | SSTEP_NOIRQ; } +static void hvf_get_ipa_granule_size(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + HVFState *s = HVF_STATE(obj); + uint32_t value = s->ipa_granule_size; + + visit_type_uint32(v, name, &value, errp); +} + +static void hvf_set_ipa_granule_size(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + HVFState *s = HVF_STATE(obj); + uint32_t value; + + if (!visit_type_uint32(v, name, &value, errp)) { + return; + } + if (value & (value - 1)) { + error_setg(errp, "ipa-granule-size must be a power of two."); + return; + } + + s->ipa_granule_size = value; +} + static void hvf_accel_class_init(ObjectClass *oc, const void *data) { AccelClass *ac = ACCEL_CLASS(oc); @@ -347,6 +381,12 @@ 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; + + object_class_property_add(oc, "ipa-granule-size", "uint32", + hvf_get_ipa_granule_size, hvf_set_ipa_granule_size, + NULL, NULL); + object_class_property_set_description(oc, "ipa-granule-size", + "Size of a single guest page"); } static const TypeInfo hvf_accel_type = { diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index de1e8fb8a05..7c44325ca64 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -12,6 +12,9 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "qemu/log.h" +#include <dlfcn.h> +#include <AvailabilityMacros.h> +#include <TargetConditionals.h> #include "system/runstate.h" #include "system/hvf.h" @@ -880,7 +883,45 @@ void hvf_arch_vcpu_destroy(CPUState *cpu) assert_hvf_ok(ret); } -hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range) +static hv_return_t hvf_set_ipa_granule(hv_vm_config_t config, + uint32_t ipa_granule_size) +{ + static hv_return_t (*set_ipa_granule)(hv_vm_config_t, uint32_t); + uint64_t page_size = qemu_real_host_page_size(); + + /* macOS 26 introduces a public API for setting granule size */ +#if defined(MAC_OS_X_VERSION_MAX_ALLOWED) && defined(MAC_OS_VERSION_26_0) && \ + MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0 + if (__builtin_available(macOS 26, *)) { + hv_ipa_granule_t granule = HV_IPA_GRANULE_16KB; + + if (ipa_granule_size == 4096) { + granule = HV_IPA_GRANULE_4KB; + } else if (ipa_granule_size != 16384) { + error_report("Unsupported granule size: 0x%x", ipa_granule_size); + return HV_UNSUPPORTED; + } + + return hv_vm_config_set_ipa_granule(config, granule); + } +#endif + + /* older macOS need to use a private API */ + if (!set_ipa_granule) { + set_ipa_granule = dlsym(RTLD_NEXT, "_hv_vm_config_set_ipa_granule"); + } + if (set_ipa_granule) { + return set_ipa_granule(config, ipa_granule_size); + } else if (ipa_granule_size != page_size) { + error_report("Failed to find _hv_vm_config_set_ipa_granule"); + return HV_UNSUPPORTED; + } + + return HV_SUCCESS; +} + +hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range, + uint32_t ipa_granule_size) { hv_return_t ret; hv_vm_config_t config = hv_vm_config_create(); @@ -891,6 +932,13 @@ hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range) } chosen_ipa_bit_size = pa_range; + if (ipa_granule_size) { + ret = hvf_set_ipa_granule(config, ipa_granule_size); + if (ret != HV_SUCCESS) { + goto cleanup; + } + } + ret = hv_vm_create(config); cleanup: diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 16febbac48f..395e13f467e 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -225,8 +225,16 @@ int hvf_arch_init(void) return 0; } -hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range) +hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range, + uint32_t ipa_granule_size) { + uint64_t page_size = qemu_real_host_page_size(); + + if (ipa_granule_size != 0 && ipa_granule_size != page_size) { + error_report("Only supported IPA granule size: 0x%llx", page_size); + return HV_UNSUPPORTED; + } + return hv_vm_create(HV_VM_DEFAULT); } -- 2.50.1 (Apple Git-155)
