Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7fafcbb0 authored by Will Deacon's avatar Will Deacon Committed by Greg Kroah-Hartman
Browse files

arm64: entry: Add fake CPU feature for unmapping the kernel at EL0




Commit ea1e3de85e94 upstream.

Allow explicit disabling of the entry trampoline on the kernel command
line (kpti=off) by adding a fake CPU feature (ARM64_UNMAP_KERNEL_AT_EL0)
that can be used to toggle the alternative sequences in our entry code and
avoid use of the trampoline altogether if desired. This also allows us to
make use of a static key in arm64_kernel_unmapped_at_el0().

Reviewed-by: default avatarMark Rutland <mark.rutland@arm.com>
Tested-by: default avatarLaura Abbott <labbott@redhat.com>
Tested-by: default avatarShanker Donthineni <shankerd@codeaurora.org>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2843ade2
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -40,7 +40,8 @@
#define ARM64_WORKAROUND_858921			19
#define ARM64_WORKAROUND_CAVIUM_30115		20
#define ARM64_HAS_DCPOP				21
#define ARM64_UNMAP_KERNEL_AT_EL0		23

#define ARM64_NCAPS				22
#define ARM64_NCAPS				24

#endif /* __ASM_CPUCAPS_H */
+2 −1
Original line number Diff line number Diff line
@@ -36,7 +36,8 @@ typedef struct {

static inline bool arm64_kernel_unmapped_at_el0(void)
{
	return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0);
	return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0) &&
	       cpus_have_const_cap(ARM64_UNMAP_KERNEL_AT_EL0);
}

extern void paging_init(void);
+41 −0
Original line number Diff line number Diff line
@@ -796,6 +796,40 @@ static bool has_no_fpsimd(const struct arm64_cpu_capabilities *entry, int __unus
					ID_AA64PFR0_FP_SHIFT) < 0;
}

#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
static int __kpti_forced; /* 0: not forced, >0: forced on, <0: forced off */

static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
				int __unused)
{
	/* Forced on command line? */
	if (__kpti_forced) {
		pr_info_once("kernel page table isolation forced %s by command line option\n",
			     __kpti_forced > 0 ? "ON" : "OFF");
		return __kpti_forced > 0;
	}

	/* Useful for KASLR robustness */
	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE))
		return true;

	return false;
}

static int __init parse_kpti(char *str)
{
	bool enabled;
	int ret = strtobool(str, &enabled);

	if (ret)
		return ret;

	__kpti_forced = enabled ? 1 : -1;
	return 0;
}
__setup("kpti=", parse_kpti);
#endif	/* CONFIG_UNMAP_KERNEL_AT_EL0 */

static const struct arm64_cpu_capabilities arm64_features[] = {
	{
		.desc = "GIC system register CPU interface",
@@ -882,6 +916,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
		.def_scope = SCOPE_SYSTEM,
		.matches = hyp_offset_low,
	},
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
	{
		.capability = ARM64_UNMAP_KERNEL_AT_EL0,
		.def_scope = SCOPE_SYSTEM,
		.matches = unmap_kernel_at_el0,
	},
#endif
	{
		/* FP/SIMD is not implemented */
		.capability = ARM64_HAS_NO_FPSIMD,
+5 −4
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@
	.macro kernel_ventry, el, label, regsize = 64
	.align 7
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
alternative_if ARM64_UNMAP_KERNEL_AT_EL0
	.if	\el == 0
	.if	\regsize == 64
	mrs	x30, tpidrro_el0
@@ -82,6 +83,7 @@
	mov	x30, xzr
	.endif
	.endif
alternative_else_nop_endif
#endif

	sub	sp, sp, #S_FRAME_SIZE
@@ -321,10 +323,9 @@ alternative_else_nop_endif
	ldr	lr, [sp, #S_LR]
	add	sp, sp, #S_FRAME_SIZE		// restore sp

#ifndef CONFIG_UNMAP_KERNEL_AT_EL0
	eret
#else
	.if	\el == 0
alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
	bne	4f
	msr	far_el1, x30
	tramp_alias	x30, tramp_exit_native
@@ -332,10 +333,10 @@ alternative_else_nop_endif
4:
	tramp_alias	x30, tramp_exit_compat
	br	x30
#endif
	.else
	eret
	.endif
#endif
	.endm

	.macro	irq_stack_entry