Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: selftests: arm64: Determine max ipa size per-page size

We are about to add 52 bit PA guest modes for 4K and 16K pages when the
system supports LPA2. In preparation beef up the logic that parses mmfr0
to also tell us what the maximum supported PA size is for each page
size. Max PA size = 0 implies the page size is not supported at all.

Reviewed-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20231127111737.1897081-12-ryan.roberts@arm.com

authored by

Ryan Roberts and committed by
Marc Zyngier
72324ac5 d782ac5b

+50 -36
+2 -2
tools/testing/selftests/kvm/include/aarch64/processor.h
··· 119 119 /* Access flag update enable/disable */ 120 120 #define TCR_EL1_HA (1ULL << 39) 121 121 122 - void aarch64_get_supported_page_sizes(uint32_t ipa, 123 - bool *ps4k, bool *ps16k, bool *ps64k); 122 + void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k, 123 + uint32_t *ipa16k, uint32_t *ipa64k); 124 124 125 125 void vm_init_descriptor_tables(struct kvm_vm *vm); 126 126 void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu);
+2 -2
tools/testing/selftests/kvm/include/guest_modes.h
··· 11 11 12 12 extern struct guest_mode guest_modes[NUM_VM_MODES]; 13 13 14 - #define guest_mode_append(mode, supported, enabled) ({ \ 15 - guest_modes[mode] = (struct guest_mode){ supported, enabled }; \ 14 + #define guest_mode_append(mode, enabled) ({ \ 15 + guest_modes[mode] = (struct guest_mode){ (enabled), (enabled) }; \ 16 16 }) 17 17 18 18 void guest_modes_append_default(void);
+25 -5
tools/testing/selftests/kvm/lib/aarch64/processor.c
··· 492 492 return read_sysreg(tpidr_el1); 493 493 } 494 494 495 - void aarch64_get_supported_page_sizes(uint32_t ipa, 496 - bool *ps4k, bool *ps16k, bool *ps64k) 495 + static uint32_t max_ipa_for_page_size(uint32_t vm_ipa, uint32_t gran, 496 + uint32_t not_sup_val, uint32_t ipa52_min_val) 497 + { 498 + if (gran == not_sup_val) 499 + return 0; 500 + else if (gran >= ipa52_min_val && vm_ipa >= 52) 501 + return 52; 502 + else 503 + return min(vm_ipa, 48U); 504 + } 505 + 506 + void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k, 507 + uint32_t *ipa16k, uint32_t *ipa64k) 497 508 { 498 509 struct kvm_vcpu_init preferred_init; 499 510 int kvm_fd, vm_fd, vcpu_fd, err; 500 511 uint64_t val; 512 + uint32_t gran; 501 513 struct kvm_one_reg reg = { 502 514 .id = KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR0_EL1), 503 515 .addr = (uint64_t)&val, ··· 530 518 err = ioctl(vcpu_fd, KVM_GET_ONE_REG, &reg); 531 519 TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_GET_ONE_REG, vcpu_fd)); 532 520 533 - *ps4k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val) != 0xf; 534 - *ps64k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val) == 0; 535 - *ps16k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val) != 0; 521 + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val); 522 + *ipa4k = max_ipa_for_page_size(ipa, gran, ID_AA64MMFR0_EL1_TGRAN4_NI, 523 + ID_AA64MMFR0_EL1_TGRAN4_52_BIT); 524 + 525 + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val); 526 + *ipa64k = max_ipa_for_page_size(ipa, gran, ID_AA64MMFR0_EL1_TGRAN64_NI, 527 + ID_AA64MMFR0_EL1_TGRAN64_IMP); 528 + 529 + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val); 530 + *ipa16k = max_ipa_for_page_size(ipa, gran, ID_AA64MMFR0_EL1_TGRAN16_NI, 531 + ID_AA64MMFR0_EL1_TGRAN16_52_BIT); 536 532 537 533 close(vcpu_fd); 538 534 close(vm_fd);
+21 -27
tools/testing/selftests/kvm/lib/guest_modes.c
··· 14 14 void guest_modes_append_default(void) 15 15 { 16 16 #ifndef __aarch64__ 17 - guest_mode_append(VM_MODE_DEFAULT, true, true); 17 + guest_mode_append(VM_MODE_DEFAULT, true); 18 18 #else 19 19 { 20 20 unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE); 21 - bool ps4k, ps16k, ps64k; 21 + uint32_t ipa4k, ipa16k, ipa64k; 22 22 int i; 23 23 24 - aarch64_get_supported_page_sizes(limit, &ps4k, &ps16k, &ps64k); 24 + aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k); 25 25 26 - vm_mode_default = NUM_VM_MODES; 26 + guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52); 27 27 28 - if (limit >= 52) 29 - guest_mode_append(VM_MODE_P52V48_64K, ps64k, ps64k); 30 - if (limit >= 48) { 31 - guest_mode_append(VM_MODE_P48V48_4K, ps4k, ps4k); 32 - guest_mode_append(VM_MODE_P48V48_16K, ps16k, ps16k); 33 - guest_mode_append(VM_MODE_P48V48_64K, ps64k, ps64k); 34 - } 35 - if (limit >= 40) { 36 - guest_mode_append(VM_MODE_P40V48_4K, ps4k, ps4k); 37 - guest_mode_append(VM_MODE_P40V48_16K, ps16k, ps16k); 38 - guest_mode_append(VM_MODE_P40V48_64K, ps64k, ps64k); 39 - if (ps4k) 40 - vm_mode_default = VM_MODE_P40V48_4K; 41 - } 42 - if (limit >= 36) { 43 - guest_mode_append(VM_MODE_P36V48_4K, ps4k, ps4k); 44 - guest_mode_append(VM_MODE_P36V48_16K, ps16k, ps16k); 45 - guest_mode_append(VM_MODE_P36V48_64K, ps64k, ps64k); 46 - guest_mode_append(VM_MODE_P36V47_16K, ps16k, ps16k); 47 - } 28 + guest_mode_append(VM_MODE_P48V48_4K, ipa4k >= 48); 29 + guest_mode_append(VM_MODE_P48V48_16K, ipa16k >= 48); 30 + guest_mode_append(VM_MODE_P48V48_64K, ipa64k >= 48); 31 + 32 + guest_mode_append(VM_MODE_P40V48_4K, ipa4k >= 40); 33 + guest_mode_append(VM_MODE_P40V48_16K, ipa16k >= 40); 34 + guest_mode_append(VM_MODE_P40V48_64K, ipa64k >= 40); 35 + 36 + guest_mode_append(VM_MODE_P36V48_4K, ipa4k >= 36); 37 + guest_mode_append(VM_MODE_P36V48_16K, ipa16k >= 36); 38 + guest_mode_append(VM_MODE_P36V48_64K, ipa64k >= 36); 39 + guest_mode_append(VM_MODE_P36V47_16K, ipa16k >= 36); 40 + 41 + vm_mode_default = ipa4k >= 40 ? VM_MODE_P40V48_4K : NUM_VM_MODES; 48 42 49 43 /* 50 44 * Pick the first supported IPA size if the default ··· 66 72 close(kvm_fd); 67 73 /* Starting with z13 we have 47bits of physical address */ 68 74 if (info.ibc >= 0x30) 69 - guest_mode_append(VM_MODE_P47V64_4K, true, true); 75 + guest_mode_append(VM_MODE_P47V64_4K, true); 70 76 } 71 77 #endif 72 78 #ifdef __riscv ··· 74 80 unsigned int sz = kvm_check_cap(KVM_CAP_VM_GPA_BITS); 75 81 76 82 if (sz >= 52) 77 - guest_mode_append(VM_MODE_P52V48_4K, true, true); 83 + guest_mode_append(VM_MODE_P52V48_4K, true); 78 84 if (sz >= 48) 79 - guest_mode_append(VM_MODE_P48V48_4K, true, true); 85 + guest_mode_append(VM_MODE_P48V48_4K, true); 80 86 } 81 87 #endif 82 88 }