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

Ard Biesheuvel ardb at kernel.org
Wed Jan 25 11:00:34 PST 2023


On Wed, 25 Jan 2023 at 19:59, Ard Biesheuvel <ardb at kernel.org> 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

not the C bit - I ripped that out at the last minute

> 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>
> ---
>  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