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 <[email protected]>
---
 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, &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);
+}
 #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

_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

Reply via email to