On Thu, Dec 16, 2021 at 12:31:34PM +0000, Marc Zyngier wrote: > Just as arm64 implemenations don't necessary support all IPA > ranges, they don't all support the same page sizes either. Fun. > > Create a dummy VM to snapshot the page sizes supported by the > host, and filter the supported modes. > > Signed-off-by: Marc Zyngier <maz@xxxxxxxxxx> > --- > tools/testing/selftests/kvm/lib/guest_modes.c | 51 ++++++++++++++++--- > 1 file changed, 45 insertions(+), 6 deletions(-) > > diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c > index fadc99bac69c..8db9ea2c4032 100644 > --- a/tools/testing/selftests/kvm/lib/guest_modes.c > +++ b/tools/testing/selftests/kvm/lib/guest_modes.c > @@ -5,7 +5,42 @@ > #include "guest_modes.h" > > #ifdef __aarch64__ > +#include "processor.h" > enum vm_guest_mode vm_mode_default; > +static void get_supported_psz(uint32_t ipa, > + bool *ps4k, bool *ps16k, bool *ps64k) > +{ > + struct kvm_vcpu_init preferred_init; > + int kvm_fd, vm_fd, vcpu_fd, err; > + uint64_t val; > + struct kvm_one_reg reg = { > + .id = KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR0_EL1), > + .addr = (uint64_t)&val, > + }; > + > + kvm_fd = open_kvm_dev_path_or_exit(); > + vm_fd = ioctl(kvm_fd, KVM_CREATE_VM, ipa); > + TEST_ASSERT(vm_fd >= 0, "Can't create VM"); > + > + vcpu_fd = ioctl(vm_fd, KVM_CREATE_VCPU, 0); > + TEST_ASSERT(vcpu_fd >= 0, "Can't create vcpu"); > + > + err = ioctl(vm_fd, KVM_ARM_PREFERRED_TARGET, &preferred_init); > + TEST_ASSERT(err == 0, "Can't get target"); > + err = ioctl(vcpu_fd, KVM_ARM_VCPU_INIT, &preferred_init); > + TEST_ASSERT(err == 0, "Can't get init vcpu"); > + > + err = ioctl(vcpu_fd, KVM_GET_ONE_REG, ®); > + TEST_ASSERT(err == 0, "Can't get MMFR0"); > + > + *ps4k = ((val >> 28) & 0xf) != 0xf; > + *ps64k = ((val >> 24) & 0xf) == 0; > + *ps16k = ((val >> 20) & 0xf) != 0; > + > + close(vcpu_fd); > + close(vm_fd); > + close(kvm_fd); > +} I think I'd prefer stashing this function in lib/aarch64/processor.c and naming it aarch64_get_supported_page_sizes. > #endif > > struct guest_mode guest_modes[NUM_VM_MODES]; > @@ -18,20 +53,24 @@ void guest_modes_append_default(void) > #ifdef __aarch64__ > { > unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE); > + bool ps4k, ps16k, ps64k; > int i; > > + get_supported_psz(limit, &ps4k, &ps16k, &ps64k); > + > vm_mode_default = NUM_VM_MODES; > > if (limit >= 52) > - guest_mode_append(VM_MODE_P52V48_64K, true, true); > + guest_mode_append(VM_MODE_P52V48_64K, ps64k, ps64k); > if (limit >= 48) { > - guest_mode_append(VM_MODE_P48V48_4K, true, true); > - guest_mode_append(VM_MODE_P48V48_64K, true, true); > + guest_mode_append(VM_MODE_P48V48_4K, ps4k, ps4k); > + guest_mode_append(VM_MODE_P48V48_64K, ps64k, ps64k); > } > if (limit >= 40) { > - guest_mode_append(VM_MODE_P40V48_4K, true, true); > - guest_mode_append(VM_MODE_P40V48_64K, true, true); > - vm_mode_default = VM_MODE_P40V48_4K; > + guest_mode_append(VM_MODE_P40V48_4K, ps4k, ps4k); > + guest_mode_append(VM_MODE_P40V48_64K, ps64k, ps64k); > + if (ps4k) > + vm_mode_default = VM_MODE_P40V48_4K; > } > > /* Pick the largest supported IPA size */ > -- > 2.30.2 > Thanks, drew