arm64: Add ARM64_HAS_LPA2 CPU capability
authorRyan Roberts <ryan.roberts@arm.com>
Mon, 27 Nov 2023 11:17:30 +0000 (11:17 +0000)
committerMarc Zyngier <maz@kernel.org>
Mon, 27 Nov 2023 15:03:50 +0000 (15:03 +0000)
Expose FEAT_LPA2 as a capability so that we can take advantage of
alternatives patching in the 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. KVM requires
support in both stages in order to use LPA2 since the same library is
used for hyp stage 1 and guest stage 2 pgtables.

Reviewed-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20231127111737.1897081-6-ryan.roberts@arm.com
arch/arm64/include/asm/cpufeature.h
arch/arm64/kernel/cpufeature.c
arch/arm64/tools/cpucaps

index f6d416f..acf1095 100644 (file)
@@ -819,6 +819,11 @@ static inline bool system_supports_tlb_range(void)
        return alternative_has_cap_unlikely(ARM64_HAS_TLB_RANGE);
 }
 
+static inline bool system_supports_lpa2(void)
+{
+       return cpus_have_final_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);
 
index 646591c..7900ba7 100644 (file)
@@ -1768,6 +1768,39 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
        return !meltdown_safe;
 }
 
+#if defined(ID_AA64MMFR0_EL1_TGRAN_LPA2) && defined(ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_LPA2)
+static bool has_lpa2_at_stage1(u64 mmfr0)
+{
+       unsigned int tgran;
+
+       tgran = cpuid_feature_extract_unsigned_field(mmfr0,
+                                       ID_AA64MMFR0_EL1_TGRAN_SHIFT);
+       return tgran == ID_AA64MMFR0_EL1_TGRAN_LPA2;
+}
+
+static bool has_lpa2_at_stage2(u64 mmfr0)
+{
+       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;
+}
+
+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);
+}
+#else
+static bool has_lpa2(const struct arm64_cpu_capabilities *entry, int scope)
+{
+       return false;
+}
+#endif
+
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
 #define KPTI_NG_TEMP_VA                (-(1UL << PMD_SHIFT))
 
@@ -2731,6 +2764,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .matches = has_cpuid_feature,
                ARM64_CPUID_FIELDS(ID_AA64MMFR2_EL1, EVT, IMP)
        },
+       {
+               .desc = "52-bit Virtual Addressing for KVM (LPA2)",
+               .capability = ARM64_HAS_LPA2,
+               .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+               .matches = has_lpa2,
+       },
        {},
 };
 
index b98c382..919eceb 100644 (file)
@@ -37,6 +37,7 @@ HAS_GIC_PRIO_MASKING
 HAS_GIC_PRIO_RELAXED_SYNC
 HAS_HCX
 HAS_LDAPR
+HAS_LPA2
 HAS_LSE_ATOMICS
 HAS_MOPS
 HAS_NESTED_VIRT