Kernel KVM virtualization development
 help / color / mirror / Atom feed
* [PATCH 0/2] 52-bit VA guest mode ID support
@ 2026-08-25 21:18 Itaru Kitayama
  2026-08-25 21:18 ` [PATCH 1/2] KVM: selftest: arm64: Support 5-level paging in stage 1 translation table Itaru Kitayama
  2026-08-25 21:18 ` [PATCH 2/2] KVM: selftests: arm64: Add 52-bit VA guest modes Itaru Kitayama
  0 siblings, 2 replies; 5+ messages in thread
From: Itaru Kitayama @ 2026-08-25 21:18 UTC (permalink / raw)
  To: Marc Zyngier, Oliver Upton, Fuad Tabba, Joey Gouly, Steffen Eiden,
	Suzuki K Poulose, Zenghui Yu, Paolo Bonzini, Shuah Khan
  Cc: linux-arm-kernel, kvmarm, kvm, linux-kselftest, linux-kernel,
	Itaru Kitayama, Takayuki Okamoto

This patch series extends the arm64 KVM selftest framework
to support 52-bit guest virtual address (VA) modes in addition to
the existing 52-bit physical address (PA) configurations.
The motivation is to enable validation of LPA2 guest memory-management
behaviour in configurations that use a 52-bit VA space.
While the selftest framework already supports testing 52-bit PA
configurations, it lacks the ability to exercise guests running with
52-bit virtual addresses, leaving part of the LPA2 functionality untested.
To address this, the series introduces new guest modes for 52-bit VA
operation, adds five-level page table support where required, and
performs runtime detection of host 52-bit VA capability so that
LPA2-enabled guest VA tests are executed only on supported systems.

Testing:

Built and tested on arm64.
Verified on QEMU with a V52-capable guest configuration.
Confirmed correct operation of high virtual address mappings by
exercising guest memory accesses in the 52-bit VA range.

Signed-off-by: Itaru Kitayama <itaru.kitayama@fujitsu.com>
Reviewed-by: Takayuki Okamoto <tokamoto@fujitsu.com>
---
Itaru Kitayama (2):
      KVM: selftest: arm64: Support 5-level paging in stage 1 translation table
      KVM: selftests: arm64: Add 52-bit VA guest modes

 .../selftests/kvm/include/arm64/processor.h        |  2 +
 tools/testing/selftests/kvm/include/kvm_util.h     |  3 +
 tools/testing/selftests/kvm/lib/arm64/processor.c  | 87 ++++++++++++++++++++--
 tools/testing/selftests/kvm/lib/guest_modes.c      |  5 ++
 tools/testing/selftests/kvm/lib/kvm_util.c         | 11 +++
 5 files changed, 103 insertions(+), 5 deletions(-)
---
base-commit: 8d3ae59288f1e7d58d76558a6ee96d533bc5019f
change-id: 20260825-arm64-52bit-va-32f1f4cd050d

Best regards,
--  
Itaru Kitayama <itaru.kitayama@fujitsu.com>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] KVM: selftest: arm64: Support 5-level paging in stage 1 translation table
  2026-08-25 21:18 [PATCH 0/2] 52-bit VA guest mode ID support Itaru Kitayama
@ 2026-08-25 21:18 ` Itaru Kitayama
  2026-08-25 21:35   ` sashiko-bot
  2026-08-25 21:18 ` [PATCH 2/2] KVM: selftests: arm64: Add 52-bit VA guest modes Itaru Kitayama
  1 sibling, 1 reply; 5+ messages in thread
From: Itaru Kitayama @ 2026-08-25 21:18 UTC (permalink / raw)
  To: Marc Zyngier, Oliver Upton, Fuad Tabba, Joey Gouly, Steffen Eiden,
	Suzuki K Poulose, Zenghui Yu, Paolo Bonzini, Shuah Khan
  Cc: linux-arm-kernel, kvmarm, kvm, linux-kselftest, linux-kernel,
	Itaru Kitayama, Takayuki Okamoto

Add p4d_index() for when 5-level paging required, i.e., V52 guest mode
IDs. With the index helper function, _virt_pg_map() handles 5-level
paging case, and aarch64_vcpu_setup() now is aware of the new V52 guest
mode IDs.

Signed-off-by: Itaru Kitayama <itaru.kitayama@fujitsu.com>
Reviewed-by: Takayuki Okamoto <tokamoto@fujitsu.com>
---
 .../selftests/kvm/include/arm64/processor.h        |  2 +
 tools/testing/selftests/kvm/lib/arm64/processor.c  | 87 ++++++++++++++++++++--
 2 files changed, 84 insertions(+), 5 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/arm64/processor.h b/tools/testing/selftests/kvm/include/arm64/processor.h
index b8a902ba8573..a6fd7a9b379e 100644
--- a/tools/testing/selftests/kvm/include/arm64/processor.h
+++ b/tools/testing/selftests/kvm/include/arm64/processor.h
@@ -113,6 +113,7 @@
 
 #define PTE_VALID		BIT(0)
 #define PGD_TYPE_TABLE		BIT(1)
+#define P4D_TYPE_TABLE		BIT(1)
 #define PUD_TYPE_TABLE		BIT(1)
 #define PMD_TYPE_TABLE		BIT(1)
 #define PTE_TYPE_PAGE		BIT(1)
@@ -167,6 +168,7 @@ enum {
 			   (v) == VECTOR_SYNC_LOWER_64    || \
 			   (v) == VECTOR_SYNC_LOWER_32)
 
+u32 aarch64_get_supported_va_size(void);
 void aarch64_get_supported_page_sizes(u32 ipa, u32 *ipa4k,
 				      u32 *ipa16k, u32 *ipa64k);
 
diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c
index 01325bf4d36f..9108e14a9b5b 100644
--- a/tools/testing/selftests/kvm/lib/arm64/processor.c
+++ b/tools/testing/selftests/kvm/lib/arm64/processor.c
@@ -29,13 +29,25 @@ static u64 pgd_index(struct kvm_vm *vm, gva_t gva)
 	return (gva >> shift) & mask;
 }
 
+static u64 p4d_index(struct kvm_vm *vm, gva_t gva)
+{
+	unsigned int shift = 3 * (vm->page_shift - 3) + vm->page_shift;
+	u64 mask = (1UL << (vm->page_shift - 3)) - 1;
+
+	TEST_ASSERT(vm->mmu.pgtable_levels == 5,
+		    "Mode %d does not have 5 page table levels", vm->mode);
+
+	return (gva >> shift) & mask;
+}
+
 static u64 pud_index(struct kvm_vm *vm, gva_t gva)
 {
 	unsigned int shift = 2 * (vm->page_shift - 3) + vm->page_shift;
 	u64 mask = (1UL << (vm->page_shift - 3)) - 1;
 
-	TEST_ASSERT(vm->mmu.pgtable_levels == 4,
-		"Mode %d does not have 4 page table levels", vm->mode);
+	TEST_ASSERT(vm->mmu.pgtable_levels >= 4,
+		    "Mode %d does not have at least 4 page table levels",
+		    vm->mode);
 
 	return (gva >> shift) & mask;
 }
@@ -147,6 +159,12 @@ static void _virt_pg_map(struct kvm_vm *vm, gva_t gva, gpa_t gpa,
 				 PGD_TYPE_TABLE | PTE_VALID);
 
 	switch (vm->mmu.pgtable_levels) {
+	case 5:
+		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + p4d_index(vm, gva) * 8;
+		if (!*ptep)
+			*ptep = addr_pte(vm, vm_alloc_page_table(vm),
+					 P4D_TYPE_TABLE | PTE_VALID);
+		/* fall through */
 	case 4:
 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, gva) * 8;
 		if (!*ptep)
@@ -163,7 +181,7 @@ static void _virt_pg_map(struct kvm_vm *vm, gva_t gva, gpa_t gpa,
 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pte_index(vm, gva) * 8;
 		break;
 	default:
-		TEST_FAIL("Page table levels must be 2, 3, or 4");
+		TEST_FAIL("Page table levels must be 2, 3, 4, or 5");
 	}
 
 	pg_attr = PTE_AF | PTE_ATTRINDX(attr_idx) | PTE_TYPE_PAGE | PTE_VALID;
@@ -182,18 +200,35 @@ void virt_arch_pg_map(struct kvm_vm *vm, gva_t gva, gpa_t gpa)
 
 u64 *virt_get_pte_hva_at_level(struct kvm_vm *vm, gva_t gva, int level)
 {
+	int start_level = 4 - vm->mmu.pgtable_levels;
 	u64 *ptep;
 
+	TEST_ASSERT(level >= start_level && level <= 3,
+		    "Invalid translation level %d, valid range is %d-3",
+		    level, start_level);
+
 	if (!vm->mmu.pgd_created)
 		goto unmapped_gva;
 
 	ptep = addr_gpa2hva(vm, vm->mmu.pgd) + pgd_index(vm, gva) * 8;
 	if (!ptep)
 		goto unmapped_gva;
-	if (level == 0)
+	/*
+	 * Stage-1 translation starts at level -1 for a five-level page
+	 * table, and at levels 0, 1, or 2 for four-, three-, or two-level
+	 * page tables, respectively.
+	 */
+	if (level == start_level)
 		return ptep;
 
 	switch (vm->mmu.pgtable_levels) {
+	case 5:
+		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + p4d_index(vm, gva) * 8;
+		if (!ptep)
+			goto unmapped_gva;
+		if (level == 0)
+			break;
+		/* fall through */
 	case 4:
 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, gva) * 8;
 		if (!ptep)
@@ -214,7 +249,7 @@ u64 *virt_get_pte_hva_at_level(struct kvm_vm *vm, gva_t gva, int level)
 			goto unmapped_gva;
 		break;
 	default:
-		TEST_FAIL("Page table levels must be 2, 3, or 4");
+		TEST_FAIL("Page table levels must be 2, 3, 4, or 5");
 	}
 
 	return ptep;
@@ -321,12 +356,14 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
 	case VM_MODE_PXXVYY_4K:
 		TEST_FAIL("AArch64 does not support 4K sized pages "
 			  "with ANY-bit physical address ranges");
+	case VM_MODE_P52V52_64K:
 	case VM_MODE_P52V48_64K:
 	case VM_MODE_P48V48_64K:
 	case VM_MODE_P40V48_64K:
 	case VM_MODE_P36V48_64K:
 		tcr_el1 |= TCR_TG0_64K;
 		break;
+	case VM_MODE_P52V52_16K:
 	case VM_MODE_P52V48_16K:
 	case VM_MODE_P48V48_16K:
 	case VM_MODE_P40V48_16K:
@@ -334,6 +371,7 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
 	case VM_MODE_P36V47_16K:
 		tcr_el1 |= TCR_TG0_16K;
 		break;
+	case VM_MODE_P52V52_4K:
 	case VM_MODE_P52V48_4K:
 	case VM_MODE_P48V48_4K:
 	case VM_MODE_P40V48_4K:
@@ -348,6 +386,9 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
 
 	/* Configure output size */
 	switch (vm->mode) {
+	case VM_MODE_P52V52_4K:
+	case VM_MODE_P52V52_16K:
+	case VM_MODE_P52V52_64K:
 	case VM_MODE_P52V48_4K:
 	case VM_MODE_P52V48_16K:
 	case VM_MODE_P52V48_64K:
@@ -578,6 +619,42 @@ static u32 max_ipa_for_page_size(u32 vm_ipa, u32 gran,
 		return min(vm_ipa, 48U);
 }
 
+u32 aarch64_get_supported_va_size(void)
+{
+	struct kvm_vcpu_init preferred_init = {};
+	int kvm_fd, vm_fd, vcpu_fd, err;
+	u64 val;
+	u32 va_range;
+	struct kvm_one_reg reg = {
+		.id	= KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR2_EL1),
+		.addr	= (u64)&val,
+	};
+
+	kvm_fd = open_kvm_dev_path_or_exit();
+	vm_fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, NULL);
+	TEST_ASSERT(vm_fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VM, vm_fd));
+
+	vcpu_fd = ioctl(vm_fd, KVM_CREATE_VCPU, 0);
+	TEST_ASSERT(vcpu_fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VCPU, vcpu_fd));
+
+	err = ioctl(vm_fd, KVM_ARM_PREFERRED_TARGET, &preferred_init);
+	TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_ARM_PREFERRED_TARGET, err));
+
+	err = ioctl(vcpu_fd, KVM_ARM_VCPU_INIT, &preferred_init);
+	TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_ARM_VCPU_INIT, err));
+
+	err = ioctl(vcpu_fd, KVM_GET_ONE_REG, &reg);
+	TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_GET_ONE_REG, err));
+
+	va_range = FIELD_GET(ID_AA64MMFR2_EL1_VARange, val);
+
+	close(vcpu_fd);
+	close(vm_fd);
+	close(kvm_fd);
+
+	return va_range >= ID_AA64MMFR2_EL1_VARange_52 ? 52 : 48;
+}
+
 void aarch64_get_supported_page_sizes(u32 ipa, u32 *ipa4k,
 				      u32 *ipa16k, u32 *ipa64k)
 {

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] KVM: selftests: arm64: Add 52-bit VA guest modes
  2026-08-25 21:18 [PATCH 0/2] 52-bit VA guest mode ID support Itaru Kitayama
  2026-08-25 21:18 ` [PATCH 1/2] KVM: selftest: arm64: Support 5-level paging in stage 1 translation table Itaru Kitayama
@ 2026-08-25 21:18 ` Itaru Kitayama
  2026-08-25 21:32   ` sashiko-bot
  1 sibling, 1 reply; 5+ messages in thread
From: Itaru Kitayama @ 2026-08-25 21:18 UTC (permalink / raw)
  To: Marc Zyngier, Oliver Upton, Fuad Tabba, Joey Gouly, Steffen Eiden,
	Suzuki K Poulose, Zenghui Yu, Paolo Bonzini, Shuah Khan
  Cc: linux-arm-kernel, kvmarm, kvm, linux-kselftest, linux-kernel,
	Itaru Kitayama, Takayuki Okamoto

Add P52V52 guest mode IDs for the 4K, 16K and 64K translation
granules, along with their mode descriptions and parameters.

Advertise the 4KB and 16KB modes when the corresponding granule supports
a 52-bit IPA, implying FEAT_LPA2 support. For the 64K mode, also require
52-bit VA support.

This makes the 52-bit VA configurations available to KVM selftests now
that the arm64 page-table code supports 5-level stage-1 translation.

Signed-off-by: Itaru Kitayama <itaru.kitayama@fujitsu.com>
Reviewed-by: Takayuki Okamoto <tokamoto@fujitsu.com>
---
 tools/testing/selftests/kvm/include/kvm_util.h    |  3 +++
 tools/testing/selftests/kvm/lib/arm64/processor.c |  2 +-
 tools/testing/selftests/kvm/lib/guest_modes.c     |  5 +++++
 tools/testing/selftests/kvm/lib/kvm_util.c        | 11 +++++++++++
 4 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 04a910164a29..9040281c0992 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -184,6 +184,9 @@ enum vm_guest_mode {
 	VM_MODE_P52V48_4K,
 	VM_MODE_P52V48_16K,
 	VM_MODE_P52V48_64K,
+	VM_MODE_P52V52_4K,
+	VM_MODE_P52V52_16K,
+	VM_MODE_P52V52_64K,
 	VM_MODE_P48V48_4K,
 	VM_MODE_P48V48_16K,
 	VM_MODE_P48V48_64K,
diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c
index 9108e14a9b5b..bcdf670c9eb8 100644
--- a/tools/testing/selftests/kvm/lib/arm64/processor.c
+++ b/tools/testing/selftests/kvm/lib/arm64/processor.c
@@ -46,7 +46,7 @@ static u64 pud_index(struct kvm_vm *vm, gva_t gva)
 	u64 mask = (1UL << (vm->page_shift - 3)) - 1;
 
 	TEST_ASSERT(vm->mmu.pgtable_levels >= 4,
-		    "Mode %d does not have at least 4 page table levels",
+		    "Mode %d does not have >= 4 page table levels",
 		    vm->mode);
 
 	return (gva >> shift) & mask;
diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c
index 7a96c43b5704..4f121e2987e9 100644
--- a/tools/testing/selftests/kvm/lib/guest_modes.c
+++ b/tools/testing/selftests/kvm/lib/guest_modes.c
@@ -21,10 +21,15 @@ void guest_modes_append_default(void)
 	{
 		unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE);
 		u32 ipa4k, ipa16k, ipa64k;
+		u32 va;
 		int i;
 
 		aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k);
+		va = aarch64_get_supported_va_size();
 
+		guest_mode_append(VM_MODE_P52V52_4K, ipa4k >= 52);
+		guest_mode_append(VM_MODE_P52V52_16K, ipa16k >= 52);
+		guest_mode_append(VM_MODE_P52V52_64K, ipa64k >= 52 && va >= 52);
 		guest_mode_append(VM_MODE_P52V48_4K, ipa4k >= 52);
 		guest_mode_append(VM_MODE_P52V48_16K, ipa16k >= 52);
 		guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52);
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 195f3fdae1e3..3fbc5b0d75ff 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -195,6 +195,9 @@ const char *vm_guest_mode_string(u32 i)
 		[VM_MODE_P52V48_4K]	= "PA-bits:52,  VA-bits:48,  4K pages",
 		[VM_MODE_P52V48_16K]	= "PA-bits:52,  VA-bits:48, 16K pages",
 		[VM_MODE_P52V48_64K]	= "PA-bits:52,  VA-bits:48, 64K pages",
+		[VM_MODE_P52V52_4K]	= "PA-bits:52,  VA-bits:52,  4K pages",
+		[VM_MODE_P52V52_16K]	= "PA-bits:52,  VA-bits:52, 16K pages",
+		[VM_MODE_P52V52_64K]	= "PA-bits:52,  VA-bits:52, 64K pages",
 		[VM_MODE_P48V48_4K]	= "PA-bits:48,  VA-bits:48,  4K pages",
 		[VM_MODE_P48V48_16K]	= "PA-bits:48,  VA-bits:48, 16K pages",
 		[VM_MODE_P48V48_64K]	= "PA-bits:48,  VA-bits:48, 64K pages",
@@ -231,6 +234,9 @@ const struct vm_guest_mode_params vm_guest_mode_params[] = {
 	[VM_MODE_P52V48_4K]	= { 52, 48,  0x1000, 12 },
 	[VM_MODE_P52V48_16K]	= { 52, 48,  0x4000, 14 },
 	[VM_MODE_P52V48_64K]	= { 52, 48, 0x10000, 16 },
+	[VM_MODE_P52V52_4K]	= { 52, 52,  0x1000, 12 },
+	[VM_MODE_P52V52_16K]	= { 52, 52,  0x4000, 14 },
+	[VM_MODE_P52V52_64K]	= { 52, 52, 0x10000, 16 },
 	[VM_MODE_P48V48_4K]	= { 48, 48,  0x1000, 12 },
 	[VM_MODE_P48V48_16K]	= { 48, 48,  0x4000, 14 },
 	[VM_MODE_P48V48_64K]	= { 48, 48, 0x10000, 16 },
@@ -298,10 +304,14 @@ struct kvm_vm *____vm_create(struct vm_shape shape)
 
 	/* Setup mode specific traits. */
 	switch (vm->mode) {
+	case VM_MODE_P52V52_4K:
+		vm->mmu.pgtable_levels = 5;
+		break;
 	case VM_MODE_P52V48_4K:
 		vm->mmu.pgtable_levels = 4;
 		break;
 	case VM_MODE_P52V48_64K:
+	case VM_MODE_P52V52_64K:
 		vm->mmu.pgtable_levels = 3;
 		break;
 	case VM_MODE_P48V48_4K:
@@ -322,6 +332,7 @@ struct kvm_vm *____vm_create(struct vm_shape shape)
 	case VM_MODE_P48V48_16K:
 	case VM_MODE_P40V48_16K:
 	case VM_MODE_P36V48_16K:
+	case VM_MODE_P52V52_16K:
 		vm->mmu.pgtable_levels = 4;
 		break;
 	case VM_MODE_P47V47_16K:

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] KVM: selftests: arm64: Add 52-bit VA guest modes
  2026-08-25 21:18 ` [PATCH 2/2] KVM: selftests: arm64: Add 52-bit VA guest modes Itaru Kitayama
@ 2026-08-25 21:32   ` sashiko-bot
  0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-08-25 21:32 UTC (permalink / raw)
  To: Itaru Kitayama; +Cc: Oliver Upton, kvmarm, kvm, Marc Zyngier

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Incorrect TTBR0_EL1 base address encoding for FEAT_LPA2 (4K/16K pages) with 52-bit physical addresses.
--

commit 7fa14109ad0da6af47dd28e3d16f9d1ca4d12232
Author: Itaru Kitayama <itaru.kitayama@fujitsu.com>

KVM: selftests: arm64: Add 52-bit VA guest modes

This commit adds P52V52 guest mode IDs for 4K, 16K, and 64K translation
granules. It advertises the 4KB and 16KB modes when the corresponding
granule supports a 52-bit IPA, and additionally requires 52-bit VA support
for the 64K mode.

> diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c
> index 7a96c43b5704d..4f121e2987e9a 100644
> --- a/tools/testing/selftests/kvm/lib/guest_modes.c
> +++ b/tools/testing/selftests/kvm/lib/guest_modes.c
> @@ -21,10 +21,15 @@ void guest_modes_append_default(void)
>  	{
>  		unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE);
>  		u32 ipa4k, ipa16k, ipa64k;
> +		u32 va;
>  		int i;
>  
>  		aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k);
> +		va = aarch64_get_supported_va_size();
>  
> +		guest_mode_append(VM_MODE_P52V52_4K, ipa4k >= 52);
> +		guest_mode_append(VM_MODE_P52V52_16K, ipa16k >= 52);

[Severity: Medium]
Will this corrupt the TTBR0_EL1 base address for FEAT_LPA2 (4K/16K pages)
guests with 52-bit physical addresses?

When a VM is created with the newly added VM_MODE_P52V52_4K or
VM_MODE_P52V52_16K modes, aarch64_vcpu_setup() configures TTBR0_EL1:

tools/testing/selftests/kvm/lib/arm64/processor.c:aarch64_vcpu_setup() {
	...
	switch (vm->mode) {
	case VM_MODE_P52V52_4K:
	case VM_MODE_P52V52_16K:
	case VM_MODE_P52V52_64K:
	case VM_MODE_P52V48_4K:
	case VM_MODE_P52V48_16K:
	case VM_MODE_P52V48_64K:
		tcr_el1 |= TCR_IPS_52_BITS;
		ttbr0_el1 |= FIELD_GET(GENMASK(51, 48), vm->mmu.pgd) << 2;
		break;
	...
}

Because TCR_EL1.DS is set for these LPA2 modes, the hardware expects the base
address directly in bits [51:x].

However, the code above incorrectly applies the 64K (FEAT_LVA) format instead,
masking out bits 51:48 and shifting them into bits 5:2.

Can this cause a translation fault if the root page table is allocated
above 256TB?

> +		guest_mode_append(VM_MODE_P52V52_64K, ipa64k >= 52 && va >= 52);
>  		guest_mode_append(VM_MODE_P52V48_4K, ipa4k >= 52);
>  		guest_mode_append(VM_MODE_P52V48_16K, ipa16k >= 52);
>  		guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260826-arm64-52bit-va-v1-0-14ec98211363@fujitsu.com?part=2

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] KVM: selftest: arm64: Support 5-level paging in stage 1 translation table
  2026-08-25 21:18 ` [PATCH 1/2] KVM: selftest: arm64: Support 5-level paging in stage 1 translation table Itaru Kitayama
@ 2026-08-25 21:35   ` sashiko-bot
  0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-08-25 21:35 UTC (permalink / raw)
  To: Itaru Kitayama; +Cc: Oliver Upton, Marc Zyngier, kvm, kvmarm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The page table dump function `pte_dump()` is missing the 'p4d' string for 5-level paging.
--

commit a04aa92b1663291806024b3dd2c32f253a43baf3
Author: Itaru Kitayama <itaru.kitayama@fujitsu.com>

KVM: selftest: arm64: Support 5-level paging in stage 1 translation table

Add p4d_index() for when 5-level paging required, i.e., V52 guest mode
IDs. With the index helper function, _virt_pg_map() handles 5-level
paging case, and aarch64_vcpu_setup() now is aware of the new V52 guest
mode IDs.

> diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c
> index 01325bf4d36fc..9108e14a9b5be 100644
> --- a/tools/testing/selftests/kvm/lib/arm64/processor.c
> +++ b/tools/testing/selftests/kvm/lib/arm64/processor.c
[ ... ]
> @@ -182,18 +200,35 @@ void virt_arch_pg_map(struct kvm_vm *vm, gva_t gva, gpa_t gpa)
>  
>  u64 *virt_get_pte_hva_at_level(struct kvm_vm *vm, gva_t gva, int level)
>  {
> +	int start_level = 4 - vm->mmu.pgtable_levels;
>  	u64 *ptep;
>  
> +	TEST_ASSERT(level >= start_level && level <= 3,
> +		    "Invalid translation level %d, valid range is %d-3",
> +		    level, start_level);
> +
>  	if (!vm->mmu.pgd_created)
>  		goto unmapped_gva;
>  
>  	ptep = addr_gpa2hva(vm, vm->mmu.pgd) + pgd_index(vm, gva) * 8;
>  	if (!ptep)
>  		goto unmapped_gva;
> -	if (level == 0)
> +	/*
> +	 * Stage-1 translation starts at level -1 for a five-level page
> +	 * table, and at levels 0, 1, or 2 for four-, three-, or two-level
> +	 * page tables, respectively.
> +	 */
> +	if (level == start_level)
>  		return ptep;
>  
>  	switch (vm->mmu.pgtable_levels) {
> +	case 5:
> +		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + p4d_index(vm, gva) * 8;
> +		if (!ptep)
> +			goto unmapped_gva;
> +		if (level == 0)
> +			break;
> +		/* fall through */
>  	case 4:

[Severity: Low]
Does pte_dump() also need to be updated to handle the new p4d level?

In tools/testing/selftests/kvm/lib/arm64/processor.c:pte_dump():

	static const char * const type[] = { "", "pud", "pmd", "pte" };

With 5-level paging enabled, virt_arch_dump() starts with level 0. The
pte_dump() function will access index 0 and print an empty string instead
of "p4d".

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260826-arm64-52bit-va-v1-0-14ec98211363@fujitsu.com?part=1

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-08-25 21:35 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-25 21:18 [PATCH 0/2] 52-bit VA guest mode ID support Itaru Kitayama
2026-08-25 21:18 ` [PATCH 1/2] KVM: selftest: arm64: Support 5-level paging in stage 1 translation table Itaru Kitayama
2026-08-25 21:35   ` sashiko-bot
2026-08-25 21:18 ` [PATCH 2/2] KVM: selftests: arm64: Add 52-bit VA guest modes Itaru Kitayama
2026-08-25 21:32   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox