Commit b65e411d authored by Marc Zyngier's avatar Marc Zyngier Committed by Will Deacon
Browse files

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: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20220630160500.1536744-3-maz@kernel.org


Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent 7ddb0c3d
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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 <asm/ptrace.h>
+5 −2
Original line number Diff line number Diff line
@@ -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)

+8 −3
Original line number Diff line number Diff line
@@ -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++) {