[PATCH 1/5] arm64: mm: use a 48-bit ID map when possible on 52-bit VA builds

Will Deacon will at kernel.org
Thu Mar 11 09:46:21 GMT 2021


On Wed, Mar 10, 2021 at 06:15:11PM +0100, Ard Biesheuvel wrote:
> 52-bit VA kernels can run on hardware that is only 48-bit capable, but
> configure the ID map as 52-bit by default. This was not a problem until
> recently, because the special T0SZ value for a 52-bit VA space was never
> programmed into the TCR register anwyay, and because a 52-bit ID map
> happens to use the same number of translation levels as a 48-bit one.
> 
> This behavior was changed by commit 1401bef703a4 ("arm64: mm: Always update
> TCR_EL1 from __cpu_set_tcr_t0sz()"), which causes the unsupported T0SZ
> value for a 52-bit VA to be programmed into TCR_EL1. While some hardware
> simply ignores this, Mark reports that Amberwing systems choke on this,
> resulting in a broken boot. But even before that commit, the unsupported
> idmap_t0sz value was exposed to KVM and used to program TCR_EL2 incorrectly
> as well.
> 
> Given that we already have to deal with address spaces being either 48-bit
> or 52-bit in size, the cleanest approach seems to be to simply default to
> a 48-bit VA ID map, and only switch to a 52-bit one if the placement of the
> kernel in DRAM requires it. This is guaranteed not to happen unless the
> system is actually 52-bit VA capable.
> 
> Fixes: 90ec95cda91a ("arm64: mm: Introduce VA_BITS_MIN")
> Reported-by: Mark Salter <msalter at redhat.com>
> Link: http://lore.kernel.org/r/20210310003216.410037-1-msalter@redhat.com
> Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> ---
>  arch/arm64/include/asm/mmu_context.h | 5 +----
>  arch/arm64/kernel/head.S             | 2 +-
>  arch/arm64/mm/mmu.c                  | 2 +-
>  3 files changed, 3 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
> index 70ce8c1d2b07..0f467d550f27 100644
> --- a/arch/arm64/include/asm/mmu_context.h
> +++ b/arch/arm64/include/asm/mmu_context.h
> @@ -65,10 +65,7 @@ extern u64 idmap_ptrs_per_pgd;
>  
>  static inline bool __cpu_uses_extended_idmap(void)
>  {
> -	if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52))
> -		return false;
> -
> -	return unlikely(idmap_t0sz != TCR_T0SZ(VA_BITS));
> +	return unlikely(idmap_t0sz != TCR_T0SZ(vabits_actual));

I'm a bit confused by this: if the idmap is using 48-bit VAs but
vabits_actual is 52, then we'll return true despite not using the extended
idmap. Have I missed something, or should that be < instead of != ?

>  }
>  
>  /*
> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
> index 66b0e0b66e31..0b0387644dc0 100644
> --- a/arch/arm64/kernel/head.S
> +++ b/arch/arm64/kernel/head.S
> @@ -319,7 +319,7 @@ SYM_FUNC_START_LOCAL(__create_page_tables)
>  	 */
>  	adrp	x5, __idmap_text_end
>  	clz	x5, x5
> -	cmp	x5, TCR_T0SZ(VA_BITS)	// default T0SZ small enough?
> +	cmp	x5, TCR_T0SZ(VA_BITS_MIN) // default T0SZ small enough?
>  	b.ge	1f			// .. then skip VA range extension

(nit: the comment immediately before this talks about VA_BITS and should
probably be updated)

Will



More information about the linux-arm-kernel mailing list