From: Marc Zyngier Date: Thu, 30 Jun 2022 16:04:53 +0000 (+0100) Subject: arm64: Save state of HCR_EL2.E2H before switch to EL1 X-Git-Tag: v6.1-rc5~793^2~1^2~8 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b65e411d6cc2f12a728cabe66b930c63c527a340;p=platform%2Fkernel%2Flinux-starfive.git arm64: Save state of HCR_EL2.E2H before switch to EL1 As we're about to switch the way E2H-stuck CPUs boot, save the boot CPU E2H state as a flag tied to the boot mode that can then be checked by the idreg override code. This allows us to replace the is_kernel_in_hyp_mode() check with a simple comparison with this state, even when running at EL1. Note that this flag isn't saved in __boot_cpu_mode, and is only kept in a register in the assembly code. Use with caution. Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220630160500.1536744-3-maz@kernel.org Signed-off-by: Will Deacon --- diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h index dec6eee..4eb601e 100644 --- a/arch/arm64/include/asm/virt.h +++ b/arch/arm64/include/asm/virt.h @@ -49,6 +49,13 @@ #define BOOT_CPU_MODE_EL1 (0xe11) #define BOOT_CPU_MODE_EL2 (0xe12) +/* + * Flags returned together with the boot mode, but not preserved in + * __boot_cpu_mode. Used by the idreg override code to work out the + * boot state. + */ +#define BOOT_CPU_FLAG_E2H BIT_ULL(32) + #ifndef __ASSEMBLY__ #include diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 6feac4e..73eb7c9 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -457,6 +457,7 @@ SYM_FUNC_START_LOCAL(__primary_switched) bl kasan_early_init #endif mov x0, x22 // pass FDT address in x0 + mov x1, x20 // pass the full boot status bl init_feature_override // Parse cpu feature overrides mov x0, x20 bl finalise_el2 // Prefer VHE if possible @@ -479,8 +480,9 @@ SYM_FUNC_END(__primary_switched) * Since we cannot always rely on ERET synchronizing writes to sysregs (e.g. if * SCTLR_ELx.EOS is clear), we place an ISB prior to ERET. * - * Returns either BOOT_CPU_MODE_EL1 or BOOT_CPU_MODE_EL2 in w0 if - * booted in EL1 or EL2 respectively. + * Returns either BOOT_CPU_MODE_EL1 or BOOT_CPU_MODE_EL2 in x0 if + * booted in EL1 or EL2 respectively, with the top 32 bits containing + * potential context flags. These flags are *not* stored in __boot_cpu_mode. */ SYM_FUNC_START(init_kernel_el) mrs x0, CurrentEL @@ -545,6 +547,7 @@ __cpu_stick_to_vhe: mov x0, #HVC_FINALISE_EL2 hvc #0 mov x0, #BOOT_CPU_MODE_EL2 + orr x0, x0, #BOOT_CPU_FLAG_E2H ret SYM_FUNC_END(init_kernel_el) diff --git a/arch/arm64/kernel/idreg-override.c b/arch/arm64/kernel/idreg-override.c index f92836e..03185bc 100644 --- a/arch/arm64/kernel/idreg-override.c +++ b/arch/arm64/kernel/idreg-override.c @@ -19,6 +19,8 @@ #define FTR_ALIAS_NAME_LEN 30 #define FTR_ALIAS_OPTION_LEN 116 +static u64 __boot_status __initdata; + struct ftr_set_desc { char name[FTR_DESC_NAME_LEN]; struct arm64_ftr_override *override; @@ -37,7 +39,8 @@ static bool __init mmfr1_vh_filter(u64 val) * the user was trying to force nVHE on us, proceed with * attitude adjustment. */ - return !(is_kernel_in_hyp_mode() && val == 0); + return !(__boot_status == (BOOT_CPU_FLAG_E2H | BOOT_CPU_MODE_EL2) && + val == 0); } static const struct ftr_set_desc mmfr1 __initconst = { @@ -229,9 +232,9 @@ static __init void parse_cmdline(const void *fdt) } /* Keep checkers quiet */ -void init_feature_override(const void *fdt); +void init_feature_override(const void *fdt, u64 boot_status); -asmlinkage void __init init_feature_override(const void *fdt) +asmlinkage void __init init_feature_override(const void *fdt, u64 boot_status) { int i; @@ -242,6 +245,8 @@ asmlinkage void __init init_feature_override(const void *fdt) } } + __boot_status = boot_status; + parse_cmdline(fdt); for (i = 0; i < ARRAY_SIZE(regs); i++) {