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

KVM: selftests: arm64: Support P52V48 4K and 16K guest_modes

Add support for VM_MODE_P52V48_4K and VM_MODE_P52V48_16K guest modes by
using the FEAT_LPA2 pte format for stage1, when FEAT_LPA2 is available.

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-13-ryan.roberts@arm.com

authored by

Ryan Roberts and committed by
Marc Zyngier
10a0cc3b 72324ac5

+36 -9
+1
tools/testing/selftests/kvm/include/kvm_util_base.h
··· 171 171 172 172 enum vm_guest_mode { 173 173 VM_MODE_P52V48_4K, 174 + VM_MODE_P52V48_16K, 174 175 VM_MODE_P52V48_64K, 175 176 VM_MODE_P48V48_4K, 176 177 VM_MODE_P48V48_16K,
+30 -9
tools/testing/selftests/kvm/lib/aarch64/processor.c
··· 12 12 #include "kvm_util.h" 13 13 #include "processor.h" 14 14 #include <linux/bitfield.h> 15 + #include <linux/sizes.h> 15 16 16 17 #define DEFAULT_ARM64_GUEST_STACK_VADDR_MIN 0xac0000 17 18 ··· 59 58 return (gva >> vm->page_shift) & mask; 60 59 } 61 60 61 + static inline bool use_lpa2_pte_format(struct kvm_vm *vm) 62 + { 63 + return (vm->page_size == SZ_4K || vm->page_size == SZ_16K) && 64 + (vm->pa_bits > 48 || vm->va_bits > 48); 65 + } 66 + 62 67 static uint64_t addr_pte(struct kvm_vm *vm, uint64_t pa, uint64_t attrs) 63 68 { 64 69 uint64_t pte; 65 70 66 - pte = pa & GENMASK(47, vm->page_shift); 67 - if (vm->page_shift == 16) 68 - pte |= FIELD_GET(GENMASK(51, 48), pa) << 12; 71 + if (use_lpa2_pte_format(vm)) { 72 + pte = pa & GENMASK(49, vm->page_shift); 73 + pte |= FIELD_GET(GENMASK(51, 50), pa) << 8; 74 + attrs &= ~GENMASK(9, 8); 75 + } else { 76 + pte = pa & GENMASK(47, vm->page_shift); 77 + if (vm->page_shift == 16) 78 + pte |= FIELD_GET(GENMASK(51, 48), pa) << 12; 79 + } 69 80 pte |= attrs; 70 81 71 82 return pte; ··· 87 74 { 88 75 uint64_t pa; 89 76 90 - pa = pte & GENMASK(47, vm->page_shift); 91 - if (vm->page_shift == 16) 92 - pa |= FIELD_GET(GENMASK(15, 12), pte) << 48; 77 + if (use_lpa2_pte_format(vm)) { 78 + pa = pte & GENMASK(49, vm->page_shift); 79 + pa |= FIELD_GET(GENMASK(9, 8), pte) << 50; 80 + } else { 81 + pa = pte & GENMASK(47, vm->page_shift); 82 + if (vm->page_shift == 16) 83 + pa |= FIELD_GET(GENMASK(15, 12), pte) << 48; 84 + } 93 85 94 86 return pa; 95 87 } ··· 284 266 285 267 /* Configure base granule size */ 286 268 switch (vm->mode) { 287 - case VM_MODE_P52V48_4K: 288 - TEST_FAIL("AArch64 does not support 4K sized pages " 289 - "with 52-bit physical address ranges"); 290 269 case VM_MODE_PXXV48_4K: 291 270 TEST_FAIL("AArch64 does not support 4K sized pages " 292 271 "with ANY-bit physical address ranges"); ··· 293 278 case VM_MODE_P36V48_64K: 294 279 tcr_el1 |= 1ul << 14; /* TG0 = 64KB */ 295 280 break; 281 + case VM_MODE_P52V48_16K: 296 282 case VM_MODE_P48V48_16K: 297 283 case VM_MODE_P40V48_16K: 298 284 case VM_MODE_P36V48_16K: 299 285 case VM_MODE_P36V47_16K: 300 286 tcr_el1 |= 2ul << 14; /* TG0 = 16KB */ 301 287 break; 288 + case VM_MODE_P52V48_4K: 302 289 case VM_MODE_P48V48_4K: 303 290 case VM_MODE_P40V48_4K: 304 291 case VM_MODE_P36V48_4K: ··· 314 297 315 298 /* Configure output size */ 316 299 switch (vm->mode) { 300 + case VM_MODE_P52V48_4K: 301 + case VM_MODE_P52V48_16K: 317 302 case VM_MODE_P52V48_64K: 318 303 tcr_el1 |= 6ul << 32; /* IPS = 52 bits */ 319 304 ttbr0_el1 |= FIELD_GET(GENMASK(51, 48), vm->pgd) << 2; ··· 344 325 /* TCR_EL1 |= IRGN0:WBWA | ORGN0:WBWA | SH0:Inner-Shareable */; 345 326 tcr_el1 |= (1 << 8) | (1 << 10) | (3 << 12); 346 327 tcr_el1 |= (64 - vm->va_bits) /* T0SZ */; 328 + if (use_lpa2_pte_format(vm)) 329 + tcr_el1 |= (1ul << 59) /* DS */; 347 330 348 331 vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), sctlr_el1); 349 332 vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TCR_EL1), tcr_el1);
+2
tools/testing/selftests/kvm/lib/guest_modes.c
··· 23 23 24 24 aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k); 25 25 26 + guest_mode_append(VM_MODE_P52V48_4K, ipa4k >= 52); 27 + guest_mode_append(VM_MODE_P52V48_16K, ipa16k >= 52); 26 28 guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52); 27 29 28 30 guest_mode_append(VM_MODE_P48V48_4K, ipa4k >= 48);
+3
tools/testing/selftests/kvm/lib/kvm_util.c
··· 148 148 { 149 149 static const char * const strings[] = { 150 150 [VM_MODE_P52V48_4K] = "PA-bits:52, VA-bits:48, 4K pages", 151 + [VM_MODE_P52V48_16K] = "PA-bits:52, VA-bits:48, 16K pages", 151 152 [VM_MODE_P52V48_64K] = "PA-bits:52, VA-bits:48, 64K pages", 152 153 [VM_MODE_P48V48_4K] = "PA-bits:48, VA-bits:48, 4K pages", 153 154 [VM_MODE_P48V48_16K] = "PA-bits:48, VA-bits:48, 16K pages", ··· 174 173 175 174 const struct vm_guest_mode_params vm_guest_mode_params[] = { 176 175 [VM_MODE_P52V48_4K] = { 52, 48, 0x1000, 12 }, 176 + [VM_MODE_P52V48_16K] = { 52, 48, 0x4000, 14 }, 177 177 [VM_MODE_P52V48_64K] = { 52, 48, 0x10000, 16 }, 178 178 [VM_MODE_P48V48_4K] = { 48, 48, 0x1000, 12 }, 179 179 [VM_MODE_P48V48_16K] = { 48, 48, 0x4000, 14 }, ··· 253 251 case VM_MODE_P36V48_64K: 254 252 vm->pgtable_levels = 3; 255 253 break; 254 + case VM_MODE_P52V48_16K: 256 255 case VM_MODE_P48V48_16K: 257 256 case VM_MODE_P40V48_16K: 258 257 case VM_MODE_P36V48_16K: