* [PATCH v2 1/6] arm64/mm: Reduce PA space to 48 bits when LPA2 is not enabled
[not found] <20241205150229.3510177-8-ardb+git@google.com>
@ 2024-12-05 15:02 ` Ard Biesheuvel
2024-12-09 13:18 ` Ard Biesheuvel
2024-12-05 15:02 ` [PATCH v2 2/6] arm64/mm: Override PARange for !LPA2 and use it consistently Ard Biesheuvel
2024-12-05 15:02 ` [PATCH v2 3/6] arm64/kvm: Configure HYP TCR.PS/DS based on host stage1 Ard Biesheuvel
2 siblings, 1 reply; 4+ messages in thread
From: Ard Biesheuvel @ 2024-12-05 15:02 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-kernel, Ard Biesheuvel, Catalin Marinas, Will Deacon,
Marc Zyngier, Mark Rutland, Ryan Roberts, Anshuman Khandual,
Kees Cook, Quentin Perret, stable
From: Ard Biesheuvel <ardb@kernel.org>
Currently, LPA2 kernel support implies support for up to 52 bits of
physical addressing, and this is reflected in global definitions such as
PHYS_MASK_SHIFT and MAX_PHYSMEM_BITS.
This is potentially problematic, given that LPA2 hardware support is
modeled as a CPU feature which can be overridden, and with LPA2 hardware
support turned off, attempting to map physical regions with address bits
[51:48] set (which may exist on LPA2 capable systems booting with
arm64.nolva) will result in corrupted mappings with a truncated output
address and bogus shareability attributes.
This means that the accepted physical address range in the mapping
routines should be at most 48 bits wide when LPA2 support is configured
but not enabled at runtime.
Fixes: 352b0395b505 ("arm64: Enable 52-bit virtual addressing for 4k and 16k granule configs")
Cc: <stable@vger.kernel.org>
Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm64/include/asm/pgtable-hwdef.h | 6 ------
arch/arm64/include/asm/pgtable-prot.h | 7 +++++++
arch/arm64/include/asm/sparsemem.h | 4 +++-
3 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index c78a988cca93..a9136cc551cc 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -222,12 +222,6 @@
*/
#define S1_TABLE_AP (_AT(pmdval_t, 3) << 61)
-/*
- * Highest possible physical address supported.
- */
-#define PHYS_MASK_SHIFT (CONFIG_ARM64_PA_BITS)
-#define PHYS_MASK ((UL(1) << PHYS_MASK_SHIFT) - 1)
-
#define TTBR_CNP_BIT (UL(1) << 0)
/*
diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index 9f9cf13bbd95..a95f1f77bb39 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -81,6 +81,7 @@ extern unsigned long prot_ns_shared;
#define lpa2_is_enabled() false
#define PTE_MAYBE_SHARED PTE_SHARED
#define PMD_MAYBE_SHARED PMD_SECT_S
+#define PHYS_MASK_SHIFT (CONFIG_ARM64_PA_BITS)
#else
static inline bool __pure lpa2_is_enabled(void)
{
@@ -89,8 +90,14 @@ static inline bool __pure lpa2_is_enabled(void)
#define PTE_MAYBE_SHARED (lpa2_is_enabled() ? 0 : PTE_SHARED)
#define PMD_MAYBE_SHARED (lpa2_is_enabled() ? 0 : PMD_SECT_S)
+#define PHYS_MASK_SHIFT (lpa2_is_enabled() ? CONFIG_ARM64_PA_BITS : 48)
#endif
+/*
+ * Highest possible physical address supported.
+ */
+#define PHYS_MASK ((UL(1) << PHYS_MASK_SHIFT) - 1)
+
/*
* If we have userspace only BTI we don't want to mark kernel pages
* guarded even if the system does support BTI.
diff --git a/arch/arm64/include/asm/sparsemem.h b/arch/arm64/include/asm/sparsemem.h
index 8a8acc220371..035e0ca74e88 100644
--- a/arch/arm64/include/asm/sparsemem.h
+++ b/arch/arm64/include/asm/sparsemem.h
@@ -5,7 +5,9 @@
#ifndef __ASM_SPARSEMEM_H
#define __ASM_SPARSEMEM_H
-#define MAX_PHYSMEM_BITS CONFIG_ARM64_PA_BITS
+#include <asm/pgtable-prot.h>
+
+#define MAX_PHYSMEM_BITS PHYS_MASK_SHIFT
/*
* Section size must be at least 512MB for 64K base
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/6] arm64/mm: Override PARange for !LPA2 and use it consistently
[not found] <20241205150229.3510177-8-ardb+git@google.com>
2024-12-05 15:02 ` [PATCH v2 1/6] arm64/mm: Reduce PA space to 48 bits when LPA2 is not enabled Ard Biesheuvel
@ 2024-12-05 15:02 ` Ard Biesheuvel
2024-12-05 15:02 ` [PATCH v2 3/6] arm64/kvm: Configure HYP TCR.PS/DS based on host stage1 Ard Biesheuvel
2 siblings, 0 replies; 4+ messages in thread
From: Ard Biesheuvel @ 2024-12-05 15:02 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-kernel, Ard Biesheuvel, Catalin Marinas, Will Deacon,
Marc Zyngier, Mark Rutland, Ryan Roberts, Anshuman Khandual,
Kees Cook, Quentin Perret, stable
From: Ard Biesheuvel <ardb@kernel.org>
When FEAT_LPA{,2} are not implemented, the ID_AA64MMFR0_EL1.PARange and
TCR.IPS values corresponding with 52-bit physical addressing are
reserved.
Setting the TCR.IPS field to 0b110 (52-bit physical addressing) has side
effects, such as how the TTBRn_ELx.BADDR fields are interpreted, and so
it is important that disabling FEAT_LPA2 (by overriding the
ID_AA64MMFR0.TGran fields) also presents a PARange field consistent with
that.
So limit the field to 48 bits unless LPA2 is enabled, and update
existing references to use the override consistently.
Fixes: 352b0395b505 ("arm64: Enable 52-bit virtual addressing for 4k and 16k granule configs")
Cc: <stable@vger.kernel.org>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm64/include/asm/assembler.h | 5 +++++
arch/arm64/kernel/cpufeature.c | 2 +-
arch/arm64/kernel/pi/idreg-override.c | 9 +++++++++
arch/arm64/kernel/pi/map_kernel.c | 6 ++++++
arch/arm64/mm/init.c | 7 ++++++-
5 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 3d8d534a7a77..ad63457a05c5 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -343,6 +343,11 @@ alternative_cb_end
// Narrow PARange to fit the PS field in TCR_ELx
ubfx \tmp0, \tmp0, #ID_AA64MMFR0_EL1_PARANGE_SHIFT, #3
mov \tmp1, #ID_AA64MMFR0_EL1_PARANGE_MAX
+#ifdef CONFIG_ARM64_LPA2
+alternative_if_not ARM64_HAS_VA52
+ mov \tmp1, #ID_AA64MMFR0_EL1_PARANGE_48
+alternative_else_nop_endif
+#endif
cmp \tmp0, \tmp1
csel \tmp0, \tmp1, \tmp0, hi
bfi \tcr, \tmp0, \pos, #3
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 6ce71f444ed8..f8cb8a6ab98a 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -3478,7 +3478,7 @@ static void verify_hyp_capabilities(void)
return;
safe_mmfr1 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
- mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
+ mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
/* Verify VMID bits */
diff --git a/arch/arm64/kernel/pi/idreg-override.c b/arch/arm64/kernel/pi/idreg-override.c
index 22159251eb3a..c6b185b885f7 100644
--- a/arch/arm64/kernel/pi/idreg-override.c
+++ b/arch/arm64/kernel/pi/idreg-override.c
@@ -83,6 +83,15 @@ static bool __init mmfr2_varange_filter(u64 val)
id_aa64mmfr0_override.val |=
(ID_AA64MMFR0_EL1_TGRAN_LPA2 - 1) << ID_AA64MMFR0_EL1_TGRAN_SHIFT;
id_aa64mmfr0_override.mask |= 0xfU << ID_AA64MMFR0_EL1_TGRAN_SHIFT;
+
+ /*
+ * Override PARange to 48 bits - the override will just be
+ * ignored if the actual PARange is smaller, but this is
+ * unlikely to be the case for LPA2 capable silicon.
+ */
+ id_aa64mmfr0_override.val |=
+ ID_AA64MMFR0_EL1_PARANGE_48 << ID_AA64MMFR0_EL1_PARANGE_SHIFT;
+ id_aa64mmfr0_override.mask |= 0xfU << ID_AA64MMFR0_EL1_PARANGE_SHIFT;
}
#endif
return true;
diff --git a/arch/arm64/kernel/pi/map_kernel.c b/arch/arm64/kernel/pi/map_kernel.c
index f374a3e5a5fe..e57b043f324b 100644
--- a/arch/arm64/kernel/pi/map_kernel.c
+++ b/arch/arm64/kernel/pi/map_kernel.c
@@ -136,6 +136,12 @@ static void noinline __section(".idmap.text") set_ttbr0_for_lpa2(u64 ttbr)
{
u64 sctlr = read_sysreg(sctlr_el1);
u64 tcr = read_sysreg(tcr_el1) | TCR_DS;
+ u64 mmfr0 = read_sysreg(id_aa64mmfr0_el1);
+ u64 parange = cpuid_feature_extract_unsigned_field(mmfr0,
+ ID_AA64MMFR0_EL1_PARANGE_SHIFT);
+
+ tcr &= ~TCR_IPS_MASK;
+ tcr |= parange << TCR_IPS_SHIFT;
asm(" msr sctlr_el1, %0 ;"
" isb ;"
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index d21f67d67cf5..2b2289d55eaa 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -280,7 +280,12 @@ void __init arm64_memblock_init(void)
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
extern u16 memstart_offset_seed;
- u64 mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
+
+ /*
+ * Use the sanitised version of id_aa64mmfr0_el1 so that linear
+ * map randomization can be enabled by shrinking the IPA space.
+ */
+ u64 mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
int parange = cpuid_feature_extract_unsigned_field(
mmfr0, ID_AA64MMFR0_EL1_PARANGE_SHIFT);
s64 range = linear_region_size -
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 3/6] arm64/kvm: Configure HYP TCR.PS/DS based on host stage1
[not found] <20241205150229.3510177-8-ardb+git@google.com>
2024-12-05 15:02 ` [PATCH v2 1/6] arm64/mm: Reduce PA space to 48 bits when LPA2 is not enabled Ard Biesheuvel
2024-12-05 15:02 ` [PATCH v2 2/6] arm64/mm: Override PARange for !LPA2 and use it consistently Ard Biesheuvel
@ 2024-12-05 15:02 ` Ard Biesheuvel
2 siblings, 0 replies; 4+ messages in thread
From: Ard Biesheuvel @ 2024-12-05 15:02 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-kernel, Ard Biesheuvel, Catalin Marinas, Will Deacon,
Marc Zyngier, Mark Rutland, Ryan Roberts, Anshuman Khandual,
Kees Cook, Quentin Perret, stable
From: Ard Biesheuvel <ardb@kernel.org>
When the host stage1 is configured for LPA2, the value currently being
programmed into TCR_EL2.T0SZ may be invalid unless LPA2 is configured
at HYP as well. This means kvm_lpa2_is_enabled() is not the right
condition to test when setting TCR_EL2.DS, as it will return false if
LPA2 is only available for stage 1 but not for stage 2.
Similary, programming TCR_EL2.PS based on a limited IPA range due to
lack of stage2 LPA2 support could potentially result in problems.
So use lpa2_is_enabled() instead, and set the PS field according to the
host's IPS, which is capped at 48 bits if LPA2 support is absent or
disabled. Whether or not we can make meaningful use of such a
configuration is a different question.
Cc: <stable@vger.kernel.org>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm64/kvm/arm.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index a102c3aebdbc..7b2735ad32e9 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -1990,8 +1990,7 @@ static int kvm_init_vector_slots(void)
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);
- u64 mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
- unsigned long tcr;
+ unsigned long tcr, ips;
/*
* Calculate the raw per-cpu offset without a translation from the
@@ -2005,6 +2004,7 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
params->mair_el2 = read_sysreg(mair_el1);
tcr = read_sysreg(tcr_el1);
+ ips = FIELD_GET(TCR_IPS_MASK, tcr);
if (cpus_have_final_cap(ARM64_KVM_HVHE)) {
tcr |= TCR_EPD1_MASK;
} else {
@@ -2014,8 +2014,8 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
tcr &= ~TCR_T0SZ_MASK;
tcr |= TCR_T0SZ(hyp_va_bits);
tcr &= ~TCR_EL2_PS_MASK;
- tcr |= FIELD_PREP(TCR_EL2_PS_MASK, kvm_get_parange(mmfr0));
- if (kvm_lpa2_is_enabled())
+ tcr |= FIELD_PREP(TCR_EL2_PS_MASK, ips);
+ if (lpa2_is_enabled())
tcr |= TCR_EL2_DS;
params->tcr_el2 = tcr;
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2 1/6] arm64/mm: Reduce PA space to 48 bits when LPA2 is not enabled
2024-12-05 15:02 ` [PATCH v2 1/6] arm64/mm: Reduce PA space to 48 bits when LPA2 is not enabled Ard Biesheuvel
@ 2024-12-09 13:18 ` Ard Biesheuvel
0 siblings, 0 replies; 4+ messages in thread
From: Ard Biesheuvel @ 2024-12-09 13:18 UTC (permalink / raw)
Cc: linux-arm-kernel, linux-kernel, Catalin Marinas, Will Deacon,
Marc Zyngier, Mark Rutland, Ryan Roberts, Anshuman Khandual,
Kees Cook, Quentin Perret, stable
On Thu, 5 Dec 2024 at 16:03, Ard Biesheuvel <ardb+git@google.com> wrote:
>
> From: Ard Biesheuvel <ardb@kernel.org>
>
> Currently, LPA2 kernel support implies support for up to 52 bits of
> physical addressing, and this is reflected in global definitions such as
> PHYS_MASK_SHIFT and MAX_PHYSMEM_BITS.
>
> This is potentially problematic, given that LPA2 hardware support is
> modeled as a CPU feature which can be overridden, and with LPA2 hardware
> support turned off, attempting to map physical regions with address bits
> [51:48] set (which may exist on LPA2 capable systems booting with
> arm64.nolva) will result in corrupted mappings with a truncated output
> address and bogus shareability attributes.
>
> This means that the accepted physical address range in the mapping
> routines should be at most 48 bits wide when LPA2 support is configured
> but not enabled at runtime.
>
> Fixes: 352b0395b505 ("arm64: Enable 52-bit virtual addressing for 4k and 16k granule configs")
> Cc: <stable@vger.kernel.org>
> Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> arch/arm64/include/asm/pgtable-hwdef.h | 6 ------
> arch/arm64/include/asm/pgtable-prot.h | 7 +++++++
> arch/arm64/include/asm/sparsemem.h | 4 +++-
> 3 files changed, 10 insertions(+), 7 deletions(-)
>
> diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
> index c78a988cca93..a9136cc551cc 100644
> --- a/arch/arm64/include/asm/pgtable-hwdef.h
> +++ b/arch/arm64/include/asm/pgtable-hwdef.h
> @@ -222,12 +222,6 @@
> */
> #define S1_TABLE_AP (_AT(pmdval_t, 3) << 61)
>
> -/*
> - * Highest possible physical address supported.
> - */
> -#define PHYS_MASK_SHIFT (CONFIG_ARM64_PA_BITS)
> -#define PHYS_MASK ((UL(1) << PHYS_MASK_SHIFT) - 1)
> -
> #define TTBR_CNP_BIT (UL(1) << 0)
>
> /*
> diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
> index 9f9cf13bbd95..a95f1f77bb39 100644
> --- a/arch/arm64/include/asm/pgtable-prot.h
> +++ b/arch/arm64/include/asm/pgtable-prot.h
> @@ -81,6 +81,7 @@ extern unsigned long prot_ns_shared;
> #define lpa2_is_enabled() false
> #define PTE_MAYBE_SHARED PTE_SHARED
> #define PMD_MAYBE_SHARED PMD_SECT_S
> +#define PHYS_MASK_SHIFT (CONFIG_ARM64_PA_BITS)
> #else
> static inline bool __pure lpa2_is_enabled(void)
> {
> @@ -89,8 +90,14 @@ static inline bool __pure lpa2_is_enabled(void)
>
> #define PTE_MAYBE_SHARED (lpa2_is_enabled() ? 0 : PTE_SHARED)
> #define PMD_MAYBE_SHARED (lpa2_is_enabled() ? 0 : PMD_SECT_S)
> +#define PHYS_MASK_SHIFT (lpa2_is_enabled() ? CONFIG_ARM64_PA_BITS : 48)
> #endif
>
> +/*
> + * Highest possible physical address supported.
> + */
> +#define PHYS_MASK ((UL(1) << PHYS_MASK_SHIFT) - 1)
> +
> /*
> * If we have userspace only BTI we don't want to mark kernel pages
> * guarded even if the system does support BTI.
> diff --git a/arch/arm64/include/asm/sparsemem.h b/arch/arm64/include/asm/sparsemem.h
> index 8a8acc220371..035e0ca74e88 100644
> --- a/arch/arm64/include/asm/sparsemem.h
> +++ b/arch/arm64/include/asm/sparsemem.h
> @@ -5,7 +5,9 @@
> #ifndef __ASM_SPARSEMEM_H
> #define __ASM_SPARSEMEM_H
>
> -#define MAX_PHYSMEM_BITS CONFIG_ARM64_PA_BITS
> +#include <asm/pgtable-prot.h>
> +
> +#define MAX_PHYSMEM_BITS PHYS_MASK_SHIFT
>
This needs
--- a/arch/arm64/include/asm/sparsemem.h
+++ b/arch/arm64/include/asm/sparsemem.h
@@ -7,7 +7,8 @@
#include <asm/pgtable-prot.h>
-#define MAX_PHYSMEM_BITS PHYS_MASK_SHIFT
+#define MAX_PHYSMEM_BITS PHYS_MASK_SHIFT
+#define MAX_POSSIBLE_PHYSMEM_BITS (52)
/*
* Section size must be at least 512MB for 64K base
applied on top to make the ZSMALLOC code happy.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2024-12-09 13:18 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20241205150229.3510177-8-ardb+git@google.com>
2024-12-05 15:02 ` [PATCH v2 1/6] arm64/mm: Reduce PA space to 48 bits when LPA2 is not enabled Ard Biesheuvel
2024-12-09 13:18 ` Ard Biesheuvel
2024-12-05 15:02 ` [PATCH v2 2/6] arm64/mm: Override PARange for !LPA2 and use it consistently Ard Biesheuvel
2024-12-05 15:02 ` [PATCH v2 3/6] arm64/kvm: Configure HYP TCR.PS/DS based on host stage1 Ard Biesheuvel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox