kvmarm.lists.cs.columbia.edu archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2
@ 2023-03-06 19:54 Ryan Roberts
  2023-03-06 19:54 ` [PATCH v2 01/12] arm64/mm: Update non-range tlb invalidation routines for FEAT_LPA2 Ryan Roberts
                   ` (12 more replies)
  0 siblings, 13 replies; 24+ messages in thread
From: Ryan Roberts @ 2023-03-06 19:54 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: Ryan Roberts, linux-arm-kernel, kvmarm

Add support for FEAT_LPA2 to KVM for both hypervisor stage 1 (for the
nvhe/protected modes) and the vm stage 2 translation tables (for all modes).
FEAT_LPA2 enables 52 bit PAs and VAs for 4KB and 16KB granules (note this is
already supported for 64KB granules via the FEAT_LPA and FEAT_LVA extensions).
The series does not include support for FEAT_LPA2 in the kernel stage 1. This
support is provided separately by Ard Biesheuvel's series at [1]. The two series
are independent.

These patches are based on top of v6.3-rc1, plus 3 kvm selftests bug-fix
patches, which I have posted separately at [2] and [3]. You can find a tree at
[4]. Those bug-fix patches relate to incorrect test code for 52-bit PA (64K)
guests, and are needed in order to test the new 52-bit 4K and 16K guest modes
that this series enables.


Testing:
Testing has been done exclusively on the FVP and covers the boot matrix tests
and kvm selftests.

The host/guest config boot matrix gives the same (expected) results as
for the v1 submission; of 180 conifgs, 12 fail, and these are all due to
attempting to load the host kernel into high memory which isn't expected to work
until the kernel has FEAT_LPA2 support for its stage 1. (refer to v1 posting for
details on the exact configs).

KVM selftests have been enhanced to support P52V48 4K and 16K guest modes, and
all tests have been run against a P48V48_4K host and a P52V52_4K host (a run
takes about 10 hours on FVP, sigh, but I can test a few more host configs if
useful). All tests pass except "memslot_perf_test", which fails due to a timeout
while syncing. This test fails in the same way for plain v6.3-rc1, so I'm
confident this is not a regression caused by this series. (the issue is that
alarm(2) is issued and the signal is received before alarm(0) is issued. I
expect this is an FVP-time related problem, although I'm not sure how to fix
robustly for the FVP without potentially hanging real systems for long periods
of time).


Changes since v1:
https://lore.kernel.org/kvmarm/20221206135930.3277585-1-ryan.roberts@arm.com/
 - Create CPU feature for LPA2 (enabled if both S1 and S2 report LPA2 support).
 - Use the CPU feature (and therefore code patching) to globally decide whether
   or not to use LPA2 PTE format; no more per-pgtable flag to pass around.
 - Removed the range-based TLBI changes, which are not required by KVM; leaves
   only minor changes to the non-range-based invalidation code.
 - Removed patch to encode/decode VTCR_EL2.SL2, and replaced with a comment
   describing why we never need to touch SL2 (stage 2 always uses concatenated
   first level lookup).
 - Added support for LPA2 guests in KVM selftests (VM_MODE_P52V48_4K enabled and
   new VM_MODE_P52V48_16K added).
 - Rebased onto 6.3-rc1.


[1] https://lore.kernel.org/linux-arm-kernel/20221124123932.2648991-1-ardb@kernel.org
[2] https://lore.kernel.org/kvmarm/20230228170756.769461-1-ryan.roberts@arm.com/
[3] https://lore.kernel.org/kvmarm/20230302152033.242073-1-ryan.roberts@arm.com/
[4] https://gitlab.arm.com/linux-arm/linux-rr/-/tree/features/lpa2/kvm_lkml-v2


Anshuman Khandual (1):
  arm64/mm: Add FEAT_LPA2 specific ID_AA64MMFR0.TGRAN[2]

Ryan Roberts (11):
  arm64/mm: Update non-range tlb invalidation routines for FEAT_LPA2
  KVM: arm64: Add ARM64_HAS_LPA2 CPU capability
  KVM: arm64: Add new (V)TCR_EL2 field definitions for FEAT_LPA2
  KVM: arm64: Use LPA2 page-tables for stage2 if HW supports it
  KVM: arm64: Use LPA2 page-tables for hyp stage1 if HW supports it
  KVM: arm64: Insert PS field at TCR_EL2 assembly time
  KVM: arm64: Convert translation level parameter to s8
  KVM: arm64: Support up to 5 levels of translation in kvm_pgtable
  KVM: arm64: Allow guests with >48-bit IPA size on FEAT_LPA2 systems
  KVM: selftests: arm64: Determine max ipa size per-page size
  KVM: selftests: arm64: Support P52V48 4K and 16K guest_modes

 arch/arm64/include/asm/cpufeature.h           |  5 ++
 arch/arm64/include/asm/kvm_arm.h              |  2 +
 arch/arm64/include/asm/kvm_emulate.h          | 12 ++-
 arch/arm64/include/asm/kvm_pgtable.h          | 72 +++++++++++------
 arch/arm64/include/asm/kvm_pkvm.h             |  5 +-
 arch/arm64/include/asm/sysreg.h               |  5 ++
 arch/arm64/include/asm/tlb.h                  |  9 ++-
 arch/arm64/include/asm/tlbflush.h             | 43 ++++++----
 arch/arm64/kernel/cpufeature.c                | 40 ++++++++++
 arch/arm64/kvm/arm.c                          |  4 +
 arch/arm64/kvm/hyp/nvhe/hyp-init.S            |  4 -
 arch/arm64/kvm/hyp/nvhe/mem_protect.c         |  6 +-
 arch/arm64/kvm/hyp/nvhe/mm.c                  |  4 +-
 arch/arm64/kvm/hyp/nvhe/setup.c               |  2 +-
 arch/arm64/kvm/hyp/pgtable.c                  | 79 ++++++++++++-------
 arch/arm64/kvm/mmu.c                          | 15 ++--
 arch/arm64/kvm/reset.c                        |  9 +--
 arch/arm64/tools/cpucaps                      |  1 +
 .../selftests/kvm/include/aarch64/processor.h |  4 +-
 .../selftests/kvm/include/kvm_util_base.h     |  1 +
 .../selftests/kvm/lib/aarch64/processor.c     | 66 ++++++++++++----
 tools/testing/selftests/kvm/lib/guest_modes.c | 42 +++++-----
 tools/testing/selftests/kvm/lib/kvm_util.c    |  3 +
 23 files changed, 297 insertions(+), 136 deletions(-)

--
2.25.1


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

* [PATCH v2 01/12] arm64/mm: Update non-range tlb invalidation routines for FEAT_LPA2
  2023-03-06 19:54 [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
@ 2023-03-06 19:54 ` Ryan Roberts
  2023-04-12 15:47   ` Catalin Marinas
  2023-03-06 19:54 ` [PATCH v2 02/12] arm64/mm: Add FEAT_LPA2 specific ID_AA64MMFR0.TGRAN[2] Ryan Roberts
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Ryan Roberts @ 2023-03-06 19:54 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: Ryan Roberts, linux-arm-kernel, kvmarm

FEAT_LPA2 impacts tlb invalidation in 2 ways; Firstly, the TTL field in
the non-range tlbi instructions can now validly take a 0 value for the
4KB granule (this is due to the extra level of translation). Secondly,
the BADDR field in the range tlbi instructions must be aligned to 64KB
when LPA2 is in use (TCR.DS=1). Changes are required for tlbi to
continue to operate correctly when LPA2 is in use.

KVM only uses the non-range (__tlbi_level()) routines. Therefore we only
solve the first problem with this patch.

It is solved by always adding the level hint if the level is between [0,
3] (previously anything other than 0 was hinted, which breaks in the new
level -1 case from kvm). When running on non-LPA2 HW, 0 is still safe to
hint as the HW will fall back to non-hinted. While we are at it, we
replace the notion of 0 being the non-hinted seninel with a macro,
TLBI_TTL_UNKNOWN. This means callers won't need updating if/when
translation depth increases in future.

Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
 arch/arm64/include/asm/tlb.h      |  9 ++++---
 arch/arm64/include/asm/tlbflush.h | 43 +++++++++++++++++++------------
 2 files changed, 31 insertions(+), 21 deletions(-)

diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h
index c995d1f4594f..2cb458f6b98f 100644
--- a/arch/arm64/include/asm/tlb.h
+++ b/arch/arm64/include/asm/tlb.h
@@ -22,15 +22,16 @@ static void tlb_flush(struct mmu_gather *tlb);
 #include <asm-generic/tlb.h>
 
 /*
- * get the tlbi levels in arm64.  Default value is 0 if more than one
- * of cleared_* is set or neither is set.
+ * get the tlbi levels in arm64.  Default value is TLBI_TTL_UNKNOWN if more than
+ * one of cleared_* is set or neither is set - this elides the level hinting to
+ * the hardware.
  * Arm64 doesn't support p4ds now.
  */
 static inline int tlb_get_level(struct mmu_gather *tlb)
 {
 	/* The TTL field is only valid for the leaf entry. */
 	if (tlb->freed_tables)
-		return 0;
+		return TLBI_TTL_UNKNOWN;
 
 	if (tlb->cleared_ptes && !(tlb->cleared_pmds ||
 				   tlb->cleared_puds ||
@@ -47,7 +48,7 @@ static inline int tlb_get_level(struct mmu_gather *tlb)
 				   tlb->cleared_p4ds))
 		return 1;
 
-	return 0;
+	return TLBI_TTL_UNKNOWN;
 }
 
 static inline void tlb_flush(struct mmu_gather *tlb)
diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index 412a3b9a3c25..67dd47df42d5 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -93,19 +93,22 @@ static inline unsigned long get_trans_granule(void)
  * When ARMv8.4-TTL exists, TLBI operations take an additional hint for
  * the level at which the invalidation must take place. If the level is
  * wrong, no invalidation may take place. In the case where the level
- * cannot be easily determined, a 0 value for the level parameter will
- * perform a non-hinted invalidation.
+ * cannot be easily determined, the value TLBI_TTL_UNKNOWN will perform
+ * a non-hinted invalidation. Any provided level outside the hint range
+ * will also cause fall-back to non-hinted invalidation.
  *
  * For Stage-2 invalidation, use the level values provided to that effect
  * in asm/stage2_pgtable.h.
  */
 #define TLBI_TTL_MASK		GENMASK_ULL(47, 44)
 
+#define TLBI_TTL_UNKNOWN	(-1)
+
 #define __tlbi_level(op, addr, level) do {				\
 	u64 arg = addr;							\
 									\
 	if (cpus_have_const_cap(ARM64_HAS_ARMv8_4_TTL) &&		\
-	    level) {							\
+	    level >= 0 && level <= 3) {					\
 		u64 ttl = level & 3;					\
 		ttl |= get_trans_granule() << 2;			\
 		arg &= ~TLBI_TTL_MASK;					\
@@ -133,16 +136,17 @@ static inline unsigned long get_trans_granule(void)
  * [BADDR, BADDR + (NUM + 1) * 2^(5*SCALE + 1) * PAGESIZE)
  *
  */
-#define __TLBI_VADDR_RANGE(addr, asid, scale, num, ttl)		\
-	({							\
-		unsigned long __ta = (addr) >> PAGE_SHIFT;	\
-		__ta &= GENMASK_ULL(36, 0);			\
-		__ta |= (unsigned long)(ttl) << 37;		\
-		__ta |= (unsigned long)(num) << 39;		\
-		__ta |= (unsigned long)(scale) << 44;		\
-		__ta |= get_trans_granule() << 46;		\
-		__ta |= (unsigned long)(asid) << 48;		\
-		__ta;						\
+#define __TLBI_VADDR_RANGE(addr, asid, scale, num, ttl)				\
+	({									\
+		unsigned long __ta = (addr) >> PAGE_SHIFT;			\
+		unsigned long __ttl = (ttl >= 1 && ttl <= 3) ? ttl : 0;		\
+		__ta &= GENMASK_ULL(36, 0);					\
+		__ta |= __ttl << 37;						\
+		__ta |= (unsigned long)(num) << 39;				\
+		__ta |= (unsigned long)(scale) << 44;				\
+		__ta |= get_trans_granule() << 46;				\
+		__ta |= (unsigned long)(asid) << 48;				\
+		__ta;								\
 	})
 
 /* These macros are used by the TLBI RANGE feature. */
@@ -215,12 +219,16 @@ static inline unsigned long get_trans_granule(void)
  *		CPUs, ensuring that any walk-cache entries associated with the
  *		translation are also invalidated.
  *
- *	__flush_tlb_range(vma, start, end, stride, last_level)
+ *	__flush_tlb_range(vma, start, end, stride, last_level, tlb_level)
  *		Invalidate the virtual-address range '[start, end)' on all
  *		CPUs for the user address space corresponding to 'vma->mm'.
  *		The invalidation operations are issued at a granularity
  *		determined by 'stride' and only affect any walk-cache entries
- *		if 'last_level' is equal to false.
+ *		if 'last_level' is equal to false. tlb_level is the level at
+ *		which the invalidation must take place. If the level is wrong,
+ *		no invalidation may take place. In the case where the level
+ *		cannot be easily determined, the value TLBI_TTL_UNKNOWN will
+ *		perform a non-hinted invalidation.
  *
  *
  *	Finally, take a look at asm/tlb.h to see how tlb_flush() is implemented
@@ -366,9 +374,10 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
 	/*
 	 * We cannot use leaf-only invalidation here, since we may be invalidating
 	 * table entries as part of collapsing hugepages or moving page tables.
-	 * Set the tlb_level to 0 because we can not get enough information here.
+	 * Set the tlb_level to TLBI_TTL_UNKNOWN because we can not get enough
+	 * information here.
 	 */
-	__flush_tlb_range(vma, start, end, PAGE_SIZE, false, 0);
+	__flush_tlb_range(vma, start, end, PAGE_SIZE, false, TLBI_TTL_UNKNOWN);
 }
 
 static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
-- 
2.25.1


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

* [PATCH v2 02/12] arm64/mm: Add FEAT_LPA2 specific ID_AA64MMFR0.TGRAN[2]
  2023-03-06 19:54 [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
  2023-03-06 19:54 ` [PATCH v2 01/12] arm64/mm: Update non-range tlb invalidation routines for FEAT_LPA2 Ryan Roberts
@ 2023-03-06 19:54 ` Ryan Roberts
  2023-04-12 16:27   ` Catalin Marinas
  2023-03-06 19:54 ` [PATCH v2 03/12] KVM: arm64: Add ARM64_HAS_LPA2 CPU capability Ryan Roberts
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Ryan Roberts @ 2023-03-06 19:54 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: Ryan Roberts, linux-arm-kernel, kvmarm

From: Anshuman Khandual <anshuman.khandual@arm.com>

PAGE_SIZE support is tested against possible minimum and maximum values for
its respective ID_AA64MMFR0.TGRAN field, depending on whether it is signed
or unsigned. But then FEAT_LPA2 implementation needs to be validated for 4K
and 16K page sizes via feature specific ID_AA64MMFR0.TGRAN values. Hence it
adds FEAT_LPA2 specific ID_AA64MMFR0.TGRAN[2] values per ARM ARM (0487G.A).

Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
 arch/arm64/include/asm/sysreg.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 9e3ecba3c4e6..7f708eecc3ad 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -609,10 +609,12 @@
 
 /* id_aa64mmfr0 */
 #define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN	0x0
+#define ID_AA64MMFR0_EL1_TGRAN4_LPA2		ID_AA64MMFR0_EL1_TGRAN4_52_BIT
 #define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MAX	0x7
 #define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MIN	0x0
 #define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MAX	0x7
 #define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MIN	0x1
+#define ID_AA64MMFR0_EL1_TGRAN16_LPA2		ID_AA64MMFR0_EL1_TGRAN16_52_BIT
 #define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MAX	0xf
 
 #define ARM64_MIN_PARANGE_BITS		32
@@ -620,6 +622,7 @@
 #define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_DEFAULT	0x0
 #define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_NONE		0x1
 #define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_MIN		0x2
+#define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_LPA2		0x3
 #define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_MAX		0x7
 
 #ifdef CONFIG_ARM64_PA_BITS_52
@@ -630,11 +633,13 @@
 
 #if defined(CONFIG_ARM64_4K_PAGES)
 #define ID_AA64MMFR0_EL1_TGRAN_SHIFT		ID_AA64MMFR0_EL1_TGRAN4_SHIFT
+#define ID_AA64MMFR0_EL1_TGRAN_LPA2		ID_AA64MMFR0_EL1_TGRAN4_52_BIT
 #define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN	ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN
 #define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX	ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MAX
 #define ID_AA64MMFR0_EL1_TGRAN_2_SHIFT		ID_AA64MMFR0_EL1_TGRAN4_2_SHIFT
 #elif defined(CONFIG_ARM64_16K_PAGES)
 #define ID_AA64MMFR0_EL1_TGRAN_SHIFT		ID_AA64MMFR0_EL1_TGRAN16_SHIFT
+#define ID_AA64MMFR0_EL1_TGRAN_LPA2		ID_AA64MMFR0_EL1_TGRAN16_52_BIT
 #define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN	ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MIN
 #define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX	ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MAX
 #define ID_AA64MMFR0_EL1_TGRAN_2_SHIFT		ID_AA64MMFR0_EL1_TGRAN16_2_SHIFT
-- 
2.25.1


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

* [PATCH v2 03/12] KVM: arm64: Add ARM64_HAS_LPA2 CPU capability
  2023-03-06 19:54 [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
  2023-03-06 19:54 ` [PATCH v2 01/12] arm64/mm: Update non-range tlb invalidation routines for FEAT_LPA2 Ryan Roberts
  2023-03-06 19:54 ` [PATCH v2 02/12] arm64/mm: Add FEAT_LPA2 specific ID_AA64MMFR0.TGRAN[2] Ryan Roberts
@ 2023-03-06 19:54 ` Ryan Roberts
  2023-03-06 19:54 ` [PATCH v2 04/12] KVM: arm64: Add new (V)TCR_EL2 field definitions for FEAT_LPA2 Ryan Roberts
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Ryan Roberts @ 2023-03-06 19:54 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: Ryan Roberts, linux-arm-kernel, kvmarm

Expose FEAT_LPA2 as a capability so that we can take advantage of
alternatives patching in both the kernel and hypervisor.

Although FEAT_LPA2 presence is advertised separately for stage1 and
stage2, the expectation is that in practice both stages will either
support or not support it. Therefore we combine both into a single
capability, allowing us to simplify the implementation.

Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
 arch/arm64/include/asm/cpufeature.h |  5 ++++
 arch/arm64/kernel/cpufeature.c      | 40 +++++++++++++++++++++++++++++
 arch/arm64/tools/cpucaps            |  1 +
 3 files changed, 46 insertions(+)

diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 6bf013fb110d..59e4bf2341af 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -838,6 +838,11 @@ static inline bool system_supports_tlb_range(void)
 		cpus_have_const_cap(ARM64_HAS_TLB_RANGE);
 }
 
+static inline bool system_supports_lpa2(void)
+{
+	return cpus_have_const_cap(ARM64_HAS_LPA2);
+}
+
 int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
 bool try_emulate_mrs(struct pt_regs *regs, u32 isn);
 
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 2e3e55139777..07b952e087bb 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -1715,6 +1715,40 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
 	return !meltdown_safe;
 }
 
+static inline bool has_lpa2_at_stage1(u64 mmfr0)
+{
+#if defined(CONFIG_ARM64_4K_PAGES) || defined(CONFIG_ARM64_16K_PAGES)
+	unsigned int tgran;
+
+	tgran = cpuid_feature_extract_unsigned_field(mmfr0,
+						ID_AA64MMFR0_EL1_TGRAN_SHIFT);
+	return tgran == ID_AA64MMFR0_EL1_TGRAN_LPA2;
+#else
+	return false;
+#endif
+}
+
+static inline bool has_lpa2_at_stage2(u64 mmfr0)
+{
+#if defined(CONFIG_ARM64_4K_PAGES) || defined(CONFIG_ARM64_16K_PAGES)
+	unsigned int tgran;
+
+	tgran = cpuid_feature_extract_unsigned_field(mmfr0,
+						ID_AA64MMFR0_EL1_TGRAN_2_SHIFT);
+	return tgran == ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_LPA2;
+#else
+	return false;
+#endif
+}
+
+static bool has_lpa2(const struct arm64_cpu_capabilities *entry, int scope)
+{
+	u64 mmfr0;
+
+	mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
+	return has_lpa2_at_stage1(mmfr0) && has_lpa2_at_stage2(mmfr0);
+}
+
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
 #define KPTI_NG_TEMP_VA		(-(1UL << PMD_SHIFT))
 
@@ -2772,6 +2806,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.matches = has_cpuid_feature,
 		.cpu_enable = cpu_enable_dit,
 	},
+	{
+		.desc = "Large Physical Address 2",
+		.capability = ARM64_HAS_LPA2,
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.matches = has_lpa2,
+	},
 	{},
 };
 
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index 37b1340e9646..a9c5d453d473 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -32,6 +32,7 @@ HAS_GIC_CPUIF_SYSREGS
 HAS_GIC_PRIO_MASKING
 HAS_GIC_PRIO_RELAXED_SYNC
 HAS_LDAPR
+HAS_LPA2
 HAS_LSE_ATOMICS
 HAS_NESTED_VIRT
 HAS_NO_FPSIMD
-- 
2.25.1


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

* [PATCH v2 04/12] KVM: arm64: Add new (V)TCR_EL2 field definitions for FEAT_LPA2
  2023-03-06 19:54 [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
                   ` (2 preceding siblings ...)
  2023-03-06 19:54 ` [PATCH v2 03/12] KVM: arm64: Add ARM64_HAS_LPA2 CPU capability Ryan Roberts
@ 2023-03-06 19:54 ` Ryan Roberts
  2023-04-12 16:36   ` Catalin Marinas
  2023-03-06 19:54 ` [PATCH v2 05/12] KVM: arm64: Use LPA2 page-tables for stage2 if HW supports it Ryan Roberts
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Ryan Roberts @ 2023-03-06 19:54 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: Ryan Roberts, linux-arm-kernel, kvmarm

As per Arm ARM (0487I.a), (V)TCR_EL2.DS fields control whether 52 bit
input and output addresses are supported on 4K and 16K page size
configurations when FEAT_LPA2 is known to have been implemented.

This adds these field definitions which will be used by KVM when
FEAT_LPA2 is enabled.

Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
 arch/arm64/include/asm/kvm_arm.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index baef29fcbeee..c31460b5457c 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -93,6 +93,7 @@
 #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
 
 /* TCR_EL2 Registers bits */
+#define TCR_EL2_DS		(1UL << 32)
 #define TCR_EL2_RES1		((1U << 31) | (1 << 23))
 #define TCR_EL2_TBI		(1 << 20)
 #define TCR_EL2_PS_SHIFT	16
@@ -107,6 +108,7 @@
 			 TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK | TCR_EL2_T0SZ_MASK)
 
 /* VTCR_EL2 Registers bits */
+#define VTCR_EL2_DS		TCR_EL2_DS
 #define VTCR_EL2_RES1		(1U << 31)
 #define VTCR_EL2_HD		(1 << 22)
 #define VTCR_EL2_HA		(1 << 21)
-- 
2.25.1


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

* [PATCH v2 05/12] KVM: arm64: Use LPA2 page-tables for stage2 if HW supports it
  2023-03-06 19:54 [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
                   ` (3 preceding siblings ...)
  2023-03-06 19:54 ` [PATCH v2 04/12] KVM: arm64: Add new (V)TCR_EL2 field definitions for FEAT_LPA2 Ryan Roberts
@ 2023-03-06 19:54 ` Ryan Roberts
  2023-03-06 19:54 ` [PATCH v2 06/12] KVM: arm64: Use LPA2 page-tables for hyp stage1 " Ryan Roberts
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Ryan Roberts @ 2023-03-06 19:54 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: Ryan Roberts, linux-arm-kernel, kvmarm

Implement a simple policy whereby if the HW supports FEAT_LPA2 for the
page size we are using, always use LPA2-style page-tables for stage 2,
regardless of the VMM-requested IPA size or HW-implemented PA size. When
in use we can now support up to 52-bit IPA and PA sizes.

We use the previously created cpu feature to track whether LPA2 is
supported for deciding whether to use the LPA2 or classic pte format.

Note that FEAT_LPA2 brings support for bigger block mappings (512GB with
4KB, 64GB with 16KB). We explicitly don't enable these in the library
because stage2_apply_range() works on batch sizes of the largest used
block mapping, and increasing the size of the batch would lead to soft
lockups. See commit 5994bc9e05c2 ("KVM: arm64: Limit
stage2_apply_range() batch size to largest block").

Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>

TMP
---
 arch/arm64/include/asm/kvm_pgtable.h | 47 +++++++++++++++++++++-------
 arch/arm64/kvm/hyp/pgtable.c         | 12 +++++--
 2 files changed, 46 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
index 4cd6762bda80..4164b336c1e7 100644
--- a/arch/arm64/include/asm/kvm_pgtable.h
+++ b/arch/arm64/include/asm/kvm_pgtable.h
@@ -25,12 +25,22 @@
 #define KVM_PGTABLE_MIN_BLOCK_LEVEL	2U
 #endif
 
+static inline u64 kvm_get_parange_max(void)
+{
+	if (system_supports_lpa2() ||
+	   (IS_ENABLED(CONFIG_ARM64_PA_BITS_52) && PAGE_SIZE == SZ_64K))
+		return ID_AA64MMFR0_EL1_PARANGE_52;
+	else
+		return ID_AA64MMFR0_EL1_PARANGE_48;
+}
+
 static inline u64 kvm_get_parange(u64 mmfr0)
 {
+	u64 parange_max = kvm_get_parange_max();
 	u64 parange = cpuid_feature_extract_unsigned_field(mmfr0,
 				ID_AA64MMFR0_EL1_PARANGE_SHIFT);
-	if (parange > ID_AA64MMFR0_EL1_PARANGE_MAX)
-		parange = ID_AA64MMFR0_EL1_PARANGE_MAX;
+	if (parange > parange_max)
+		parange = parange_max;
 
 	return parange;
 }
@@ -41,6 +51,8 @@ typedef u64 kvm_pte_t;
 
 #define KVM_PTE_ADDR_MASK		GENMASK(47, PAGE_SHIFT)
 #define KVM_PTE_ADDR_51_48		GENMASK(15, 12)
+#define KVM_PTE_ADDR_MASK_LPA2		GENMASK(49, PAGE_SHIFT)
+#define KVM_PTE_ADDR_51_50_LPA2		GENMASK(9, 8)
 
 #define KVM_PHYS_INVALID		(-1ULL)
 
@@ -51,21 +63,34 @@ static inline bool kvm_pte_valid(kvm_pte_t pte)
 
 static inline u64 kvm_pte_to_phys(kvm_pte_t pte)
 {
-	u64 pa = pte & KVM_PTE_ADDR_MASK;
-
-	if (PAGE_SHIFT == 16)
-		pa |= FIELD_GET(KVM_PTE_ADDR_51_48, pte) << 48;
+	u64 pa;
+
+	if (system_supports_lpa2()) {
+		pa = pte & KVM_PTE_ADDR_MASK_LPA2;
+		pa |= FIELD_GET(KVM_PTE_ADDR_51_50_LPA2, pte) << 50;
+	} else {
+		pa = pte & KVM_PTE_ADDR_MASK;
+		if (PAGE_SHIFT == 16)
+			pa |= FIELD_GET(KVM_PTE_ADDR_51_48, pte) << 48;
+	}
 
 	return pa;
 }
 
 static inline kvm_pte_t kvm_phys_to_pte(u64 pa)
 {
-	kvm_pte_t pte = pa & KVM_PTE_ADDR_MASK;
-
-	if (PAGE_SHIFT == 16) {
-		pa &= GENMASK(51, 48);
-		pte |= FIELD_PREP(KVM_PTE_ADDR_51_48, pa >> 48);
+	kvm_pte_t pte;
+
+	if (system_supports_lpa2()) {
+		pte = pa & KVM_PTE_ADDR_MASK_LPA2;
+		pa &= GENMASK(51, 50);
+		pte |= FIELD_PREP(KVM_PTE_ADDR_51_50_LPA2, pa >> 50);
+	} else {
+		pte = pa & KVM_PTE_ADDR_MASK;
+		if (PAGE_SHIFT == 16) {
+			pa &= GENMASK(51, 48);
+			pte |= FIELD_PREP(KVM_PTE_ADDR_51_48, pa >> 48);
+		}
 	}
 
 	return pte;
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index 3d61bd3e591d..414a5dbf233d 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -64,7 +64,10 @@ struct kvm_pgtable_walk_data {
 
 static bool kvm_phys_is_valid(u64 phys)
 {
-	return phys < BIT(id_aa64mmfr0_parange_to_phys_shift(ID_AA64MMFR0_EL1_PARANGE_MAX));
+	u64 parange_max = kvm_get_parange_max();
+	u8 shift = id_aa64mmfr0_parange_to_phys_shift(parange_max);
+
+	return phys < BIT(shift);
 }
 
 static bool kvm_block_mapping_supported(const struct kvm_pgtable_visit_ctx *ctx, u64 phys)
@@ -615,6 +618,9 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
 	vtcr |= VTCR_EL2_HA;
 #endif /* CONFIG_ARM64_HW_AFDBM */
 
+	if (system_supports_lpa2())
+		vtcr |= VTCR_EL2_DS;
+
 	/* Set the vmid bits */
 	vtcr |= (get_vmid_bits(mmfr1) == 16) ?
 		VTCR_EL2_VS_16BIT :
@@ -652,7 +658,9 @@ static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot p
 	if (prot & KVM_PGTABLE_PROT_W)
 		attr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
 
-	attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S2_SH, sh);
+	if (!system_supports_lpa2())
+		attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S2_SH, sh);
+
 	attr |= KVM_PTE_LEAF_ATTR_LO_S2_AF;
 	attr |= prot & KVM_PTE_LEAF_ATTR_HI_SW;
 	*ptep = attr;
-- 
2.25.1


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

* [PATCH v2 06/12] KVM: arm64: Use LPA2 page-tables for hyp stage1 if HW supports it
  2023-03-06 19:54 [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
                   ` (4 preceding siblings ...)
  2023-03-06 19:54 ` [PATCH v2 05/12] KVM: arm64: Use LPA2 page-tables for stage2 if HW supports it Ryan Roberts
@ 2023-03-06 19:54 ` Ryan Roberts
  2023-04-12 17:06   ` Catalin Marinas
  2023-03-06 19:54 ` [PATCH v2 07/12] KVM: arm64: Insert PS field at TCR_EL2 assembly time Ryan Roberts
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Ryan Roberts @ 2023-03-06 19:54 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: Ryan Roberts, linux-arm-kernel, kvmarm

Implement a simple policy whereby if the HW supports FEAT_LPA2 for the
page size we are using, always use LPA2-style page-tables for hyp stage
1, regardless of the IPA or PA size requirements. When in use we can now
support up to 52-bit IPA and PA sizes.

Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
 arch/arm64/kvm/arm.c         | 2 ++
 arch/arm64/kvm/hyp/pgtable.c | 3 ++-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 3bd732eaf087..bef73c484162 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -1548,6 +1548,8 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
 	tcr = (read_sysreg(tcr_el1) & TCR_EL2_MASK) | TCR_EL2_RES1;
 	tcr &= ~TCR_T0SZ_MASK;
 	tcr |= TCR_T0SZ(hyp_va_bits);
+	if (system_supports_lpa2())
+		tcr |= TCR_EL2_DS;
 	params->tcr_el2 = tcr;
 
 	params->pgd_pa = kvm_mmu_get_httbr();
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index 414a5dbf233d..bb481d6c7f2d 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -379,7 +379,8 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
 	}
 
 	attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_AP, ap);
-	attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_SH, sh);
+	if (!system_supports_lpa2())
+		attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_SH, sh);
 	attr |= KVM_PTE_LEAF_ATTR_LO_S1_AF;
 	attr |= prot & KVM_PTE_LEAF_ATTR_HI_SW;
 	*ptep = attr;
-- 
2.25.1


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

* [PATCH v2 07/12] KVM: arm64: Insert PS field at TCR_EL2 assembly time
  2023-03-06 19:54 [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
                   ` (5 preceding siblings ...)
  2023-03-06 19:54 ` [PATCH v2 06/12] KVM: arm64: Use LPA2 page-tables for hyp stage1 " Ryan Roberts
@ 2023-03-06 19:54 ` Ryan Roberts
  2023-03-06 19:54 ` [PATCH v2 08/12] KVM: arm64: Convert translation level parameter to s8 Ryan Roberts
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Ryan Roberts @ 2023-03-06 19:54 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: Ryan Roberts, linux-arm-kernel, kvmarm

With the addition of LPA2 support in the hypervisor, the PA size
supported by the HW must be capped with a runtime decision, rather than
simply using a compile-time decision based on PA_BITS. For example, on a
system that advertises 52 bit PA but does not support FEAT_LPA2, A 4KB
or 16KB kernel compiled with LPA2 support must still limit the PA size
to 48 bits.

Therefore, move the insertion of the PS field into TCR_EL2 out of
__kvm_hyp_init assembly code and instead do it in cpu_prepare_hyp_mode()
where the rest of TCR_EL2 is assembled. This allows us to figure out PS
with kvm_get_parange(), which has the appropriate logic to ensure the
above requirement. (and the PS field of VTCR_EL2 is already populated
this way).

Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
 arch/arm64/kvm/arm.c               | 2 ++
 arch/arm64/kvm/hyp/nvhe/hyp-init.S | 4 ----
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index bef73c484162..e537d4485d1c 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -1533,6 +1533,7 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
 {
 	struct kvm_nvhe_init_params *params = per_cpu_ptr_nvhe_sym(kvm_init_params, cpu);
 	unsigned long tcr;
+	u64 mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
 
 	/*
 	 * Calculate the raw per-cpu offset without a translation from the
@@ -1548,6 +1549,7 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
 	tcr = (read_sysreg(tcr_el1) & TCR_EL2_MASK) | TCR_EL2_RES1;
 	tcr &= ~TCR_T0SZ_MASK;
 	tcr |= TCR_T0SZ(hyp_va_bits);
+	tcr |= kvm_get_parange(mmfr0) << TCR_EL2_PS_SHIFT;
 	if (system_supports_lpa2())
 		tcr |= TCR_EL2_DS;
 	params->tcr_el2 = tcr;
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-init.S b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
index a6d67c2bb5ae..c11bef588b63 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
@@ -108,11 +108,7 @@ alternative_if ARM64_HAS_CNP
 alternative_else_nop_endif
 	msr	ttbr0_el2, x2
 
-	/*
-	 * Set the PS bits in TCR_EL2.
-	 */
 	ldr	x0, [x0, #NVHE_INIT_TCR_EL2]
-	tcr_compute_pa_size x0, #TCR_EL2_PS_SHIFT, x1, x2
 	msr	tcr_el2, x0
 
 	isb
-- 
2.25.1


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

* [PATCH v2 08/12] KVM: arm64: Convert translation level parameter to s8
  2023-03-06 19:54 [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
                   ` (6 preceding siblings ...)
  2023-03-06 19:54 ` [PATCH v2 07/12] KVM: arm64: Insert PS field at TCR_EL2 assembly time Ryan Roberts
@ 2023-03-06 19:54 ` Ryan Roberts
  2023-03-06 19:54 ` [PATCH v2 09/12] KVM: arm64: Support up to 5 levels of translation in kvm_pgtable Ryan Roberts
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Ryan Roberts @ 2023-03-06 19:54 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: Ryan Roberts, linux-arm-kernel, kvmarm

With the introduction of FEAT_LPA2, the Arm ARM adds a new level of
translation, level -1, so levels can now be in the range [-1;3]. 3 is
always the last level and the first level is determined based on the
number of VA bits in use.

Convert level variables to use a signed type in preparation for
supporting this new level -1.

Since the last level is always anchored at 3, and the first level varies
to suit the number of VA/IPA bits, take the opportunity to replace
KVM_PGTABLE_MAX_LEVELS with the 2 macros KVM_PGTABLE_FIRST_LEVEL and
KVM_PGTABLE_LAST_LEVEL. This removes the assumption from the code that
levels run from 0 to KVM_PGTABLE_MAX_LEVELS - 1, which will soon no
longer be true.

No behavioral changes intended.

Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
 arch/arm64/include/asm/kvm_emulate.h  |  2 +-
 arch/arm64/include/asm/kvm_pgtable.h  | 25 +++++++------
 arch/arm64/include/asm/kvm_pkvm.h     |  5 ++-
 arch/arm64/kvm/hyp/nvhe/mem_protect.c |  6 +--
 arch/arm64/kvm/hyp/nvhe/mm.c          |  4 +-
 arch/arm64/kvm/hyp/nvhe/setup.c       |  2 +-
 arch/arm64/kvm/hyp/pgtable.c          | 54 ++++++++++++++-------------
 arch/arm64/kvm/mmu.c                  | 15 ++++----
 8 files changed, 60 insertions(+), 53 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index b31b32ecbe2d..26666a623fa8 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -403,7 +403,7 @@ static __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vc
 	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_TYPE;
 }
 
-static __always_inline u8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu)
+static __always_inline s8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu)
 {
 	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_LEVEL;
 }
diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
index 4164b336c1e7..8c7e65147777 100644
--- a/arch/arm64/include/asm/kvm_pgtable.h
+++ b/arch/arm64/include/asm/kvm_pgtable.h
@@ -11,7 +11,8 @@
 #include <linux/kvm_host.h>
 #include <linux/types.h>
 
-#define KVM_PGTABLE_MAX_LEVELS		4U
+#define KVM_PGTABLE_FIRST_LEVEL		0
+#define KVM_PGTABLE_LAST_LEVEL		3
 
 /*
  * The largest supported block sizes for KVM (no 52-bit PA support):
@@ -20,9 +21,9 @@
  *  - 64K (level 2):	512MB
  */
 #ifdef CONFIG_ARM64_4K_PAGES
-#define KVM_PGTABLE_MIN_BLOCK_LEVEL	1U
+#define KVM_PGTABLE_MIN_BLOCK_LEVEL	1
 #else
-#define KVM_PGTABLE_MIN_BLOCK_LEVEL	2U
+#define KVM_PGTABLE_MIN_BLOCK_LEVEL	2
 #endif
 
 static inline u64 kvm_get_parange_max(void)
@@ -101,18 +102,18 @@ static inline kvm_pfn_t kvm_pte_to_pfn(kvm_pte_t pte)
 	return __phys_to_pfn(kvm_pte_to_phys(pte));
 }
 
-static inline u64 kvm_granule_shift(u32 level)
+static inline u64 kvm_granule_shift(s8 level)
 {
-	/* Assumes KVM_PGTABLE_MAX_LEVELS is 4 */
+	/* Assumes KVM_PGTABLE_LAST_LEVEL is 3 */
 	return ARM64_HW_PGTABLE_LEVEL_SHIFT(level);
 }
 
-static inline u64 kvm_granule_size(u32 level)
+static inline u64 kvm_granule_size(s8 level)
 {
 	return BIT(kvm_granule_shift(level));
 }
 
-static inline bool kvm_level_supports_block_mapping(u32 level)
+static inline bool kvm_level_supports_block_mapping(s8 level)
 {
 	return level >= KVM_PGTABLE_MIN_BLOCK_LEVEL;
 }
@@ -149,7 +150,7 @@ struct kvm_pgtable_mm_ops {
 	void*		(*zalloc_page)(void *arg);
 	void*		(*zalloc_pages_exact)(size_t size);
 	void		(*free_pages_exact)(void *addr, size_t size);
-	void		(*free_removed_table)(void *addr, u32 level);
+	void		(*free_removed_table)(void *addr, s8 level);
 	void		(*get_page)(void *addr);
 	void		(*put_page)(void *addr);
 	int		(*page_count)(void *addr);
@@ -236,7 +237,7 @@ struct kvm_pgtable_visit_ctx {
 	struct kvm_pgtable_mm_ops		*mm_ops;
 	u64					addr;
 	u64					end;
-	u32					level;
+	s8					level;
 	enum kvm_pgtable_walk_flags		flags;
 };
 
@@ -339,7 +340,7 @@ static inline bool kvm_pgtable_walk_lock_held(void)
  */
 struct kvm_pgtable {
 	u32					ia_bits;
-	u32					start_level;
+	s8					start_level;
 	kvm_pteref_t				pgd;
 	struct kvm_pgtable_mm_ops		*mm_ops;
 
@@ -473,7 +474,7 @@ void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt);
  * The page-table is assumed to be unreachable by any hardware walkers prior to
  * freeing and therefore no TLB invalidation is performed.
  */
-void kvm_pgtable_stage2_free_removed(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, u32 level);
+void kvm_pgtable_stage2_free_removed(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, s8 level);
 
 /**
  * kvm_pgtable_stage2_map() - Install a mapping in a guest stage-2 page-table.
@@ -686,7 +687,7 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 size,
  * Return: 0 on success, negative error code on failure.
  */
 int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr,
-			 kvm_pte_t *ptep, u32 *level);
+			 kvm_pte_t *ptep, s8 *level);
 
 /**
  * kvm_pgtable_stage2_pte_prot() - Retrieve the protection attributes of a
diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h
index 01129b0d4c68..0d091086fb00 100644
--- a/arch/arm64/include/asm/kvm_pkvm.h
+++ b/arch/arm64/include/asm/kvm_pkvm.h
@@ -54,10 +54,11 @@ static inline unsigned long hyp_vm_table_pages(void)
 
 static inline unsigned long __hyp_pgtable_max_pages(unsigned long nr_pages)
 {
-	unsigned long total = 0, i;
+	unsigned long total = 0;
+	int i;
 
 	/* Provision the worst case scenario */
-	for (i = 0; i < KVM_PGTABLE_MAX_LEVELS; i++) {
+	for (i = KVM_PGTABLE_FIRST_LEVEL; i <= KVM_PGTABLE_LAST_LEVEL; i++) {
 		nr_pages = DIV_ROUND_UP(nr_pages, PTRS_PER_PTE);
 		total += nr_pages;
 	}
diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
index 552653fa18be..f35dc9f1d6b0 100644
--- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c
+++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
@@ -91,7 +91,7 @@ static void host_s2_put_page(void *addr)
 	hyp_put_page(&host_s2_pool, addr);
 }
 
-static void host_s2_free_removed_table(void *addr, u32 level)
+static void host_s2_free_removed_table(void *addr, s8 level)
 {
 	kvm_pgtable_stage2_free_removed(&host_mmu.mm_ops, addr, level);
 }
@@ -436,7 +436,7 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range)
 {
 	struct kvm_mem_range cur;
 	kvm_pte_t pte;
-	u32 level;
+	s8 level;
 	int ret;
 
 	hyp_assert_lock_held(&host_mmu.lock);
@@ -455,7 +455,7 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range)
 		cur.start = ALIGN_DOWN(addr, granule);
 		cur.end = cur.start + granule;
 		level++;
-	} while ((level < KVM_PGTABLE_MAX_LEVELS) &&
+	} while ((level <= KVM_PGTABLE_LAST_LEVEL) &&
 			!(kvm_level_supports_block_mapping(level) &&
 			  range_included(&cur, range)));
 
diff --git a/arch/arm64/kvm/hyp/nvhe/mm.c b/arch/arm64/kvm/hyp/nvhe/mm.c
index 318298eb3d6b..e29a1a417640 100644
--- a/arch/arm64/kvm/hyp/nvhe/mm.c
+++ b/arch/arm64/kvm/hyp/nvhe/mm.c
@@ -250,7 +250,7 @@ static void fixmap_clear_slot(struct hyp_fixmap_slot *slot)
 	 * https://lore.kernel.org/kvm/20221017115209.2099-1-will@kernel.org/T/#mf10dfbaf1eaef9274c581b81c53758918c1d0f03
 	 */
 	dsb(ishst);
-	__tlbi_level(vale2is, __TLBI_VADDR(addr, 0), (KVM_PGTABLE_MAX_LEVELS - 1));
+	__tlbi_level(vale2is, __TLBI_VADDR(addr, 0), KVM_PGTABLE_LAST_LEVEL);
 	dsb(ish);
 	isb();
 }
@@ -265,7 +265,7 @@ static int __create_fixmap_slot_cb(const struct kvm_pgtable_visit_ctx *ctx,
 {
 	struct hyp_fixmap_slot *slot = per_cpu_ptr(&fixmap_slots, (u64)ctx->arg);
 
-	if (!kvm_pte_valid(ctx->old) || ctx->level != KVM_PGTABLE_MAX_LEVELS - 1)
+	if (!kvm_pte_valid(ctx->old) || ctx->level != KVM_PGTABLE_LAST_LEVEL)
 		return -EINVAL;
 
 	slot->addr = ctx->addr;
diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c
index 110f04627785..db09ab3d70bc 100644
--- a/arch/arm64/kvm/hyp/nvhe/setup.c
+++ b/arch/arm64/kvm/hyp/nvhe/setup.c
@@ -199,7 +199,7 @@ static int fix_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx,
 	if (!kvm_pte_valid(ctx->old))
 		return 0;
 
-	if (ctx->level != (KVM_PGTABLE_MAX_LEVELS - 1))
+	if (ctx->level != KVM_PGTABLE_LAST_LEVEL)
 		return -EINVAL;
 
 	phys = kvm_pte_to_phys(ctx->old);
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index bb481d6c7f2d..939eab245205 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -86,7 +86,7 @@ static bool kvm_block_mapping_supported(const struct kvm_pgtable_visit_ctx *ctx,
 	return IS_ALIGNED(ctx->addr, granule);
 }
 
-static u32 kvm_pgtable_idx(struct kvm_pgtable_walk_data *data, u32 level)
+static u32 kvm_pgtable_idx(struct kvm_pgtable_walk_data *data, s8 level)
 {
 	u64 shift = kvm_granule_shift(level);
 	u64 mask = BIT(PAGE_SHIFT - 3) - 1;
@@ -102,7 +102,7 @@ static u32 kvm_pgd_page_idx(struct kvm_pgtable *pgt, u64 addr)
 	return (addr & mask) >> shift;
 }
 
-static u32 kvm_pgd_pages(u32 ia_bits, u32 start_level)
+static u32 kvm_pgd_pages(u32 ia_bits, s8 start_level)
 {
 	struct kvm_pgtable pgt = {
 		.ia_bits	= ia_bits,
@@ -112,9 +112,9 @@ static u32 kvm_pgd_pages(u32 ia_bits, u32 start_level)
 	return kvm_pgd_page_idx(&pgt, -1ULL) + 1;
 }
 
-static bool kvm_pte_table(kvm_pte_t pte, u32 level)
+static bool kvm_pte_table(kvm_pte_t pte, s8 level)
 {
-	if (level == KVM_PGTABLE_MAX_LEVELS - 1)
+	if (level == KVM_PGTABLE_LAST_LEVEL)
 		return false;
 
 	if (!kvm_pte_valid(pte))
@@ -142,11 +142,11 @@ static kvm_pte_t kvm_init_table_pte(kvm_pte_t *childp, struct kvm_pgtable_mm_ops
 	return pte;
 }
 
-static kvm_pte_t kvm_init_valid_leaf_pte(u64 pa, kvm_pte_t attr, u32 level)
+static kvm_pte_t kvm_init_valid_leaf_pte(u64 pa, kvm_pte_t attr, s8 level)
 {
 	kvm_pte_t pte = kvm_phys_to_pte(pa);
-	u64 type = (level == KVM_PGTABLE_MAX_LEVELS - 1) ? KVM_PTE_TYPE_PAGE :
-							   KVM_PTE_TYPE_BLOCK;
+	u64 type = (level == KVM_PGTABLE_LAST_LEVEL) ? KVM_PTE_TYPE_PAGE :
+						       KVM_PTE_TYPE_BLOCK;
 
 	pte |= attr & (KVM_PTE_LEAF_ATTR_LO | KVM_PTE_LEAF_ATTR_HI);
 	pte |= FIELD_PREP(KVM_PTE_TYPE, type);
@@ -191,11 +191,11 @@ static bool kvm_pgtable_walk_continue(const struct kvm_pgtable_walker *walker,
 }
 
 static int __kvm_pgtable_walk(struct kvm_pgtable_walk_data *data,
-			      struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, u32 level);
+			      struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, s8 level);
 
 static inline int __kvm_pgtable_visit(struct kvm_pgtable_walk_data *data,
 				      struct kvm_pgtable_mm_ops *mm_ops,
-				      kvm_pteref_t pteref, u32 level)
+				      kvm_pteref_t pteref, s8 level)
 {
 	enum kvm_pgtable_walk_flags flags = data->walker->flags;
 	kvm_pte_t *ptep = kvm_dereference_pteref(data->walker, pteref);
@@ -247,12 +247,12 @@ static inline int __kvm_pgtable_visit(struct kvm_pgtable_walk_data *data,
 }
 
 static int __kvm_pgtable_walk(struct kvm_pgtable_walk_data *data,
-			      struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, u32 level)
+			      struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, s8 level)
 {
 	u32 idx;
 	int ret = 0;
 
-	if (WARN_ON_ONCE(level >= KVM_PGTABLE_MAX_LEVELS))
+	if (WARN_ON_ONCE(level > KVM_PGTABLE_LAST_LEVEL))
 		return -EINVAL;
 
 	for (idx = kvm_pgtable_idx(data, level); idx < PTRS_PER_PTE; ++idx) {
@@ -314,7 +314,7 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 size,
 
 struct leaf_walk_data {
 	kvm_pte_t	pte;
-	u32		level;
+	s8		level;
 };
 
 static int leaf_walker(const struct kvm_pgtable_visit_ctx *ctx,
@@ -329,7 +329,7 @@ static int leaf_walker(const struct kvm_pgtable_visit_ctx *ctx,
 }
 
 int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr,
-			 kvm_pte_t *ptep, u32 *level)
+			 kvm_pte_t *ptep, s8 *level)
 {
 	struct leaf_walk_data data;
 	struct kvm_pgtable_walker walker = {
@@ -440,7 +440,7 @@ static int hyp_map_walker(const struct kvm_pgtable_visit_ctx *ctx,
 	if (hyp_map_walker_try_leaf(ctx, data))
 		return 0;
 
-	if (WARN_ON(ctx->level == KVM_PGTABLE_MAX_LEVELS - 1))
+	if (WARN_ON(ctx->level == KVM_PGTABLE_LAST_LEVEL))
 		return -EINVAL;
 
 	childp = (kvm_pte_t *)mm_ops->zalloc_page(NULL);
@@ -536,14 +536,18 @@ u64 kvm_pgtable_hyp_unmap(struct kvm_pgtable *pgt, u64 addr, u64 size)
 int kvm_pgtable_hyp_init(struct kvm_pgtable *pgt, u32 va_bits,
 			 struct kvm_pgtable_mm_ops *mm_ops)
 {
-	u64 levels = ARM64_HW_PGTABLE_LEVELS(va_bits);
+	s8 start_level = KVM_PGTABLE_LAST_LEVEL + 1 -
+			 ARM64_HW_PGTABLE_LEVELS(va_bits);
+	if (start_level < KVM_PGTABLE_FIRST_LEVEL ||
+	    start_level > KVM_PGTABLE_LAST_LEVEL)
+		return -EINVAL;
 
 	pgt->pgd = (kvm_pteref_t)mm_ops->zalloc_page(NULL);
 	if (!pgt->pgd)
 		return -ENOMEM;
 
 	pgt->ia_bits		= va_bits;
-	pgt->start_level	= KVM_PGTABLE_MAX_LEVELS - levels;
+	pgt->start_level	= start_level;
 	pgt->mm_ops		= mm_ops;
 	pgt->mmu		= NULL;
 	pgt->force_pte_cb	= NULL;
@@ -597,7 +601,7 @@ struct stage2_map_data {
 u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
 {
 	u64 vtcr = VTCR_EL2_FLAGS;
-	u8 lvls;
+	s8 lvls;
 
 	vtcr |= kvm_get_parange(mmfr0) << VTCR_EL2_PS_SHIFT;
 	vtcr |= VTCR_EL2_T0SZ(phys_shift);
@@ -806,7 +810,7 @@ static bool stage2_pte_executable(kvm_pte_t pte)
 static bool stage2_leaf_mapping_allowed(const struct kvm_pgtable_visit_ctx *ctx,
 					struct stage2_map_data *data)
 {
-	if (data->force_pte && (ctx->level < (KVM_PGTABLE_MAX_LEVELS - 1)))
+	if (data->force_pte && ctx->level < KVM_PGTABLE_LAST_LEVEL)
 		return false;
 
 	return kvm_block_mapping_supported(ctx, data->phys);
@@ -884,7 +888,7 @@ static int stage2_map_walk_leaf(const struct kvm_pgtable_visit_ctx *ctx,
 	if (ret != -E2BIG)
 		return ret;
 
-	if (WARN_ON(ctx->level == KVM_PGTABLE_MAX_LEVELS - 1))
+	if (WARN_ON(ctx->level == KVM_PGTABLE_LAST_LEVEL))
 		return -EINVAL;
 
 	if (!data->memcache)
@@ -1048,7 +1052,7 @@ struct stage2_attr_data {
 	kvm_pte_t			attr_set;
 	kvm_pte_t			attr_clr;
 	kvm_pte_t			pte;
-	u32				level;
+	s8				level;
 };
 
 static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx,
@@ -1091,7 +1095,7 @@ static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx,
 static int stage2_update_leaf_attrs(struct kvm_pgtable *pgt, u64 addr,
 				    u64 size, kvm_pte_t attr_set,
 				    kvm_pte_t attr_clr, kvm_pte_t *orig_pte,
-				    u32 *level, enum kvm_pgtable_walk_flags flags)
+				    s8 *level, enum kvm_pgtable_walk_flags flags)
 {
 	int ret;
 	kvm_pte_t attr_mask = KVM_PTE_LEAF_ATTR_LO | KVM_PTE_LEAF_ATTR_HI;
@@ -1164,7 +1168,7 @@ int kvm_pgtable_stage2_relax_perms(struct kvm_pgtable *pgt, u64 addr,
 				   enum kvm_pgtable_prot prot)
 {
 	int ret;
-	u32 level;
+	s8 level;
 	kvm_pte_t set = 0, clr = 0;
 
 	if (prot & KVM_PTE_LEAF_ATTR_HI_SW)
@@ -1226,7 +1230,7 @@ int __kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2_mmu *mmu,
 	u64 vtcr = mmu->arch->vtcr;
 	u32 ia_bits = VTCR_EL2_IPA(vtcr);
 	u32 sl0 = FIELD_GET(VTCR_EL2_SL0_MASK, vtcr);
-	u32 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
+	s8 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
 
 	pgd_sz = kvm_pgd_pages(ia_bits, start_level) * PAGE_SIZE;
 	pgt->pgd = (kvm_pteref_t)mm_ops->zalloc_pages_exact(pgd_sz);
@@ -1249,7 +1253,7 @@ size_t kvm_pgtable_stage2_pgd_size(u64 vtcr)
 {
 	u32 ia_bits = VTCR_EL2_IPA(vtcr);
 	u32 sl0 = FIELD_GET(VTCR_EL2_SL0_MASK, vtcr);
-	u32 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
+	s8 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
 
 	return kvm_pgd_pages(ia_bits, start_level) * PAGE_SIZE;
 }
@@ -1285,7 +1289,7 @@ void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt)
 	pgt->pgd = NULL;
 }
 
-void kvm_pgtable_stage2_free_removed(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, u32 level)
+void kvm_pgtable_stage2_free_removed(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, s8 level)
 {
 	kvm_pteref_t ptep = (kvm_pteref_t)pgtable;
 	struct kvm_pgtable_walker walker = {
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 7113587222ff..783347b19c39 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -135,12 +135,12 @@ static void stage2_free_removed_table_rcu_cb(struct rcu_head *head)
 {
 	struct page *page = container_of(head, struct page, rcu_head);
 	void *pgtable = page_to_virt(page);
-	u32 level = page_private(page);
+	s8 level = page_private(page);
 
 	kvm_pgtable_stage2_free_removed(&kvm_s2_mm_ops, pgtable, level);
 }
 
-static void stage2_free_removed_table(void *addr, u32 level)
+static void stage2_free_removed_table(void *addr, s8 level)
 {
 	struct page *page = virt_to_page(addr);
 
@@ -662,17 +662,18 @@ static int get_user_mapping_size(struct kvm *kvm, u64 addr)
 	struct kvm_pgtable pgt = {
 		.pgd		= (kvm_pteref_t)kvm->mm->pgd,
 		.ia_bits	= vabits_actual,
-		.start_level	= (KVM_PGTABLE_MAX_LEVELS -
-				   CONFIG_PGTABLE_LEVELS),
+		.start_level	= (KVM_PGTABLE_LAST_LEVEL -
+				   CONFIG_PGTABLE_LEVELS + 1),
 		.mm_ops		= &kvm_user_mm_ops,
 	};
 	kvm_pte_t pte = 0;	/* Keep GCC quiet... */
-	u32 level = ~0;
+	s8 level = ~0;
 	int ret;
 
 	ret = kvm_pgtable_get_leaf(&pgt, addr, &pte, &level);
 	VM_BUG_ON(ret);
-	VM_BUG_ON(level >= KVM_PGTABLE_MAX_LEVELS);
+	VM_BUG_ON(level > KVM_PGTABLE_LAST_LEVEL);
+	VM_BUG_ON(level < KVM_PGTABLE_FIRST_LEVEL);
 	VM_BUG_ON(!(pte & PTE_VALID));
 
 	return BIT(ARM64_HW_PGTABLE_LEVEL_SHIFT(level));
@@ -1202,7 +1203,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	gfn_t gfn;
 	kvm_pfn_t pfn;
 	bool logging_active = memslot_is_logging(memslot);
-	unsigned long fault_level = kvm_vcpu_trap_get_fault_level(vcpu);
+	s8 fault_level = kvm_vcpu_trap_get_fault_level(vcpu);
 	unsigned long vma_pagesize, fault_granule;
 	enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R;
 	struct kvm_pgtable *pgt;
-- 
2.25.1


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

* [PATCH v2 09/12] KVM: arm64: Support up to 5 levels of translation in kvm_pgtable
  2023-03-06 19:54 [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
                   ` (7 preceding siblings ...)
  2023-03-06 19:54 ` [PATCH v2 08/12] KVM: arm64: Convert translation level parameter to s8 Ryan Roberts
@ 2023-03-06 19:54 ` Ryan Roberts
  2023-03-06 20:02   ` Ryan Roberts
  2023-03-06 19:54 ` [PATCH v2 10/12] KVM: arm64: Allow guests with >48-bit IPA size on FEAT_LPA2 systems Ryan Roberts
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Ryan Roberts @ 2023-03-06 19:54 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: Ryan Roberts, linux-arm-kernel, kvmarm

FEAT_LPA2 increases the maximum levels of translation from 4 to 5 for
the 4KB page case, when IA is >48 bits. While we can still use 4 levels
for stage2 translation in this case (due to stage2 allowing concatenated
page tables for first level lookup), the same kvm_pgtable library is
used for the hyp stage1 page tables and stage1 does not support
concatenation.

Therefore, modify the library to support up to 5 levels. Previous
patches already laid the groundwork for this by refactoring code to work
in terms of KVM_PGTABLE_FIRST_LEVEL and KVM_PGTABLE_LAST_LEVEL. So we
just need to change these macros.

The hardware sometimes encodes the new level differently from the
others: One such place is when reading the level from the FSC field in
the ESR_EL2 register. We never expect to see the lowest level (-1) here
since the stage 2 page tables always use concatenated tables for first
level lookup and therefore only use 4 levels of lookup. So we get away
with just adding a comment to explain why we are not being careful about
decoding level -1.

For stage2 VTCR_EL2.SL2 is introduced to encode the new start level.
However, since we always use concatenated page tables for first level
look up at stage2 (and therefore we will never need the new extra level)
we never touch this new field.

Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
 arch/arm64/include/asm/kvm_emulate.h | 10 ++++++++++
 arch/arm64/include/asm/kvm_pgtable.h |  2 +-
 arch/arm64/kvm/hyp/pgtable.c         | 10 ++++++++++
 3 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 26666a623fa8..542575aad159 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -405,6 +405,16 @@ static __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vc
 
 static __always_inline s8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu)
 {
+	/*
+	 * Note: With the introduction of FEAT_LPA2 an extra level of
+	 * translation (level -1) is added. This level (obviously) doesn't
+	 * follow the previous convention of encoding the 4 levels in the 2 LSBs
+	 * of the FSC so this function breaks if the fault is for level -1.
+	 *
+	 * However, stage2 tables always use concatenated tables for first level
+	 * lookup and therefore it is guaranteed that the level will be between
+	 * 0 and 3, and this function continues to work.
+	 */
 	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_LEVEL;
 }
 
diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
index 8c7e65147777..a5d96592c658 100644
--- a/arch/arm64/include/asm/kvm_pgtable.h
+++ b/arch/arm64/include/asm/kvm_pgtable.h
@@ -11,7 +11,7 @@
 #include <linux/kvm_host.h>
 #include <linux/types.h>
 
-#define KVM_PGTABLE_FIRST_LEVEL		0
+#define KVM_PGTABLE_FIRST_LEVEL		-1
 #define KVM_PGTABLE_LAST_LEVEL		3
 
 /*
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index 939eab245205..a09c17242da7 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -612,6 +612,15 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
 	lvls = stage2_pgtable_levels(phys_shift);
 	if (lvls < 2)
 		lvls = 2;
+
+	/*
+	 * When LPA2 is enabled, the HW supports an extra level of translation
+	 * (for 5 in total) when using 4K pages. It also introduces VTCR_EL2.SL2
+	 * to as an addition to SL0 to enable encoding this extra start level.
+	 * However, since we always use concatenated pages for the first level
+	 * lookup, we will never need this extra level and therefore do not need
+	 * to touch SL2.
+	 */
 	vtcr |= VTCR_EL2_LVLS_TO_SL0(lvls);
 
 #ifdef CONFIG_ARM64_HW_AFDBM
@@ -1053,6 +1062,7 @@ struct stage2_attr_data {
 	kvm_pte_t			attr_clr;
 	kvm_pte_t			pte;
 	s8				level;
+	struct kvm_pgtable_mm_ops	*mm_ops;
 };
 
 static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx,
-- 
2.25.1


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

* [PATCH v2 10/12] KVM: arm64: Allow guests with >48-bit IPA size on FEAT_LPA2 systems
  2023-03-06 19:54 [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
                   ` (8 preceding siblings ...)
  2023-03-06 19:54 ` [PATCH v2 09/12] KVM: arm64: Support up to 5 levels of translation in kvm_pgtable Ryan Roberts
@ 2023-03-06 19:54 ` Ryan Roberts
  2023-03-06 19:54 ` [PATCH v2 11/12] KVM: selftests: arm64: Determine max ipa size per-page size Ryan Roberts
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Ryan Roberts @ 2023-03-06 19:54 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: Ryan Roberts, linux-arm-kernel, kvmarm

With all the page-table infrastructure in place, we can finally increase
the maximum permisable IPA size to 52-bits on 4KB and 16KB page systems
that have FEAT_LPA2.

Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
 arch/arm64/kvm/reset.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 49a3257dec46..92906f483942 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -378,12 +378,11 @@ int __init kvm_set_ipa_limit(void)
 	parange = cpuid_feature_extract_unsigned_field(mmfr0,
 				ID_AA64MMFR0_EL1_PARANGE_SHIFT);
 	/*
-	 * IPA size beyond 48 bits could not be supported
-	 * on either 4K or 16K page size. Hence let's cap
-	 * it to 48 bits, in case it's reported as larger
-	 * on the system.
+	 * IPA size beyond 48 bits for 4K and 16K page size is only supported
+	 * when LPA2 is available. So if we have LPA2, enable it, else cap to 48
+	 * bits, in case it's reported as larger on the system.
 	 */
-	if (PAGE_SIZE != SZ_64K)
+	if (!system_supports_lpa2() && PAGE_SIZE != SZ_64K)
 		parange = min(parange, (unsigned int)ID_AA64MMFR0_EL1_PARANGE_48);
 
 	/*
-- 
2.25.1


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

* [PATCH v2 11/12] KVM: selftests: arm64: Determine max ipa size per-page size
  2023-03-06 19:54 [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
                   ` (9 preceding siblings ...)
  2023-03-06 19:54 ` [PATCH v2 10/12] KVM: arm64: Allow guests with >48-bit IPA size on FEAT_LPA2 systems Ryan Roberts
@ 2023-03-06 19:54 ` Ryan Roberts
  2023-03-06 19:54 ` [PATCH v2 12/12] KVM: selftests: arm64: Support P52V48 4K and 16K guest_modes Ryan Roberts
  2023-04-17 10:43 ` [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
  12 siblings, 0 replies; 24+ messages in thread
From: Ryan Roberts @ 2023-03-06 19:54 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: Ryan Roberts, linux-arm-kernel, kvmarm

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.

Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
 .../selftests/kvm/include/aarch64/processor.h |  4 +-
 .../selftests/kvm/lib/aarch64/processor.c     | 27 ++++++++++---
 tools/testing/selftests/kvm/lib/guest_modes.c | 40 ++++++++-----------
 3 files changed, 41 insertions(+), 30 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h
index 5f977528e09c..f6e3bb6e257b 100644
--- a/tools/testing/selftests/kvm/include/aarch64/processor.h
+++ b/tools/testing/selftests/kvm/include/aarch64/processor.h
@@ -118,8 +118,8 @@ enum {
 /* Access flag update enable/disable */
 #define TCR_EL1_HA		(1ULL << 39)
 
-void aarch64_get_supported_page_sizes(uint32_t ipa,
-				      bool *ps4k, bool *ps16k, bool *ps64k);
+void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k,
+					uint32_t *ipa16k, uint32_t *ipa64k);
 
 void vm_init_descriptor_tables(struct kvm_vm *vm);
 void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu);
diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c
index 3947f3ccee7e..b2d80396b8f8 100644
--- a/tools/testing/selftests/kvm/lib/aarch64/processor.c
+++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c
@@ -492,12 +492,24 @@ uint32_t guest_get_vcpuid(void)
 	return read_sysreg(tpidr_el1);
 }
 
-void aarch64_get_supported_page_sizes(uint32_t ipa,
-				      bool *ps4k, bool *ps16k, bool *ps64k)
+static uint32_t max_ipa_for_page_size(uint32_t vm_ipa, uint32_t gran,
+				uint32_t not_sup_val, uint32_t ipa52_min_val)
+{
+	if (gran == not_sup_val)
+		return 0;
+	else if (gran >= ipa52_min_val && vm_ipa >= 52)
+		return 52;
+	else
+		return min(vm_ipa, 48U);
+}
+
+void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k,
+					uint32_t *ipa16k, uint32_t *ipa64k)
 {
 	struct kvm_vcpu_init preferred_init;
 	int kvm_fd, vm_fd, vcpu_fd, err;
 	uint64_t val;
+	uint32_t gran;
 	struct kvm_one_reg reg = {
 		.id	= KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR0_EL1),
 		.addr	= (uint64_t)&val,
@@ -518,9 +530,14 @@ void aarch64_get_supported_page_sizes(uint32_t ipa,
 	err = ioctl(vcpu_fd, KVM_GET_ONE_REG, &reg);
 	TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_GET_ONE_REG, vcpu_fd));
 
-	*ps4k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_TGRAN4), val) != 0xf;
-	*ps64k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_TGRAN64), val) == 0;
-	*ps16k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_TGRAN16), val) != 0;
+	gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_TGRAN4), val);
+	*ipa4k = max_ipa_for_page_size(ipa, gran, 0xf, 1);
+
+	gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_TGRAN64), val);
+	*ipa64k = max_ipa_for_page_size(ipa, gran, 0xf, 0);
+
+	gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_TGRAN16), val);
+	*ipa16k = max_ipa_for_page_size(ipa, gran, 0, 2);
 
 	close(vcpu_fd);
 	close(vm_fd);
diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c
index 1df3ce4b16fd..c64c5cf49942 100644
--- a/tools/testing/selftests/kvm/lib/guest_modes.c
+++ b/tools/testing/selftests/kvm/lib/guest_modes.c
@@ -18,33 +18,27 @@ void guest_modes_append_default(void)
 #else
 	{
 		unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE);
-		bool ps4k, ps16k, ps64k;
+		uint32_t ipa4k, ipa16k, ipa64k;
 		int i;
 
-		aarch64_get_supported_page_sizes(limit, &ps4k, &ps16k, &ps64k);
+		aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k);
 
-		vm_mode_default = NUM_VM_MODES;
+		guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52, ipa64k >= 52);
 
-		if (limit >= 52)
-			guest_mode_append(VM_MODE_P52V48_64K, ps64k, ps64k);
-		if (limit >= 48) {
-			guest_mode_append(VM_MODE_P48V48_4K, ps4k, ps4k);
-			guest_mode_append(VM_MODE_P48V48_16K, ps16k, ps16k);
-			guest_mode_append(VM_MODE_P48V48_64K, ps64k, ps64k);
-		}
-		if (limit >= 40) {
-			guest_mode_append(VM_MODE_P40V48_4K, ps4k, ps4k);
-			guest_mode_append(VM_MODE_P40V48_16K, ps16k, ps16k);
-			guest_mode_append(VM_MODE_P40V48_64K, ps64k, ps64k);
-			if (ps4k)
-				vm_mode_default = VM_MODE_P40V48_4K;
-		}
-		if (limit >= 36) {
-			guest_mode_append(VM_MODE_P36V48_4K, ps4k, ps4k);
-			guest_mode_append(VM_MODE_P36V48_16K, ps16k, ps16k);
-			guest_mode_append(VM_MODE_P36V48_64K, ps64k, ps64k);
-			guest_mode_append(VM_MODE_P36V47_16K, ps16k, ps16k);
-		}
+		guest_mode_append(VM_MODE_P48V48_4K, ipa4k >= 48, ipa4k >= 48);
+		guest_mode_append(VM_MODE_P48V48_16K, ipa16k >= 48, ipa16k >= 48);
+		guest_mode_append(VM_MODE_P48V48_64K, ipa64k >= 48, ipa16k >= 48);
+
+		guest_mode_append(VM_MODE_P40V48_4K, ipa4k >= 40, ipa4k >= 40);
+		guest_mode_append(VM_MODE_P40V48_16K, ipa16k >= 40, ipa16k >= 40);
+		guest_mode_append(VM_MODE_P40V48_64K, ipa64k >= 40, ipa64k >= 40);
+
+		guest_mode_append(VM_MODE_P36V48_4K, ipa4k >= 36, ipa4k >= 36);
+		guest_mode_append(VM_MODE_P36V48_16K, ipa16k >= 36, ipa16k >= 36);
+		guest_mode_append(VM_MODE_P36V48_64K, ipa64k >= 36, ipa64k >= 36);
+		guest_mode_append(VM_MODE_P36V47_16K, ipa16k >= 36, ipa16k >= 36);
+
+		vm_mode_default = ipa4k >= 40 ? VM_MODE_P40V48_4K : NUM_VM_MODES;
 
 		/*
 		 * Pick the first supported IPA size if the default
-- 
2.25.1


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

* [PATCH v2 12/12] KVM: selftests: arm64: Support P52V48 4K and 16K guest_modes
  2023-03-06 19:54 [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
                   ` (10 preceding siblings ...)
  2023-03-06 19:54 ` [PATCH v2 11/12] KVM: selftests: arm64: Determine max ipa size per-page size Ryan Roberts
@ 2023-03-06 19:54 ` Ryan Roberts
  2023-03-06 20:04   ` Ryan Roberts
  2023-04-17 10:43 ` [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
  12 siblings, 1 reply; 24+ messages in thread
From: Ryan Roberts @ 2023-03-06 19:54 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: Ryan Roberts, linux-arm-kernel, kvmarm

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.

Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
 .../selftests/kvm/include/kvm_util_base.h     |  1 +
 .../selftests/kvm/lib/aarch64/processor.c     | 39 ++++++++++++++-----
 tools/testing/selftests/kvm/lib/guest_modes.c |  2 +
 tools/testing/selftests/kvm/lib/kvm_util.c    |  3 ++
 4 files changed, 36 insertions(+), 9 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h
index fbc2a79369b8..b8678bf4a980 100644
--- a/tools/testing/selftests/kvm/include/kvm_util_base.h
+++ b/tools/testing/selftests/kvm/include/kvm_util_base.h
@@ -150,6 +150,7 @@ static inline struct userspace_mem_region *vm_get_mem_region(struct kvm_vm *vm,
 
 enum vm_guest_mode {
 	VM_MODE_P52V48_4K,
+	VM_MODE_P52V48_16K,
 	VM_MODE_P52V48_64K,
 	VM_MODE_P48V48_4K,
 	VM_MODE_P48V48_16K,
diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c
index b2d80396b8f8..934f8baa7d0e 100644
--- a/tools/testing/selftests/kvm/lib/aarch64/processor.c
+++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c
@@ -12,6 +12,7 @@
 #include "kvm_util.h"
 #include "processor.h"
 #include <linux/bitfield.h>
+#include <linux/sizes.h>
 
 #define DEFAULT_ARM64_GUEST_STACK_VADDR_MIN	0xac0000
 
@@ -58,13 +59,25 @@ static uint64_t pte_index(struct kvm_vm *vm, vm_vaddr_t gva)
 	return (gva >> vm->page_shift) & mask;
 }
 
+static inline bool use_lpa2_pte_format(struct kvm_vm *vm)
+{
+	return (vm->page_size == SZ_4K || vm->page_size == SZ_16K) &&
+	    (vm->pa_bits > 48 || vm->va_bits > 48);
+}
+
 static uint64_t addr_pte(struct kvm_vm *vm, uint64_t pa, uint64_t attrs)
 {
 	uint64_t pte;
 
-	pte = pa & GENMASK(47, vm->page_shift);
-	if (vm->page_shift == 16)
-		pte |= (pa & GENMASK(51, 48)) >> (48 - 12);
+	if (use_lpa2_pte_format(vm)) {
+		pte = pa & GENMASK(49, vm->page_shift);
+		pte |= (pa & GENMASK(51, 50)) >> (50 - 8);
+		attrs &= ~GENMASK(9, 8);
+	} else {
+		pte = pa & GENMASK(47, vm->page_shift);
+		if (vm->page_shift == 16)
+			pte |= (pa & GENMASK(51, 48)) >> (48 - 12);
+	}
 	pte |= attrs;
 
 	return pte;
@@ -74,9 +87,14 @@ static uint64_t pte_addr(struct kvm_vm *vm, uint64_t pte)
 {
 	uint64_t pa;
 
-	pa = pte & GENMASK(47, vm->page_shift);
-	if (vm->page_shift == 16)
-		pa |= (pte & GENMASK(15, 12)) << (48 - 12);
+	if (use_lpa2_pte_format(vm)) {
+		pa = pte & GENMASK(49, vm->page_shift);
+		pa |= (pte & GENMASK(9, 8)) << (50 - 8);
+	} else {
+		pa = pte & GENMASK(47, vm->page_shift);
+		if (vm->page_shift == 16)
+			pa |= (pte & GENMASK(15, 12)) << (48 - 12);
+	}
 
 	return pa;
 }
@@ -266,9 +284,6 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
 
 	/* Configure base granule size */
 	switch (vm->mode) {
-	case VM_MODE_P52V48_4K:
-		TEST_FAIL("AArch64 does not support 4K sized pages "
-			  "with 52-bit physical address ranges");
 	case VM_MODE_PXXV48_4K:
 		TEST_FAIL("AArch64 does not support 4K sized pages "
 			  "with ANY-bit physical address ranges");
@@ -278,12 +293,14 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
 	case VM_MODE_P36V48_64K:
 		tcr_el1 |= 1ul << 14; /* TG0 = 64KB */
 		break;
+	case VM_MODE_P52V48_16K:
 	case VM_MODE_P48V48_16K:
 	case VM_MODE_P40V48_16K:
 	case VM_MODE_P36V48_16K:
 	case VM_MODE_P36V47_16K:
 		tcr_el1 |= 2ul << 14; /* TG0 = 16KB */
 		break;
+	case VM_MODE_P52V48_4K:
 	case VM_MODE_P48V48_4K:
 	case VM_MODE_P40V48_4K:
 	case VM_MODE_P36V48_4K:
@@ -297,6 +314,8 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
 
 	/* Configure output size */
 	switch (vm->mode) {
+	case VM_MODE_P52V48_4K:
+	case VM_MODE_P52V48_16K:
 	case VM_MODE_P52V48_64K:
 		tcr_el1 |= 6ul << 32; /* IPS = 52 bits */
 		ttbr0_el1 |= (vm->pgd & GENMASK(51, 48)) >> (48 - 2);
@@ -325,6 +344,8 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
 	/* TCR_EL1 |= IRGN0:WBWA | ORGN0:WBWA | SH0:Inner-Shareable */;
 	tcr_el1 |= (1 << 8) | (1 << 10) | (3 << 12);
 	tcr_el1 |= (64 - vm->va_bits) /* T0SZ */;
+	if (use_lpa2_pte_format(vm))
+		tcr_el1 |= (1ul << 59) /* DS */;
 
 	vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), sctlr_el1);
 	vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TCR_EL1), tcr_el1);
diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c
index c64c5cf49942..6634afc22137 100644
--- a/tools/testing/selftests/kvm/lib/guest_modes.c
+++ b/tools/testing/selftests/kvm/lib/guest_modes.c
@@ -23,6 +23,8 @@ void guest_modes_append_default(void)
 
 		aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k);
 
+		guest_mode_append(VM_MODE_P52V48_4K, ipa4k >= 52, ipa4k >= 52);
+		guest_mode_append(VM_MODE_P52V48_16K, ipa16k >= 52, ipa16k >= 52);
 		guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52, ipa64k >= 52);
 
 		guest_mode_append(VM_MODE_P48V48_4K, ipa4k >= 48, ipa4k >= 48);
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 3ea24a5f4c43..0e4905b75825 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -143,6 +143,7 @@ const char *vm_guest_mode_string(uint32_t i)
 {
 	static const char * const strings[] = {
 		[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_P48V48_4K]	= "PA-bits:48,  VA-bits:48,  4K pages",
 		[VM_MODE_P48V48_16K]	= "PA-bits:48,  VA-bits:48, 16K pages",
@@ -168,6 +169,7 @@ const char *vm_guest_mode_string(uint32_t i)
 
 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_P48V48_4K]	= { 48, 48,  0x1000, 12 },
 	[VM_MODE_P48V48_16K]	= { 48, 48,  0x4000, 14 },
@@ -246,6 +248,7 @@ struct kvm_vm *____vm_create(enum vm_guest_mode mode)
 	case VM_MODE_P36V48_64K:
 		vm->pgtable_levels = 3;
 		break;
+	case VM_MODE_P52V48_16K:
 	case VM_MODE_P48V48_16K:
 	case VM_MODE_P40V48_16K:
 	case VM_MODE_P36V48_16K:
-- 
2.25.1


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

* Re: [PATCH v2 09/12] KVM: arm64: Support up to 5 levels of translation in kvm_pgtable
  2023-03-06 19:54 ` [PATCH v2 09/12] KVM: arm64: Support up to 5 levels of translation in kvm_pgtable Ryan Roberts
@ 2023-03-06 20:02   ` Ryan Roberts
  0 siblings, 0 replies; 24+ messages in thread
From: Ryan Roberts @ 2023-03-06 20:02 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: linux-arm-kernel, kvmarm

On 06/03/2023 19:54, Ryan Roberts wrote:
> FEAT_LPA2 increases the maximum levels of translation from 4 to 5 for
> the 4KB page case, when IA is >48 bits. While we can still use 4 levels
> for stage2 translation in this case (due to stage2 allowing concatenated
> page tables for first level lookup), the same kvm_pgtable library is
> used for the hyp stage1 page tables and stage1 does not support
> concatenation.
> 
> Therefore, modify the library to support up to 5 levels. Previous
> patches already laid the groundwork for this by refactoring code to work
> in terms of KVM_PGTABLE_FIRST_LEVEL and KVM_PGTABLE_LAST_LEVEL. So we
> just need to change these macros.
> 
> The hardware sometimes encodes the new level differently from the
> others: One such place is when reading the level from the FSC field in
> the ESR_EL2 register. We never expect to see the lowest level (-1) here
> since the stage 2 page tables always use concatenated tables for first
> level lookup and therefore only use 4 levels of lookup. So we get away
> with just adding a comment to explain why we are not being careful about
> decoding level -1.
> 
> For stage2 VTCR_EL2.SL2 is introduced to encode the new start level.
> However, since we always use concatenated page tables for first level
> look up at stage2 (and therefore we will never need the new extra level)
> we never touch this new field.
> 
> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
> ---
>  arch/arm64/include/asm/kvm_emulate.h | 10 ++++++++++
>  arch/arm64/include/asm/kvm_pgtable.h |  2 +-
>  arch/arm64/kvm/hyp/pgtable.c         | 10 ++++++++++
>  3 files changed, 21 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 26666a623fa8..542575aad159 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -405,6 +405,16 @@ static __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vc
>  
>  static __always_inline s8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu)
>  {
> +	/*
> +	 * Note: With the introduction of FEAT_LPA2 an extra level of
> +	 * translation (level -1) is added. This level (obviously) doesn't
> +	 * follow the previous convention of encoding the 4 levels in the 2 LSBs
> +	 * of the FSC so this function breaks if the fault is for level -1.
> +	 *
> +	 * However, stage2 tables always use concatenated tables for first level
> +	 * lookup and therefore it is guaranteed that the level will be between
> +	 * 0 and 3, and this function continues to work.
> +	 */
>  	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_LEVEL;
>  }
>  
> diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
> index 8c7e65147777..a5d96592c658 100644
> --- a/arch/arm64/include/asm/kvm_pgtable.h
> +++ b/arch/arm64/include/asm/kvm_pgtable.h
> @@ -11,7 +11,7 @@
>  #include <linux/kvm_host.h>
>  #include <linux/types.h>
>  
> -#define KVM_PGTABLE_FIRST_LEVEL		0
> +#define KVM_PGTABLE_FIRST_LEVEL		-1
>  #define KVM_PGTABLE_LAST_LEVEL		3
>  
>  /*
> diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
> index 939eab245205..a09c17242da7 100644
> --- a/arch/arm64/kvm/hyp/pgtable.c
> +++ b/arch/arm64/kvm/hyp/pgtable.c
> @@ -612,6 +612,15 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
>  	lvls = stage2_pgtable_levels(phys_shift);
>  	if (lvls < 2)
>  		lvls = 2;
> +
> +	/*
> +	 * When LPA2 is enabled, the HW supports an extra level of translation
> +	 * (for 5 in total) when using 4K pages. It also introduces VTCR_EL2.SL2
> +	 * to as an addition to SL0 to enable encoding this extra start level.
> +	 * However, since we always use concatenated pages for the first level
> +	 * lookup, we will never need this extra level and therefore do not need
> +	 * to touch SL2.
> +	 */
>  	vtcr |= VTCR_EL2_LVLS_TO_SL0(lvls);
>  
>  #ifdef CONFIG_ARM64_HW_AFDBM
> @@ -1053,6 +1062,7 @@ struct stage2_attr_data {
>  	kvm_pte_t			attr_clr;
>  	kvm_pte_t			pte;
>  	s8				level;
> +	struct kvm_pgtable_mm_ops	*mm_ops;

Naturally, as soon as I sent this out, I noticed this, which clearly should not
be here. I suspect it's an artifact from rebasing. Sorry about that, please
ignore and I'll fix it in the next version.


>  };
>  
>  static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx,


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

* Re: [PATCH v2 12/12] KVM: selftests: arm64: Support P52V48 4K and 16K guest_modes
  2023-03-06 19:54 ` [PATCH v2 12/12] KVM: selftests: arm64: Support P52V48 4K and 16K guest_modes Ryan Roberts
@ 2023-03-06 20:04   ` Ryan Roberts
  0 siblings, 0 replies; 24+ messages in thread
From: Ryan Roberts @ 2023-03-06 20:04 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: linux-arm-kernel, kvmarm

On 06/03/2023 19:54, Ryan Roberts wrote:
> 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.
> 
> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
> ---
>  .../selftests/kvm/include/kvm_util_base.h     |  1 +
>  .../selftests/kvm/lib/aarch64/processor.c     | 39 ++++++++++++++-----
>  tools/testing/selftests/kvm/lib/guest_modes.c |  2 +
>  tools/testing/selftests/kvm/lib/kvm_util.c    |  3 ++
>  4 files changed, 36 insertions(+), 9 deletions(-)
> 
> diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h
> index fbc2a79369b8..b8678bf4a980 100644
> --- a/tools/testing/selftests/kvm/include/kvm_util_base.h
> +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h
> @@ -150,6 +150,7 @@ static inline struct userspace_mem_region *vm_get_mem_region(struct kvm_vm *vm,
>  
>  enum vm_guest_mode {
>  	VM_MODE_P52V48_4K,
> +	VM_MODE_P52V48_16K,

I wasn't sure whether it was best to add this here in its "natural" position, or
at the end. These enum values are exposed through the command line interface, so
by putting it here, perhaps I could break people's scripts because everything
below gets renumbered. Happy to move we care about compat for these tests.

>  	VM_MODE_P52V48_64K,
>  	VM_MODE_P48V48_4K,
>  	VM_MODE_P48V48_16K,
> diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c
> index b2d80396b8f8..934f8baa7d0e 100644
> --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c
> +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c
> @@ -12,6 +12,7 @@
>  #include "kvm_util.h"
>  #include "processor.h"
>  #include <linux/bitfield.h>
> +#include <linux/sizes.h>
>  
>  #define DEFAULT_ARM64_GUEST_STACK_VADDR_MIN	0xac0000
>  
> @@ -58,13 +59,25 @@ static uint64_t pte_index(struct kvm_vm *vm, vm_vaddr_t gva)
>  	return (gva >> vm->page_shift) & mask;
>  }
>  
> +static inline bool use_lpa2_pte_format(struct kvm_vm *vm)
> +{
> +	return (vm->page_size == SZ_4K || vm->page_size == SZ_16K) &&
> +	    (vm->pa_bits > 48 || vm->va_bits > 48);
> +}
> +
>  static uint64_t addr_pte(struct kvm_vm *vm, uint64_t pa, uint64_t attrs)
>  {
>  	uint64_t pte;
>  
> -	pte = pa & GENMASK(47, vm->page_shift);
> -	if (vm->page_shift == 16)
> -		pte |= (pa & GENMASK(51, 48)) >> (48 - 12);
> +	if (use_lpa2_pte_format(vm)) {
> +		pte = pa & GENMASK(49, vm->page_shift);
> +		pte |= (pa & GENMASK(51, 50)) >> (50 - 8);
> +		attrs &= ~GENMASK(9, 8);
> +	} else {
> +		pte = pa & GENMASK(47, vm->page_shift);
> +		if (vm->page_shift == 16)
> +			pte |= (pa & GENMASK(51, 48)) >> (48 - 12);
> +	}
>  	pte |= attrs;
>  
>  	return pte;
> @@ -74,9 +87,14 @@ static uint64_t pte_addr(struct kvm_vm *vm, uint64_t pte)
>  {
>  	uint64_t pa;
>  
> -	pa = pte & GENMASK(47, vm->page_shift);
> -	if (vm->page_shift == 16)
> -		pa |= (pte & GENMASK(15, 12)) << (48 - 12);
> +	if (use_lpa2_pte_format(vm)) {
> +		pa = pte & GENMASK(49, vm->page_shift);
> +		pa |= (pte & GENMASK(9, 8)) << (50 - 8);
> +	} else {
> +		pa = pte & GENMASK(47, vm->page_shift);
> +		if (vm->page_shift == 16)
> +			pa |= (pte & GENMASK(15, 12)) << (48 - 12);
> +	}
>  
>  	return pa;
>  }
> @@ -266,9 +284,6 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
>  
>  	/* Configure base granule size */
>  	switch (vm->mode) {
> -	case VM_MODE_P52V48_4K:
> -		TEST_FAIL("AArch64 does not support 4K sized pages "
> -			  "with 52-bit physical address ranges");
>  	case VM_MODE_PXXV48_4K:
>  		TEST_FAIL("AArch64 does not support 4K sized pages "
>  			  "with ANY-bit physical address ranges");
> @@ -278,12 +293,14 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
>  	case VM_MODE_P36V48_64K:
>  		tcr_el1 |= 1ul << 14; /* TG0 = 64KB */
>  		break;
> +	case VM_MODE_P52V48_16K:
>  	case VM_MODE_P48V48_16K:
>  	case VM_MODE_P40V48_16K:
>  	case VM_MODE_P36V48_16K:
>  	case VM_MODE_P36V47_16K:
>  		tcr_el1 |= 2ul << 14; /* TG0 = 16KB */
>  		break;
> +	case VM_MODE_P52V48_4K:
>  	case VM_MODE_P48V48_4K:
>  	case VM_MODE_P40V48_4K:
>  	case VM_MODE_P36V48_4K:
> @@ -297,6 +314,8 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
>  
>  	/* Configure output size */
>  	switch (vm->mode) {
> +	case VM_MODE_P52V48_4K:
> +	case VM_MODE_P52V48_16K:
>  	case VM_MODE_P52V48_64K:
>  		tcr_el1 |= 6ul << 32; /* IPS = 52 bits */
>  		ttbr0_el1 |= (vm->pgd & GENMASK(51, 48)) >> (48 - 2);
> @@ -325,6 +344,8 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
>  	/* TCR_EL1 |= IRGN0:WBWA | ORGN0:WBWA | SH0:Inner-Shareable */;
>  	tcr_el1 |= (1 << 8) | (1 << 10) | (3 << 12);
>  	tcr_el1 |= (64 - vm->va_bits) /* T0SZ */;
> +	if (use_lpa2_pte_format(vm))
> +		tcr_el1 |= (1ul << 59) /* DS */;
>  
>  	vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), sctlr_el1);
>  	vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TCR_EL1), tcr_el1);
> diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c
> index c64c5cf49942..6634afc22137 100644
> --- a/tools/testing/selftests/kvm/lib/guest_modes.c
> +++ b/tools/testing/selftests/kvm/lib/guest_modes.c
> @@ -23,6 +23,8 @@ void guest_modes_append_default(void)
>  
>  		aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k);
>  
> +		guest_mode_append(VM_MODE_P52V48_4K, ipa4k >= 52, ipa4k >= 52);
> +		guest_mode_append(VM_MODE_P52V48_16K, ipa16k >= 52, ipa16k >= 52);
>  		guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52, ipa64k >= 52);
>  
>  		guest_mode_append(VM_MODE_P48V48_4K, ipa4k >= 48, ipa4k >= 48);
> diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
> index 3ea24a5f4c43..0e4905b75825 100644
> --- a/tools/testing/selftests/kvm/lib/kvm_util.c
> +++ b/tools/testing/selftests/kvm/lib/kvm_util.c
> @@ -143,6 +143,7 @@ const char *vm_guest_mode_string(uint32_t i)
>  {
>  	static const char * const strings[] = {
>  		[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_P48V48_4K]	= "PA-bits:48,  VA-bits:48,  4K pages",
>  		[VM_MODE_P48V48_16K]	= "PA-bits:48,  VA-bits:48, 16K pages",
> @@ -168,6 +169,7 @@ const char *vm_guest_mode_string(uint32_t i)
>  
>  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_P48V48_4K]	= { 48, 48,  0x1000, 12 },
>  	[VM_MODE_P48V48_16K]	= { 48, 48,  0x4000, 14 },
> @@ -246,6 +248,7 @@ struct kvm_vm *____vm_create(enum vm_guest_mode mode)
>  	case VM_MODE_P36V48_64K:
>  		vm->pgtable_levels = 3;
>  		break;
> +	case VM_MODE_P52V48_16K:
>  	case VM_MODE_P48V48_16K:
>  	case VM_MODE_P40V48_16K:
>  	case VM_MODE_P36V48_16K:


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

* Re: [PATCH v2 01/12] arm64/mm: Update non-range tlb invalidation routines for FEAT_LPA2
  2023-03-06 19:54 ` [PATCH v2 01/12] arm64/mm: Update non-range tlb invalidation routines for FEAT_LPA2 Ryan Roberts
@ 2023-04-12 15:47   ` Catalin Marinas
  2023-04-13  8:04     ` Ryan Roberts
  0 siblings, 1 reply; 24+ messages in thread
From: Catalin Marinas @ 2023-04-12 15:47 UTC (permalink / raw)
  To: Ryan Roberts
  Cc: Will Deacon, Marc Zyngier, Oliver Upton, Suzuki K Poulose,
	Ard Biesheuvel, Anshuman Khandual, linux-arm-kernel, kvmarm

On Mon, Mar 06, 2023 at 07:54:27PM +0000, Ryan Roberts wrote:
> FEAT_LPA2 impacts tlb invalidation in 2 ways; Firstly, the TTL field in
> the non-range tlbi instructions can now validly take a 0 value for the
> 4KB granule (this is due to the extra level of translation). Secondly,
> the BADDR field in the range tlbi instructions must be aligned to 64KB
> when LPA2 is in use (TCR.DS=1). Changes are required for tlbi to
> continue to operate correctly when LPA2 is in use.
> 
> KVM only uses the non-range (__tlbi_level()) routines. Therefore we only
> solve the first problem with this patch.

There are some patches on the list to add support for range invalidation
in KVM:

https://lore.kernel.org/r/20230206172340.2639971-1-rananta@google.com

> diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
> index 412a3b9a3c25..67dd47df42d5 100644
> --- a/arch/arm64/include/asm/tlbflush.h
> +++ b/arch/arm64/include/asm/tlbflush.h
> @@ -93,19 +93,22 @@ static inline unsigned long get_trans_granule(void)
>   * When ARMv8.4-TTL exists, TLBI operations take an additional hint for
>   * the level at which the invalidation must take place. If the level is
>   * wrong, no invalidation may take place. In the case where the level
> - * cannot be easily determined, a 0 value for the level parameter will
> - * perform a non-hinted invalidation.
> + * cannot be easily determined, the value TLBI_TTL_UNKNOWN will perform
> + * a non-hinted invalidation. Any provided level outside the hint range
> + * will also cause fall-back to non-hinted invalidation.
>   *
>   * For Stage-2 invalidation, use the level values provided to that effect
>   * in asm/stage2_pgtable.h.
>   */
>  #define TLBI_TTL_MASK		GENMASK_ULL(47, 44)
>  
> +#define TLBI_TTL_UNKNOWN	(-1)
> +
>  #define __tlbi_level(op, addr, level) do {				\
>  	u64 arg = addr;							\
>  									\
>  	if (cpus_have_const_cap(ARM64_HAS_ARMv8_4_TTL) &&		\
> -	    level) {							\
> +	    level >= 0 && level <= 3) {					\

I'd just use level != TLBI_TTL_UNKNOWN here.

>  		u64 ttl = level & 3;					\
>  		ttl |= get_trans_granule() << 2;			\
>  		arg &= ~TLBI_TTL_MASK;					\
> @@ -133,16 +136,17 @@ static inline unsigned long get_trans_granule(void)
>   * [BADDR, BADDR + (NUM + 1) * 2^(5*SCALE + 1) * PAGESIZE)
>   *
>   */
> -#define __TLBI_VADDR_RANGE(addr, asid, scale, num, ttl)		\
> -	({							\
> -		unsigned long __ta = (addr) >> PAGE_SHIFT;	\
> -		__ta &= GENMASK_ULL(36, 0);			\
> -		__ta |= (unsigned long)(ttl) << 37;		\
> -		__ta |= (unsigned long)(num) << 39;		\
> -		__ta |= (unsigned long)(scale) << 44;		\
> -		__ta |= get_trans_granule() << 46;		\
> -		__ta |= (unsigned long)(asid) << 48;		\
> -		__ta;						\
> +#define __TLBI_VADDR_RANGE(addr, asid, scale, num, ttl)				\
> +	({									\
> +		unsigned long __ta = (addr) >> PAGE_SHIFT;			\
> +		unsigned long __ttl = (ttl >= 1 && ttl <= 3) ? ttl : 0;		\

And here, set __ttl to 0 if TLBI_TTL_UNKNOWN.

Otherwise it looks fine:

Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>

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

* Re: [PATCH v2 02/12] arm64/mm: Add FEAT_LPA2 specific ID_AA64MMFR0.TGRAN[2]
  2023-03-06 19:54 ` [PATCH v2 02/12] arm64/mm: Add FEAT_LPA2 specific ID_AA64MMFR0.TGRAN[2] Ryan Roberts
@ 2023-04-12 16:27   ` Catalin Marinas
  2023-04-13  8:16     ` Ryan Roberts
  0 siblings, 1 reply; 24+ messages in thread
From: Catalin Marinas @ 2023-04-12 16:27 UTC (permalink / raw)
  To: Ryan Roberts
  Cc: Will Deacon, Marc Zyngier, Oliver Upton, Suzuki K Poulose,
	Ard Biesheuvel, Anshuman Khandual, linux-arm-kernel, kvmarm

On Mon, Mar 06, 2023 at 07:54:28PM +0000, Ryan Roberts wrote:
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 9e3ecba3c4e6..7f708eecc3ad 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -609,10 +609,12 @@
>  
>  /* id_aa64mmfr0 */
>  #define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN	0x0
> +#define ID_AA64MMFR0_EL1_TGRAN4_LPA2		ID_AA64MMFR0_EL1_TGRAN4_52_BIT
>  #define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MAX	0x7
>  #define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MIN	0x0
>  #define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MAX	0x7
>  #define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MIN	0x1
> +#define ID_AA64MMFR0_EL1_TGRAN16_LPA2		ID_AA64MMFR0_EL1_TGRAN16_52_BIT
>  #define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MAX	0xf

This patch evolved a bit since I first acked it in Anshuman's series. I
can't find any trace of ID_AA64MMFR0_EL1_TGRAN4_52_BIT in the kernel. Is
it introduced in a later patch?

-- 
Catalin

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

* Re: [PATCH v2 04/12] KVM: arm64: Add new (V)TCR_EL2 field definitions for FEAT_LPA2
  2023-03-06 19:54 ` [PATCH v2 04/12] KVM: arm64: Add new (V)TCR_EL2 field definitions for FEAT_LPA2 Ryan Roberts
@ 2023-04-12 16:36   ` Catalin Marinas
  0 siblings, 0 replies; 24+ messages in thread
From: Catalin Marinas @ 2023-04-12 16:36 UTC (permalink / raw)
  To: Ryan Roberts
  Cc: Will Deacon, Marc Zyngier, Oliver Upton, Suzuki K Poulose,
	Ard Biesheuvel, Anshuman Khandual, linux-arm-kernel, kvmarm

On Mon, Mar 06, 2023 at 07:54:30PM +0000, Ryan Roberts wrote:
> As per Arm ARM (0487I.a), (V)TCR_EL2.DS fields control whether 52 bit
> input and output addresses are supported on 4K and 16K page size
> configurations when FEAT_LPA2 is known to have been implemented.
> 
> This adds these field definitions which will be used by KVM when
> FEAT_LPA2 is enabled.
> 
> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>

Acked-by: Catalin Marinas <catalin.marinas@arm.com>

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

* Re: [PATCH v2 06/12] KVM: arm64: Use LPA2 page-tables for hyp stage1 if HW supports it
  2023-03-06 19:54 ` [PATCH v2 06/12] KVM: arm64: Use LPA2 page-tables for hyp stage1 " Ryan Roberts
@ 2023-04-12 17:06   ` Catalin Marinas
  2023-04-13  8:27     ` Ryan Roberts
  0 siblings, 1 reply; 24+ messages in thread
From: Catalin Marinas @ 2023-04-12 17:06 UTC (permalink / raw)
  To: Ryan Roberts
  Cc: Will Deacon, Marc Zyngier, Oliver Upton, Suzuki K Poulose,
	Ard Biesheuvel, Anshuman Khandual, linux-arm-kernel, kvmarm

On Mon, Mar 06, 2023 at 07:54:32PM +0000, Ryan Roberts wrote:
> Implement a simple policy whereby if the HW supports FEAT_LPA2 for the
> page size we are using, always use LPA2-style page-tables for hyp stage
> 1, regardless of the IPA or PA size requirements. When in use we can now
> support up to 52-bit IPA and PA sizes.
> 
> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
> ---
>  arch/arm64/kvm/arm.c         | 2 ++
>  arch/arm64/kvm/hyp/pgtable.c | 3 ++-
>  2 files changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index 3bd732eaf087..bef73c484162 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -1548,6 +1548,8 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
>  	tcr = (read_sysreg(tcr_el1) & TCR_EL2_MASK) | TCR_EL2_RES1;
>  	tcr &= ~TCR_T0SZ_MASK;
>  	tcr |= TCR_T0SZ(hyp_va_bits);
> +	if (system_supports_lpa2())
> +		tcr |= TCR_EL2_DS;
>  	params->tcr_el2 = tcr;
>  
>  	params->pgd_pa = kvm_mmu_get_httbr();
> diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
> index 414a5dbf233d..bb481d6c7f2d 100644
> --- a/arch/arm64/kvm/hyp/pgtable.c
> +++ b/arch/arm64/kvm/hyp/pgtable.c
> @@ -379,7 +379,8 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
>  	}
>  
>  	attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_AP, ap);
> -	attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_SH, sh);
> +	if (!system_supports_lpa2())
> +		attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_SH, sh);
>  	attr |= KVM_PTE_LEAF_ATTR_LO_S1_AF;
>  	attr |= prot & KVM_PTE_LEAF_ATTR_HI_SW;
>  	*ptep = attr;

Isn't LPA2 at stage 1 more involved than just not setting the SH field?
Does kvm_phys_to_pte() need changing as well?

If that's not strictly needed for stage 2, I'd rather keep the two
stages separate and add the stage 1 hyp together with Ard's series for
LPA2 at stage 1.

-- 
Catalin

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

* Re: [PATCH v2 01/12] arm64/mm: Update non-range tlb invalidation routines for FEAT_LPA2
  2023-04-12 15:47   ` Catalin Marinas
@ 2023-04-13  8:04     ` Ryan Roberts
  0 siblings, 0 replies; 24+ messages in thread
From: Ryan Roberts @ 2023-04-13  8:04 UTC (permalink / raw)
  To: Catalin Marinas
  Cc: Will Deacon, Marc Zyngier, Oliver Upton, Suzuki K Poulose,
	Ard Biesheuvel, Anshuman Khandual, linux-arm-kernel, kvmarm

Thanks for the review!


On 12/04/2023 16:47, Catalin Marinas wrote:
> On Mon, Mar 06, 2023 at 07:54:27PM +0000, Ryan Roberts wrote:
>> FEAT_LPA2 impacts tlb invalidation in 2 ways; Firstly, the TTL field in
>> the non-range tlbi instructions can now validly take a 0 value for the
>> 4KB granule (this is due to the extra level of translation). Secondly,
>> the BADDR field in the range tlbi instructions must be aligned to 64KB
>> when LPA2 is in use (TCR.DS=1). Changes are required for tlbi to
>> continue to operate correctly when LPA2 is in use.
>>
>> KVM only uses the non-range (__tlbi_level()) routines. Therefore we only
>> solve the first problem with this patch.
> 
> There are some patches on the list to add support for range invalidation
> in KVM:
> 
> https://lore.kernel.org/r/20230206172340.2639971-1-rananta@google.com

I have the required change for range invalidation at:
https://gitlab.arm.com/linux-arm/linux-rr/-/commit/38628decb785aea42a349a857b9f8a65a19e9c2b.
But I didn't include it in this submission because it would be dead code until
either the patches you point out land, or Ard's patches land. Also, the
implementation I did uses the CPU feature to determine which variant to apply,
and since the kernel is not using LPA2 yet, it would give the wrong answer for
the case where LPA2 is supported by the system.

I think this patch (or similar) should be included with Ard's changes. What's
your view?


> 
>> diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
>> index 412a3b9a3c25..67dd47df42d5 100644
>> --- a/arch/arm64/include/asm/tlbflush.h
>> +++ b/arch/arm64/include/asm/tlbflush.h
>> @@ -93,19 +93,22 @@ static inline unsigned long get_trans_granule(void)
>>   * When ARMv8.4-TTL exists, TLBI operations take an additional hint for
>>   * the level at which the invalidation must take place. If the level is
>>   * wrong, no invalidation may take place. In the case where the level
>> - * cannot be easily determined, a 0 value for the level parameter will
>> - * perform a non-hinted invalidation.
>> + * cannot be easily determined, the value TLBI_TTL_UNKNOWN will perform
>> + * a non-hinted invalidation. Any provided level outside the hint range
>> + * will also cause fall-back to non-hinted invalidation.
>>   *
>>   * For Stage-2 invalidation, use the level values provided to that effect
>>   * in asm/stage2_pgtable.h.
>>   */
>>  #define TLBI_TTL_MASK		GENMASK_ULL(47, 44)
>>  
>> +#define TLBI_TTL_UNKNOWN	(-1)
>> +
>>  #define __tlbi_level(op, addr, level) do {				\
>>  	u64 arg = addr;							\
>>  									\
>>  	if (cpus_have_const_cap(ARM64_HAS_ARMv8_4_TTL) &&		\
>> -	    level) {							\
>> +	    level >= 0 && level <= 3) {					\
> 
> I'd just use level != TLBI_TTL_UNKNOWN here.

I don't think that is correct, since if/when level -2 gets added,
TLBI_TTL_UNKNOWN would likely be changed to -2, and with your logic, you would
allow level=-1 through and ttl = -1 & 3 = 3. Callers will call this with the
actual level [-1, 3] and the intent here is to use a hint where the instruction
supports it [0, 3]. If you're concerned about the 2 comparisons, how about
leaving "level >= 0" and removing "level <= 3"?

> 
>>  		u64 ttl = level & 3;					\
>>  		ttl |= get_trans_granule() << 2;			\
>>  		arg &= ~TLBI_TTL_MASK;					\
>> @@ -133,16 +136,17 @@ static inline unsigned long get_trans_granule(void)
>>   * [BADDR, BADDR + (NUM + 1) * 2^(5*SCALE + 1) * PAGESIZE)
>>   *
>>   */
>> -#define __TLBI_VADDR_RANGE(addr, asid, scale, num, ttl)		\
>> -	({							\
>> -		unsigned long __ta = (addr) >> PAGE_SHIFT;	\
>> -		__ta &= GENMASK_ULL(36, 0);			\
>> -		__ta |= (unsigned long)(ttl) << 37;		\
>> -		__ta |= (unsigned long)(num) << 39;		\
>> -		__ta |= (unsigned long)(scale) << 44;		\
>> -		__ta |= get_trans_granule() << 46;		\
>> -		__ta |= (unsigned long)(asid) << 48;		\
>> -		__ta;						\
>> +#define __TLBI_VADDR_RANGE(addr, asid, scale, num, ttl)				\
>> +	({									\
>> +		unsigned long __ta = (addr) >> PAGE_SHIFT;			\
>> +		unsigned long __ttl = (ttl >= 1 && ttl <= 3) ? ttl : 0;		\
> 
> And here, set __ttl to 0 if TLBI_TTL_UNKNOWN.

Same argument as above.

> 
> Otherwise it looks fine:
> 
> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>


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

* Re: [PATCH v2 02/12] arm64/mm: Add FEAT_LPA2 specific ID_AA64MMFR0.TGRAN[2]
  2023-04-12 16:27   ` Catalin Marinas
@ 2023-04-13  8:16     ` Ryan Roberts
  2023-04-13 16:54       ` Catalin Marinas
  0 siblings, 1 reply; 24+ messages in thread
From: Ryan Roberts @ 2023-04-13  8:16 UTC (permalink / raw)
  To: Catalin Marinas
  Cc: Will Deacon, Marc Zyngier, Oliver Upton, Suzuki K Poulose,
	Ard Biesheuvel, Anshuman Khandual, linux-arm-kernel, kvmarm

On 12/04/2023 17:27, Catalin Marinas wrote:
> On Mon, Mar 06, 2023 at 07:54:28PM +0000, Ryan Roberts wrote:
>> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
>> index 9e3ecba3c4e6..7f708eecc3ad 100644
>> --- a/arch/arm64/include/asm/sysreg.h
>> +++ b/arch/arm64/include/asm/sysreg.h
>> @@ -609,10 +609,12 @@
>>  
>>  /* id_aa64mmfr0 */
>>  #define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN	0x0
>> +#define ID_AA64MMFR0_EL1_TGRAN4_LPA2		ID_AA64MMFR0_EL1_TGRAN4_52_BIT
>>  #define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MAX	0x7
>>  #define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MIN	0x0
>>  #define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MAX	0x7
>>  #define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MIN	0x1
>> +#define ID_AA64MMFR0_EL1_TGRAN16_LPA2		ID_AA64MMFR0_EL1_TGRAN16_52_BIT
>>  #define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MAX	0xf
> 
> This patch evolved a bit since I first acked it in Anshuman's series. I
> can't find any trace of ID_AA64MMFR0_EL1_TGRAN4_52_BIT in the kernel. Is
> it introduced in a later patch?
> 

It's autogenerated as part of the sysreg magic. Ends up in
arch/arm64/include/generated/asm/sysreg-defs.h.

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

* Re: [PATCH v2 06/12] KVM: arm64: Use LPA2 page-tables for hyp stage1 if HW supports it
  2023-04-12 17:06   ` Catalin Marinas
@ 2023-04-13  8:27     ` Ryan Roberts
  0 siblings, 0 replies; 24+ messages in thread
From: Ryan Roberts @ 2023-04-13  8:27 UTC (permalink / raw)
  To: Catalin Marinas
  Cc: Will Deacon, Marc Zyngier, Oliver Upton, Suzuki K Poulose,
	Ard Biesheuvel, Anshuman Khandual, linux-arm-kernel, kvmarm

On 12/04/2023 18:06, Catalin Marinas wrote:
> On Mon, Mar 06, 2023 at 07:54:32PM +0000, Ryan Roberts wrote:
>> Implement a simple policy whereby if the HW supports FEAT_LPA2 for the
>> page size we are using, always use LPA2-style page-tables for hyp stage
>> 1, regardless of the IPA or PA size requirements. When in use we can now
>> support up to 52-bit IPA and PA sizes.
>>
>> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
>> ---
>>  arch/arm64/kvm/arm.c         | 2 ++
>>  arch/arm64/kvm/hyp/pgtable.c | 3 ++-
>>  2 files changed, 4 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
>> index 3bd732eaf087..bef73c484162 100644
>> --- a/arch/arm64/kvm/arm.c
>> +++ b/arch/arm64/kvm/arm.c
>> @@ -1548,6 +1548,8 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
>>  	tcr = (read_sysreg(tcr_el1) & TCR_EL2_MASK) | TCR_EL2_RES1;
>>  	tcr &= ~TCR_T0SZ_MASK;
>>  	tcr |= TCR_T0SZ(hyp_va_bits);
>> +	if (system_supports_lpa2())
>> +		tcr |= TCR_EL2_DS;
>>  	params->tcr_el2 = tcr;
>>  
>>  	params->pgd_pa = kvm_mmu_get_httbr();
>> diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
>> index 414a5dbf233d..bb481d6c7f2d 100644
>> --- a/arch/arm64/kvm/hyp/pgtable.c
>> +++ b/arch/arm64/kvm/hyp/pgtable.c
>> @@ -379,7 +379,8 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
>>  	}
>>  
>>  	attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_AP, ap);
>> -	attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_SH, sh);
>> +	if (!system_supports_lpa2())
>> +		attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_SH, sh);
>>  	attr |= KVM_PTE_LEAF_ATTR_LO_S1_AF;
>>  	attr |= prot & KVM_PTE_LEAF_ATTR_HI_SW;
>>  	*ptep = attr;
> 
> Isn't LPA2 at stage 1 more involved than just not setting the SH field?
> Does kvm_phys_to_pte() need changing as well?

Yes, the kvm_pgtable library was changed in the previous commit to handle LPA2
correctly. kvm_phys_to_pte() is one such modification.

> 
> If that's not strictly needed for stage 2, I'd rather keep the two
> stages separate and add the stage 1 hyp together with Ard's series for
> LPA2 at stage 1.
> 
The problem is that KVM uses the same kvm_pgtable library to manage the hyp
stage1 and guest stage2 page tables. My original approach was to pass around a
per-pgtable flag that indicated the pgtable format and the library would do the
right thing based on that flag. But the preference at round 1 was to do away
with that and use a static key to simplify and speed things up. The consequence
is that all users of the library must use the same format, so that ties hyp s1
and guest s2 changes together.


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

* Re: [PATCH v2 02/12] arm64/mm: Add FEAT_LPA2 specific ID_AA64MMFR0.TGRAN[2]
  2023-04-13  8:16     ` Ryan Roberts
@ 2023-04-13 16:54       ` Catalin Marinas
  0 siblings, 0 replies; 24+ messages in thread
From: Catalin Marinas @ 2023-04-13 16:54 UTC (permalink / raw)
  To: Ryan Roberts
  Cc: Will Deacon, Marc Zyngier, Oliver Upton, Suzuki K Poulose,
	Ard Biesheuvel, Anshuman Khandual, linux-arm-kernel, kvmarm

On Thu, Apr 13, 2023 at 09:16:03AM +0100, Ryan Roberts wrote:
> On 12/04/2023 17:27, Catalin Marinas wrote:
> > On Mon, Mar 06, 2023 at 07:54:28PM +0000, Ryan Roberts wrote:
> >> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> >> index 9e3ecba3c4e6..7f708eecc3ad 100644
> >> --- a/arch/arm64/include/asm/sysreg.h
> >> +++ b/arch/arm64/include/asm/sysreg.h
> >> @@ -609,10 +609,12 @@
> >>  
> >>  /* id_aa64mmfr0 */
> >>  #define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN	0x0
> >> +#define ID_AA64MMFR0_EL1_TGRAN4_LPA2		ID_AA64MMFR0_EL1_TGRAN4_52_BIT
> >>  #define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MAX	0x7
> >>  #define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MIN	0x0
> >>  #define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MAX	0x7
> >>  #define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MIN	0x1
> >> +#define ID_AA64MMFR0_EL1_TGRAN16_LPA2		ID_AA64MMFR0_EL1_TGRAN16_52_BIT
> >>  #define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MAX	0xf
> > 
> > This patch evolved a bit since I first acked it in Anshuman's series. I
> > can't find any trace of ID_AA64MMFR0_EL1_TGRAN4_52_BIT in the kernel. Is
> > it introduced in a later patch?
> 
> It's autogenerated as part of the sysreg magic. Ends up in
> arch/arm64/include/generated/asm/sysreg-defs.h.

Ah, I keep forgetting this (I usually build the kernel in a different
directory, so grep doesn't encounter it).

-- 
Catalin

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

* Re: [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2
  2023-03-06 19:54 [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
                   ` (11 preceding siblings ...)
  2023-03-06 19:54 ` [PATCH v2 12/12] KVM: selftests: arm64: Support P52V48 4K and 16K guest_modes Ryan Roberts
@ 2023-04-17 10:43 ` Ryan Roberts
  12 siblings, 0 replies; 24+ messages in thread
From: Ryan Roberts @ 2023-04-17 10:43 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
	Suzuki K Poulose, Ard Biesheuvel, Anshuman Khandual
  Cc: linux-arm-kernel, kvmarm

Just a polite nudge: If anyone has any feedback on this series, it would be
great to hear it!

On 06/03/2023 19:54, Ryan Roberts wrote:
> Add support for FEAT_LPA2 to KVM for both hypervisor stage 1 (for the
> nvhe/protected modes) and the vm stage 2 translation tables (for all modes).
> FEAT_LPA2 enables 52 bit PAs and VAs for 4KB and 16KB granules (note this is
> already supported for 64KB granules via the FEAT_LPA and FEAT_LVA extensions).
> The series does not include support for FEAT_LPA2 in the kernel stage 1. This
> support is provided separately by Ard Biesheuvel's series at [1]. The two series
> are independent.
> 
> These patches are based on top of v6.3-rc1, plus 3 kvm selftests bug-fix
> patches, which I have posted separately at [2] and [3]. You can find a tree at
> [4]. Those bug-fix patches relate to incorrect test code for 52-bit PA (64K)
> guests, and are needed in order to test the new 52-bit 4K and 16K guest modes
> that this series enables.
> 
> 
> Testing:
> Testing has been done exclusively on the FVP and covers the boot matrix tests
> and kvm selftests.
> 
> The host/guest config boot matrix gives the same (expected) results as
> for the v1 submission; of 180 conifgs, 12 fail, and these are all due to
> attempting to load the host kernel into high memory which isn't expected to work
> until the kernel has FEAT_LPA2 support for its stage 1. (refer to v1 posting for
> details on the exact configs).
> 
> KVM selftests have been enhanced to support P52V48 4K and 16K guest modes, and
> all tests have been run against a P48V48_4K host and a P52V52_4K host (a run
> takes about 10 hours on FVP, sigh, but I can test a few more host configs if
> useful). All tests pass except "memslot_perf_test", which fails due to a timeout
> while syncing. This test fails in the same way for plain v6.3-rc1, so I'm
> confident this is not a regression caused by this series. (the issue is that
> alarm(2) is issued and the signal is received before alarm(0) is issued. I
> expect this is an FVP-time related problem, although I'm not sure how to fix
> robustly for the FVP without potentially hanging real systems for long periods
> of time).
> 
> 
> Changes since v1:
> https://lore.kernel.org/kvmarm/20221206135930.3277585-1-ryan.roberts@arm.com/
>  - Create CPU feature for LPA2 (enabled if both S1 and S2 report LPA2 support).
>  - Use the CPU feature (and therefore code patching) to globally decide whether
>    or not to use LPA2 PTE format; no more per-pgtable flag to pass around.
>  - Removed the range-based TLBI changes, which are not required by KVM; leaves
>    only minor changes to the non-range-based invalidation code.
>  - Removed patch to encode/decode VTCR_EL2.SL2, and replaced with a comment
>    describing why we never need to touch SL2 (stage 2 always uses concatenated
>    first level lookup).
>  - Added support for LPA2 guests in KVM selftests (VM_MODE_P52V48_4K enabled and
>    new VM_MODE_P52V48_16K added).
>  - Rebased onto 6.3-rc1.
> 
> 
> [1] https://lore.kernel.org/linux-arm-kernel/20221124123932.2648991-1-ardb@kernel.org
> [2] https://lore.kernel.org/kvmarm/20230228170756.769461-1-ryan.roberts@arm.com/
> [3] https://lore.kernel.org/kvmarm/20230302152033.242073-1-ryan.roberts@arm.com/
> [4] https://gitlab.arm.com/linux-arm/linux-rr/-/tree/features/lpa2/kvm_lkml-v2
> 
> 
> Anshuman Khandual (1):
>   arm64/mm: Add FEAT_LPA2 specific ID_AA64MMFR0.TGRAN[2]
> 
> Ryan Roberts (11):
>   arm64/mm: Update non-range tlb invalidation routines for FEAT_LPA2
>   KVM: arm64: Add ARM64_HAS_LPA2 CPU capability
>   KVM: arm64: Add new (V)TCR_EL2 field definitions for FEAT_LPA2
>   KVM: arm64: Use LPA2 page-tables for stage2 if HW supports it
>   KVM: arm64: Use LPA2 page-tables for hyp stage1 if HW supports it
>   KVM: arm64: Insert PS field at TCR_EL2 assembly time
>   KVM: arm64: Convert translation level parameter to s8
>   KVM: arm64: Support up to 5 levels of translation in kvm_pgtable
>   KVM: arm64: Allow guests with >48-bit IPA size on FEAT_LPA2 systems
>   KVM: selftests: arm64: Determine max ipa size per-page size
>   KVM: selftests: arm64: Support P52V48 4K and 16K guest_modes
> 
>  arch/arm64/include/asm/cpufeature.h           |  5 ++
>  arch/arm64/include/asm/kvm_arm.h              |  2 +
>  arch/arm64/include/asm/kvm_emulate.h          | 12 ++-
>  arch/arm64/include/asm/kvm_pgtable.h          | 72 +++++++++++------
>  arch/arm64/include/asm/kvm_pkvm.h             |  5 +-
>  arch/arm64/include/asm/sysreg.h               |  5 ++
>  arch/arm64/include/asm/tlb.h                  |  9 ++-
>  arch/arm64/include/asm/tlbflush.h             | 43 ++++++----
>  arch/arm64/kernel/cpufeature.c                | 40 ++++++++++
>  arch/arm64/kvm/arm.c                          |  4 +
>  arch/arm64/kvm/hyp/nvhe/hyp-init.S            |  4 -
>  arch/arm64/kvm/hyp/nvhe/mem_protect.c         |  6 +-
>  arch/arm64/kvm/hyp/nvhe/mm.c                  |  4 +-
>  arch/arm64/kvm/hyp/nvhe/setup.c               |  2 +-
>  arch/arm64/kvm/hyp/pgtable.c                  | 79 ++++++++++++-------
>  arch/arm64/kvm/mmu.c                          | 15 ++--
>  arch/arm64/kvm/reset.c                        |  9 +--
>  arch/arm64/tools/cpucaps                      |  1 +
>  .../selftests/kvm/include/aarch64/processor.h |  4 +-
>  .../selftests/kvm/include/kvm_util_base.h     |  1 +
>  .../selftests/kvm/lib/aarch64/processor.c     | 66 ++++++++++++----
>  tools/testing/selftests/kvm/lib/guest_modes.c | 42 +++++-----
>  tools/testing/selftests/kvm/lib/kvm_util.c    |  3 +
>  23 files changed, 297 insertions(+), 136 deletions(-)
> 
> --
> 2.25.1
> 
> 


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

end of thread, other threads:[~2023-04-17 10:43 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-06 19:54 [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts
2023-03-06 19:54 ` [PATCH v2 01/12] arm64/mm: Update non-range tlb invalidation routines for FEAT_LPA2 Ryan Roberts
2023-04-12 15:47   ` Catalin Marinas
2023-04-13  8:04     ` Ryan Roberts
2023-03-06 19:54 ` [PATCH v2 02/12] arm64/mm: Add FEAT_LPA2 specific ID_AA64MMFR0.TGRAN[2] Ryan Roberts
2023-04-12 16:27   ` Catalin Marinas
2023-04-13  8:16     ` Ryan Roberts
2023-04-13 16:54       ` Catalin Marinas
2023-03-06 19:54 ` [PATCH v2 03/12] KVM: arm64: Add ARM64_HAS_LPA2 CPU capability Ryan Roberts
2023-03-06 19:54 ` [PATCH v2 04/12] KVM: arm64: Add new (V)TCR_EL2 field definitions for FEAT_LPA2 Ryan Roberts
2023-04-12 16:36   ` Catalin Marinas
2023-03-06 19:54 ` [PATCH v2 05/12] KVM: arm64: Use LPA2 page-tables for stage2 if HW supports it Ryan Roberts
2023-03-06 19:54 ` [PATCH v2 06/12] KVM: arm64: Use LPA2 page-tables for hyp stage1 " Ryan Roberts
2023-04-12 17:06   ` Catalin Marinas
2023-04-13  8:27     ` Ryan Roberts
2023-03-06 19:54 ` [PATCH v2 07/12] KVM: arm64: Insert PS field at TCR_EL2 assembly time Ryan Roberts
2023-03-06 19:54 ` [PATCH v2 08/12] KVM: arm64: Convert translation level parameter to s8 Ryan Roberts
2023-03-06 19:54 ` [PATCH v2 09/12] KVM: arm64: Support up to 5 levels of translation in kvm_pgtable Ryan Roberts
2023-03-06 20:02   ` Ryan Roberts
2023-03-06 19:54 ` [PATCH v2 10/12] KVM: arm64: Allow guests with >48-bit IPA size on FEAT_LPA2 systems Ryan Roberts
2023-03-06 19:54 ` [PATCH v2 11/12] KVM: selftests: arm64: Determine max ipa size per-page size Ryan Roberts
2023-03-06 19:54 ` [PATCH v2 12/12] KVM: selftests: arm64: Support P52V48 4K and 16K guest_modes Ryan Roberts
2023-03-06 20:04   ` Ryan Roberts
2023-04-17 10:43 ` [PATCH v2 00/12] KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 Ryan Roberts

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).