Skip to content

Commit bd09128

Browse files
author
James Morse
committed
arm64: Add percpu vectors for EL1
The Spectre-BHB workaround adds a firmware call to the vectors. This is needed on some CPUs, but not others. To avoid the unaffected CPU in a big/little pair from making the firmware call, create per cpu vectors. The per-cpu vectors only apply when returning from EL0. Systems using KPTI can use the canonical 'full-fat' vectors directly at EL1, the trampoline exit code will switch to this_cpu_vector on exit to EL0. Systems not using KPTI should always use this_cpu_vector. this_cpu_vector will point at a vector in tramp_vecs or __bp_harden_el1_vectors, depending on whether KPTI is in use. Reviewed-by: Catalin Marinas <[email protected]> Signed-off-by: James Morse <[email protected]>
1 parent b28a8ee commit bd09128

File tree

4 files changed

+53
-9
lines changed

4 files changed

+53
-9
lines changed

arch/arm64/include/asm/vectors.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@
55
#ifndef __ASM_VECTORS_H
66
#define __ASM_VECTORS_H
77

8+
#include <linux/bug.h>
9+
#include <linux/percpu.h>
10+
11+
#include <asm/fixmap.h>
12+
13+
extern char vectors[];
14+
extern char tramp_vectors[];
15+
extern char __bp_harden_el1_vectors[];
16+
817
/*
918
* Note: the order of this enum corresponds to two arrays in entry.S:
1019
* tramp_vecs and __bp_harden_el1_vectors. By default the canonical
@@ -29,6 +38,24 @@ enum arm64_bp_harden_el1_vectors {
2938
* Remap the kernel before branching to the canonical vectors.
3039
*/
3140
EL1_VECTOR_KPTI,
32-
+};
41+
};
42+
43+
/* The vectors to use on return from EL0. e.g. to remap the kernel */
44+
DECLARE_PER_CPU_READ_MOSTLY(const char *, this_cpu_vector);
45+
46+
#ifndef CONFIG_UNMAP_KERNEL_AT_EL0
47+
#define TRAMP_VALIAS 0
48+
#endif
49+
50+
static inline const char *
51+
arm64_get_bp_hardening_vector(enum arm64_bp_harden_el1_vectors slot)
52+
{
53+
if (arm64_kernel_unmapped_at_el0())
54+
return (char *)TRAMP_VALIAS + SZ_2K * slot;
55+
56+
WARN_ON_ONCE(slot == EL1_VECTOR_KPTI);
57+
58+
return __bp_harden_el1_vectors + SZ_2K * slot;
59+
}
3360

3461
#endif /* __ASM_VECTORS_H */

arch/arm64/kernel/cpufeature.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@
7373
#include <linux/mm.h>
7474
#include <linux/cpu.h>
7575
#include <linux/kasan.h>
76+
#include <linux/percpu.h>
77+
7678
#include <asm/cpu.h>
7779
#include <asm/cpufeature.h>
7880
#include <asm/cpu_ops.h>
@@ -85,6 +87,7 @@
8587
#include <asm/smp.h>
8688
#include <asm/sysreg.h>
8789
#include <asm/traps.h>
90+
#include <asm/vectors.h>
8891
#include <asm/virt.h>
8992

9093
/* Kernel representation of AT_HWCAP and AT_HWCAP2 */
@@ -110,6 +113,8 @@ DECLARE_BITMAP(boot_capabilities, ARM64_NPATCHABLE);
110113
bool arm64_use_ng_mappings = false;
111114
EXPORT_SYMBOL(arm64_use_ng_mappings);
112115

116+
DEFINE_PER_CPU_READ_MOSTLY(const char *, this_cpu_vector) = vectors;
117+
113118
/*
114119
* Permit PER_LINUX32 and execve() of 32-bit binaries even if not all CPUs
115120
* support it?
@@ -1590,6 +1595,12 @@ kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
15901595

15911596
int cpu = smp_processor_id();
15921597

1598+
if (__this_cpu_read(this_cpu_vector) == vectors) {
1599+
const char *v = arm64_get_bp_hardening_vector(EL1_VECTOR_KPTI);
1600+
1601+
__this_cpu_write(this_cpu_vector, v);
1602+
}
1603+
15931604
/*
15941605
* We don't need to rewrite the page-tables if either we've done
15951606
* it already or we have KASLR enabled and therefore have not

arch/arm64/kernel/entry.S

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
.macro kernel_ventry, el:req, ht:req, regsize:req, label:req
3939
.align 7
4040
.Lventry_start\@:
41-
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
4241
.if \el == 0
4342
/*
4443
* This must be the first instruction of the EL0 vector entries. It is
@@ -53,7 +52,6 @@
5352
.endif
5453
.Lskip_tramp_vectors_cleanup\@:
5554
.endif
56-
#endif
5755

5856
sub sp, sp, #PT_REGS_SIZE
5957
#ifdef CONFIG_VMAP_STACK
@@ -712,10 +710,10 @@ alternative_else_nop_endif
712710
.endm
713711

714712
.macro tramp_exit, regsize = 64
715-
adr x30, tramp_vectors
716-
#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
717-
add x30, x30, SZ_4K
718-
#endif
713+
tramp_data_read_var x30, this_cpu_vector
714+
get_this_cpu_offset x29
715+
ldr x30, [x30, x29]
716+
719717
msr vbar_el1, x30
720718
ldr lr, [sp, #S_LR]
721719
tramp_unmap_kernel x29
@@ -775,6 +773,8 @@ __entry_tramp_data_vectors:
775773
__entry_tramp_data___sdei_asm_handler:
776774
.quad __sdei_asm_handler
777775
#endif /* CONFIG_ARM_SDE_INTERFACE */
776+
__entry_tramp_data_this_cpu_vector:
777+
.quad this_cpu_vector
778778
SYM_DATA_END(__entry_tramp_data_start)
779779
.popsection // .rodata
780780
#endif /* CONFIG_RANDOMIZE_BASE */

arch/arm64/kvm/hyp/vhe/switch.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/kvm_host.h>
1111
#include <linux/types.h>
1212
#include <linux/jump_label.h>
13+
#include <linux/percpu.h>
1314
#include <uapi/linux/psci.h>
1415

1516
#include <kvm/arm_psci.h>
@@ -24,6 +25,8 @@
2425
#include <asm/fpsimd.h>
2526
#include <asm/debug-monitors.h>
2627
#include <asm/processor.h>
28+
#include <asm/thread_info.h>
29+
#include <asm/vectors.h>
2730

2831
/* VHE specific context */
2932
DEFINE_PER_CPU(struct kvm_host_data, kvm_host_data);
@@ -67,7 +70,7 @@ NOKPROBE_SYMBOL(__activate_traps);
6770

6871
static void __deactivate_traps(struct kvm_vcpu *vcpu)
6972
{
70-
extern char vectors[]; /* kernel exception vectors */
73+
const char *host_vectors = vectors;
7174

7275
___deactivate_traps(vcpu);
7376

@@ -81,7 +84,10 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)
8184
asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_SPECULATIVE_AT));
8285

8386
write_sysreg(CPACR_EL1_DEFAULT, cpacr_el1);
84-
write_sysreg(vectors, vbar_el1);
87+
88+
if (!arm64_kernel_unmapped_at_el0())
89+
host_vectors = __this_cpu_read(this_cpu_vector);
90+
write_sysreg(host_vectors, vbar_el1);
8591
}
8692
NOKPROBE_SYMBOL(__deactivate_traps);
8793

0 commit comments

Comments
 (0)