[PATCH] arm64: head: Switch endianness before populating the ID map

Nathan Chancellor nathan at kernel.org
Wed Jan 25 13:34:12 PST 2023


On Wed, Jan 25, 2023 at 07:59:10PM +0100, Ard Biesheuvel wrote:
> Ensure that the endianness used for populating the ID map matches the
> endianness that the running kernel will be using, as this is no longer
> guaranteed now that create_idmap() is invoked before init_kernel_el().
> 
> Note that doing so is only safe if the MMU is off, as switching the
> endianness with the MMU on results in the active ID map to become
> invalid. So also clear the C and M bits when toggling the EE bit in
> SCTLR, and mark the MMU as disabled at boot.
> 
> Note that the same issue has resulted in preserve_boot_args() recording
> the contents of registers X0 ... X3 in the wrong byte order, although
> this is arguably a very minor concern.
> 
> Fixes: 32b135a7fafe ("arm64: head: avoid cache invalidation when entering with the MMU on")
> Reported-by: Nathan Chancellor <nathan at kernel.org>
> Signed-off-by: Ard Biesheuvel <ardb at kernel.org>

Tested-by: Nathan Chancellor <nathan at kernel.org>

Thanks a lot for the quick fix!

> ---
>  arch/arm64/include/asm/sysreg.h |  3 ++-
>  arch/arm64/kernel/head.S        | 23 ++++++++++++++++++++++-
>  2 files changed, 24 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 1312fb48f18b5a51..2facd7933948677a 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -575,6 +575,7 @@
>  #define SCTLR_ELx_DSSBS	(BIT(44))
>  #define SCTLR_ELx_ATA	(BIT(43))
>  
> +#define SCTLR_ELx_EE_SHIFT	25
>  #define SCTLR_ELx_ENIA_SHIFT	31
>  
>  #define SCTLR_ELx_ITFSB	 (BIT(37))
> @@ -583,7 +584,7 @@
>  #define SCTLR_ELx_LSMAOE (BIT(29))
>  #define SCTLR_ELx_nTLSMD (BIT(28))
>  #define SCTLR_ELx_ENDA	 (BIT(27))
> -#define SCTLR_ELx_EE     (BIT(25))
> +#define SCTLR_ELx_EE     (BIT(SCTLR_ELx_EE_SHIFT))
>  #define SCTLR_ELx_EIS	 (BIT(22))
>  #define SCTLR_ELx_IESB	 (BIT(21))
>  #define SCTLR_ELx_TSCXT	 (BIT(20))
> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
> index dc56e1d8f36eb387..107a2b87577c9b0e 100644
> --- a/arch/arm64/kernel/head.S
> +++ b/arch/arm64/kernel/head.S
> @@ -129,10 +129,31 @@ SYM_CODE_START_LOCAL(record_mmu_state)
>  	mrs	x19, sctlr_el1
>  	b.ne	0f
>  	mrs	x19, sctlr_el2
> -0:	tst	x19, #SCTLR_ELx_C		// Z := (C == 0)
> +0:
> +CPU_LE( tbnz	x19, #SCTLR_ELx_EE_SHIFT, 1f	)
> +CPU_BE( tbz	x19, #SCTLR_ELx_EE_SHIFT, 1f	)
> +	tst	x19, #SCTLR_ELx_C		// Z := (C == 0)
>  	and	x19, x19, #SCTLR_ELx_M		// isolate M bit
>  	csel	x19, xzr, x19, eq		// clear x19 if Z
>  	ret
> +
> +	/*
> +	 * Set the correct endianness early so all memory accesses issued
> +	 * before init_kernel_el() occur in the correct byte order. Note that
> +	 * this means the MMU must be disabled, or the active ID map will end
> +	 * up getting interpreted with the wrong byte order.
> +	 */
> +1:	eor	x19, x19, #SCTLR_ELx_EE
> +	bic	x19, x19, #SCTLR_ELx_M
> +	b.ne	2f
> +	pre_disable_mmu_workaround
> +	msr	sctlr_el2, x19
> +	b	3f
> +	pre_disable_mmu_workaround
> +2:	msr	sctlr_el1, x19
> +3:	isb
> +	mov	x19, xzr
> +	ret
>  SYM_CODE_END(record_mmu_state)
>  
>  /*
> -- 
> 2.39.0
> 



More information about the linux-arm-kernel mailing list