Will do. I’ll reach out if I need extra info. The issue appears to be closed though, was this fixed/no-repro already though?
-Danny > On Feb 10, 2025, at 9:26 AM, Philippe Mathieu-Daudé <phi...@linaro.org> wrote: > > Hi Danny, > > On 28/8/24 13:15, Danny Canter wrote: >> This patch's main focus is to use the previously added >> hvf_get_physical_address_range to inform VM creation >> about the IPA size we need for the VM, so we can extend >> the default 36b IPA size and support VMs with 64+GB of >> RAM. This is done by freezing the memory map, computing >> the highest GPA and then (depending on if the platform >> supports an IPA size that large) telling the kernel to >> use a size >= for the VM. In pursuit of this a couple of >> things related to how we handle the physical address range >> we expose to guests were altered, but for an explanation of >> what we were doing: >> Today, to get the IPA size we were reading id_aa64mmfr0_el1's >> PARange field from a newly made vcpu. Unfortunately, HVF just >> returns the hosts PARange directly for the initial value and >> not the IPA size that will actually back the VM, so we believe >> we have much more address space than we actually do today it seems. >> Starting in macOS 13.0 some APIs were introduced to be able to >> query the maximum IPA size the kernel supports, and to set the IPA >> size for a given VM. However, this still has a couple of issues >> on < macOS 15. Up until macOS 15 (and if the hardware supported >> it) the max IPA size was 39 bits which is not a valid PARange >> value, so we can't clamp down what we advertise in the vcpu's >> id_aa64mmfr0_el1 to our IPA size. Starting in macOS 15 however, >> the maximum IPA size is 40 bits (if it's supported in the hardware >> as well) which is also a valid PARange value so we can set our IPA >> size to the maximum as well as clamp down the PARange we advertise >> to the guest. This allows VMs with 64+ GB of RAM and should fix the >> oddness of the PARange situation as well. > > Could you have a look at the following issue related to your patch? > https://gitlab.com/qemu-project/qemu/-/issues/2800 > > >> Signed-off-by: Danny Canter <danny_can...@apple.com> >> --- >> accel/hvf/hvf-accel-ops.c | 12 ++++++++- >> hw/arm/virt.c | 31 +++++++++++++++++++++- >> target/arm/hvf/hvf.c | 56 ++++++++++++++++++++++++++++++++++++++- >> target/arm/hvf_arm.h | 19 +++++++++++++ >> target/arm/internals.h | 19 +++++++++++++ >> target/arm/ptw.c | 15 +++++++++++ >> 6 files changed, 149 insertions(+), 3 deletions(-) >> diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c >> index dbebf209f4..d60874d3e6 100644 >> --- a/accel/hvf/hvf-accel-ops.c >> +++ b/accel/hvf/hvf-accel-ops.c >> @@ -53,6 +53,7 @@ >> #include "exec/address-spaces.h" >> #include "exec/exec-all.h" >> #include "gdbstub/enums.h" >> +#include "hw/boards.h" >> #include "sysemu/cpus.h" >> #include "sysemu/hvf.h" >> #include "sysemu/hvf_int.h" >> @@ -319,8 +320,17 @@ static int hvf_accel_init(MachineState *ms) >> int x; >> hv_return_t ret; >> HVFState *s; >> + int pa_range = 36; >> + MachineClass *mc = MACHINE_GET_CLASS(ms); >> - ret = hvf_arch_vm_create(ms, 0); >> + if (mc->hvf_get_physical_address_range) { >> + pa_range = mc->hvf_get_physical_address_range(ms); >> + if (pa_range < 0) { >> + return -EINVAL; >> + } >> + } >> + >> + ret = hvf_arch_vm_create(ms, (uint32_t)pa_range); >> assert_hvf_ok(ret); >> s = g_new0(HVFState, 1); >> diff --git a/hw/arm/virt.c b/hw/arm/virt.c >> index 62ee5f849b..b39c7924a0 100644 >> --- a/hw/arm/virt.c >> +++ b/hw/arm/virt.c >> @@ -66,6 +66,7 @@ >> #include "hw/intc/arm_gicv3_its_common.h" >> #include "hw/irq.h" >> #include "kvm_arm.h" >> +#include "hvf_arm.h" >> #include "hw/firmware/smbios.h" >> #include "qapi/visitor.h" >> #include "qapi/qapi-visit-common.h" >> @@ -3030,7 +3031,35 @@ static int virt_kvm_type(MachineState *ms, const char >> *type_str) >> static int virt_hvf_get_physical_address_range(MachineState *ms) >> { >> - return 0; >> + VirtMachineState *vms = VIRT_MACHINE(ms); >> + >> + int default_ipa_size = hvf_arm_get_default_ipa_bit_size(); >> + int max_ipa_size = hvf_arm_get_max_ipa_bit_size(); >> + >> + /* We freeze the memory map to compute the highest gpa */ >> + virt_set_memmap(vms, max_ipa_size); >> + >> + int requested_ipa_size = 64 - clz64(vms->highest_gpa); >> + >> + /* >> + * If we're <= the default IPA size just use the default. >> + * If we're above the default but below the maximum, round up to >> + * the maximum. hvf_arm_get_max_ipa_bit_size() conveniently only >> + * returns values that are valid ARM PARange values. >> + */ >> + if (requested_ipa_size <= default_ipa_size) { >> + requested_ipa_size = default_ipa_size; >> + } else if (requested_ipa_size <= max_ipa_size) { >> + requested_ipa_size = max_ipa_size; >> + } else { >> + error_report("-m and ,maxmem option values " >> + "require an IPA range (%d bits) larger than " >> + "the one supported by the host (%d bits)", >> + requested_ipa_size, max_ipa_size); >> + return -1; >> + } >> + >> + return requested_ipa_size; >> } >> static void virt_machine_class_init(ObjectClass *oc, void *data) >> diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c >> index 19964d241e..6cea483d42 100644 >> --- a/target/arm/hvf/hvf.c >> +++ b/target/arm/hvf/hvf.c >> @@ -22,6 +22,7 @@ >> #include <mach/mach_time.h> >> #include "exec/address-spaces.h" >> +#include "hw/boards.h" >> #include "hw/irq.h" >> #include "qemu/main-loop.h" >> #include "sysemu/cpus.h" >> @@ -297,6 +298,8 @@ void hvf_arm_init_debug(void) >> static void hvf_wfi(CPUState *cpu); >> +static uint32_t chosen_ipa_bit_size; >> + >> typedef struct HVFVTimer { >> /* Vtimer value during migration and paused state */ >> uint64_t vtimer_val; >> @@ -839,6 +842,16 @@ static uint64_t hvf_get_reg(CPUState *cpu, int rt) >> return val; >> } >> +static void clamp_id_aa64mmfr0_parange_to_ipa_size(uint64_t *id_aa64mmfr0) >> +{ >> + uint32_t ipa_size = chosen_ipa_bit_size ? >> + chosen_ipa_bit_size : hvf_arm_get_max_ipa_bit_size(); >> + >> + /* Clamp down the PARange to the IPA size the kernel supports. */ >> + uint8_t index = round_down_to_parange_index(ipa_size); >> + *id_aa64mmfr0 = (*id_aa64mmfr0 & ~R_ID_AA64MMFR0_PARANGE_MASK) | index; >> +} >> + >> static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) >> { >> ARMISARegisters host_isar = {}; >> @@ -882,6 +895,8 @@ static bool >> hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) >> r |= hv_vcpu_get_sys_reg(fd, HV_SYS_REG_MIDR_EL1, &ahcf->midr); >> r |= hv_vcpu_destroy(fd); >> + clamp_id_aa64mmfr0_parange_to_ipa_size(&host_isar.id_aa64mmfr0); >> + >> ahcf->isar = host_isar; >> /* >> @@ -904,6 +919,30 @@ static bool >> hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) >> return r == HV_SUCCESS; >> } >> +uint32_t hvf_arm_get_default_ipa_bit_size(void) >> +{ >> + uint32_t default_ipa_size; >> + hv_return_t ret = hv_vm_config_get_default_ipa_size(&default_ipa_size); >> + assert_hvf_ok(ret); >> + >> + return default_ipa_size; >> +} >> + >> +uint32_t hvf_arm_get_max_ipa_bit_size(void) >> +{ >> + uint32_t max_ipa_size; >> + hv_return_t ret = hv_vm_config_get_max_ipa_size(&max_ipa_size); >> + assert_hvf_ok(ret); >> + >> + /* >> + * We clamp any IPA size we want to back the VM with to a valid PARange >> + * value so the guest doesn't try and map memory outside of the valid >> range. >> + * This logic just clamps the passed in IPA bit size to the first valid >> + * PARange value <= to it. >> + */ >> + return round_down_to_parange_bit_size(max_ipa_size); >> +} >> + >> void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu) >> { >> if (!arm_host_cpu_features.dtb_compatible) { >> @@ -931,8 +970,18 @@ void hvf_arch_vcpu_destroy(CPUState *cpu) >> hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range) >> { >> + hv_return_t ret; >> hv_vm_config_t config = hv_vm_config_create(); >> - hv_return_t ret = hv_vm_create(config); >> + >> + ret = hv_vm_config_set_ipa_size(config, pa_range); >> + if (ret != HV_SUCCESS) { >> + goto cleanup; >> + } >> + chosen_ipa_bit_size = pa_range; >> + >> + ret = hv_vm_create(config); >> + >> +cleanup: >> os_release(config); >> return ret; >> @@ -1004,6 +1053,11 @@ int hvf_arch_init_vcpu(CPUState *cpu) >> &arm_cpu->isar.id_aa64mmfr0); >> assert_hvf_ok(ret); >> + clamp_id_aa64mmfr0_parange_to_ipa_size(&arm_cpu->isar.id_aa64mmfr0); >> + ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64MMFR0_EL1, >> + arm_cpu->isar.id_aa64mmfr0); >> + assert_hvf_ok(ret); >> + >> return 0; >> } >> diff --git a/target/arm/hvf_arm.h b/target/arm/hvf_arm.h >> index e848c1d27d..26c717b382 100644 >> --- a/target/arm/hvf_arm.h >> +++ b/target/arm/hvf_arm.h >> @@ -22,4 +22,23 @@ void hvf_arm_init_debug(void); >> void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu); >> +#ifdef CONFIG_HVF >> + >> +uint32_t hvf_arm_get_default_ipa_bit_size(void); >> +uint32_t hvf_arm_get_max_ipa_bit_size(void); >> + >> +#else >> + >> +static inline uint32_t hvf_arm_get_default_ipa_bit_size(void) >> +{ >> + return 0; >> +} >> + >> +static inline uint32_t hvf_arm_get_max_ipa_bit_size(void) >> +{ >> + return 0; >> +} >> + >> +#endif >> + >> #endif >> diff --git a/target/arm/internals.h b/target/arm/internals.h >> index 203a2dae14..c5d7b0b492 100644 >> --- a/target/arm/internals.h >> +++ b/target/arm/internals.h >> @@ -450,6 +450,25 @@ static inline void update_spsel(CPUARMState *env, >> uint32_t imm) >> */ >> unsigned int arm_pamax(ARMCPU *cpu); >> +/* >> + * round_down_to_parange_index >> + * @bit_size: uint8_t >> + * >> + * Rounds down the bit_size supplied to the first supported ARM physical >> + * address range and returns the index for this. The index is intended to >> + * be used to set ID_AA64MMFR0_EL1's PARANGE bits. >> + */ >> +uint8_t round_down_to_parange_index(uint8_t bit_size); >> + >> +/* >> + * round_down_to_parange_bit_size >> + * @bit_size: uint8_t >> + * >> + * Rounds down the bit_size supplied to the first supported ARM physical >> + * address range bit size and returns this. >> + */ >> +uint8_t round_down_to_parange_bit_size(uint8_t bit_size); >> + >> /* Return true if extended addresses are enabled. >> * This is always the case if our translation regime is 64 bit, >> * but depends on TTBCR.EAE for 32 bit. >> diff --git a/target/arm/ptw.c b/target/arm/ptw.c >> index 278004661b..defd6b84de 100644 >> --- a/target/arm/ptw.c >> +++ b/target/arm/ptw.c >> @@ -96,6 +96,21 @@ static const uint8_t pamax_map[] = { >> [6] = 52, >> }; >> +uint8_t round_down_to_parange_index(uint8_t bit_size) >> +{ >> + for (int i = ARRAY_SIZE(pamax_map) - 1; i >= 0; i--) { >> + if (pamax_map[i] <= bit_size) { >> + return i; >> + } >> + } >> + g_assert_not_reached(); >> +} >> + >> +uint8_t round_down_to_parange_bit_size(uint8_t bit_size) >> +{ >> + return pamax_map[round_down_to_parange_index(bit_size)]; >> +} >> + >> /* >> * The cpu-specific constant value of PAMax; also used by hw/arm/virt. >> * Note that machvirt_init calls this on a CPU that is inited but not >> realized! >