Skip to content

Commit 228a26b

Browse files
author
James Morse
committed
arm64: Use the clearbhb instruction in mitigations
Future CPUs may implement a clearbhb instruction that is sufficient to mitigate SpectreBHB. CPUs that implement this instruction, but not CSV2.3 must be affected by Spectre-BHB. Add support to use this instruction as the BHB mitigation on CPUs that support it. The instruction is in the hint space, so it will be treated by a NOP as older CPUs. Reviewed-by: Russell King (Oracle) <[email protected]> Reviewed-by: Catalin Marinas <[email protected]> Signed-off-by: James Morse <[email protected]>
1 parent a5905d6 commit 228a26b

File tree

10 files changed

+79
-0
lines changed

10 files changed

+79
-0
lines changed

arch/arm64/include/asm/assembler.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@
108108
hint #20
109109
.endm
110110

111+
/*
112+
* Clear Branch History instruction
113+
*/
114+
.macro clearbhb
115+
hint #22
116+
.endm
117+
111118
/*
112119
* Speculation barrier
113120
*/
@@ -884,6 +891,16 @@ alternative_cb smccc_patch_fw_mitigation_conduit
884891
alternative_cb_end
885892
ldp x2, x3, [sp], #16
886893
ldp x0, x1, [sp], #16
894+
#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
895+
.endm
896+
897+
.macro mitigate_spectre_bhb_clear_insn
898+
#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
899+
alternative_cb spectre_bhb_patch_clearbhb
900+
/* Patched to NOP when not supported */
901+
clearbhb
902+
isb
903+
alternative_cb_end
887904
#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
888905
.endm
889906
#endif /* __ASM_ASSEMBLER_H */

arch/arm64/include/asm/cpufeature.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,19 @@ static inline bool supports_csv2p3(int scope)
653653
return csv2_val == 3;
654654
}
655655

656+
static inline bool supports_clearbhb(int scope)
657+
{
658+
u64 isar2;
659+
660+
if (scope == SCOPE_LOCAL_CPU)
661+
isar2 = read_sysreg_s(SYS_ID_AA64ISAR2_EL1);
662+
else
663+
isar2 = read_sanitised_ftr_reg(SYS_ID_AA64ISAR2_EL1);
664+
665+
return cpuid_feature_extract_unsigned_field(isar2,
666+
ID_AA64ISAR2_CLEARBHB_SHIFT);
667+
}
668+
656669
const struct cpumask *system_32bit_el0_cpumask(void);
657670
DECLARE_STATIC_KEY_FALSE(arm64_mismatched_32bit_el0);
658671

arch/arm64/include/asm/insn.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ enum aarch64_insn_hint_cr_op {
6565
AARCH64_INSN_HINT_PSB = 0x11 << 5,
6666
AARCH64_INSN_HINT_TSB = 0x12 << 5,
6767
AARCH64_INSN_HINT_CSDB = 0x14 << 5,
68+
AARCH64_INSN_HINT_CLEARBHB = 0x16 << 5,
6869

6970
AARCH64_INSN_HINT_BTI = 0x20 << 5,
7071
AARCH64_INSN_HINT_BTIC = 0x22 << 5,

arch/arm64/include/asm/sysreg.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,7 @@
773773
#define ID_AA64ISAR1_GPI_IMP_DEF 0x1
774774

775775
/* id_aa64isar2 */
776+
#define ID_AA64ISAR2_CLEARBHB_SHIFT 28
776777
#define ID_AA64ISAR2_RPRES_SHIFT 4
777778
#define ID_AA64ISAR2_WFXT_SHIFT 0
778779

arch/arm64/include/asm/vectors.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ enum arm64_bp_harden_el1_vectors {
3232
* canonical vectors.
3333
*/
3434
EL1_VECTOR_BHB_FW,
35+
36+
/*
37+
* Use the ClearBHB instruction, before branching to the canonical
38+
* vectors.
39+
*/
40+
EL1_VECTOR_BHB_CLEAR_INSN,
3541
#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
3642

3743
/*
@@ -43,6 +49,7 @@ enum arm64_bp_harden_el1_vectors {
4349
#ifndef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
4450
#define EL1_VECTOR_BHB_LOOP -1
4551
#define EL1_VECTOR_BHB_FW -1
52+
#define EL1_VECTOR_BHB_CLEAR_INSN -1
4653
#endif /* !CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
4754

4855
/* The vectors to use on return from EL0. e.g. to remap the kernel */

arch/arm64/kernel/cpufeature.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
231231
};
232232

233233
static const struct arm64_ftr_bits ftr_id_aa64isar2[] = {
234+
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_HIGHER_SAFE, ID_AA64ISAR2_CLEARBHB_SHIFT, 4, 0),
234235
ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_RPRES_SHIFT, 4, 0),
235236
ARM64_FTR_END,
236237
};

arch/arm64/kernel/entry.S

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,7 @@ alternative_else_nop_endif
657657
#define BHB_MITIGATION_NONE 0
658658
#define BHB_MITIGATION_LOOP 1
659659
#define BHB_MITIGATION_FW 2
660+
#define BHB_MITIGATION_INSN 3
660661

661662
.macro tramp_ventry, vector_start, regsize, kpti, bhb
662663
.align 7
@@ -673,6 +674,11 @@ alternative_else_nop_endif
673674
__mitigate_spectre_bhb_loop x30
674675
.endif // \bhb == BHB_MITIGATION_LOOP
675676

677+
.if \bhb == BHB_MITIGATION_INSN
678+
clearbhb
679+
isb
680+
.endif // \bhb == BHB_MITIGATION_INSN
681+
676682
.if \kpti == 1
677683
/*
678684
* Defend against branch aliasing attacks by pushing a dummy
@@ -749,6 +755,7 @@ SYM_CODE_START_NOALIGN(tramp_vectors)
749755
#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
750756
generate_tramp_vector kpti=1, bhb=BHB_MITIGATION_LOOP
751757
generate_tramp_vector kpti=1, bhb=BHB_MITIGATION_FW
758+
generate_tramp_vector kpti=1, bhb=BHB_MITIGATION_INSN
752759
#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
753760
generate_tramp_vector kpti=1, bhb=BHB_MITIGATION_NONE
754761
SYM_CODE_END(tramp_vectors)
@@ -811,6 +818,7 @@ SYM_CODE_START(__bp_harden_el1_vectors)
811818
#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
812819
generate_el1_vector bhb=BHB_MITIGATION_LOOP
813820
generate_el1_vector bhb=BHB_MITIGATION_FW
821+
generate_el1_vector bhb=BHB_MITIGATION_INSN
814822
#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
815823
SYM_CODE_END(__bp_harden_el1_vectors)
816824
.popsection

arch/arm64/kernel/image-vars.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ KVM_NVHE_ALIAS(kvm_compute_final_ctr_el0);
6969
KVM_NVHE_ALIAS(spectre_bhb_patch_loop_iter);
7070
KVM_NVHE_ALIAS(spectre_bhb_patch_loop_mitigation_enable);
7171
KVM_NVHE_ALIAS(spectre_bhb_patch_wa3);
72+
KVM_NVHE_ALIAS(spectre_bhb_patch_clearbhb);
7273

7374
/* Global kernel state accessed by nVHE hyp code. */
7475
KVM_NVHE_ALIAS(kvm_vgic_global_state);

arch/arm64/kernel/proton-pack.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,7 @@ int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
805805
* - Mitigated by a branchy loop a CPU specific number of times, and listed
806806
* in our "loop mitigated list".
807807
* - Mitigated in software by the firmware Spectre v2 call.
808+
* - Has the ClearBHB instruction to perform the mitigation.
808809
* - Has the 'Exception Clears Branch History Buffer' (ECBHB) feature, so no
809810
* software mitigation in the vectors is needed.
810811
* - Has CSV2.3, so is unaffected.
@@ -820,6 +821,7 @@ enum bhb_mitigation_bits {
820821
BHB_LOOP,
821822
BHB_FW,
822823
BHB_HW,
824+
BHB_INSN,
823825
};
824826
static unsigned long system_bhb_mitigations;
825827

@@ -937,6 +939,9 @@ bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry,
937939
if (supports_csv2p3(scope))
938940
return false;
939941

942+
if (supports_clearbhb(scope))
943+
return true;
944+
940945
if (spectre_bhb_loop_affected(scope))
941946
return true;
942947

@@ -984,6 +989,17 @@ void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *entry)
984989
} else if (supports_ecbhb(SCOPE_LOCAL_CPU)) {
985990
state = SPECTRE_MITIGATED;
986991
set_bit(BHB_HW, &system_bhb_mitigations);
992+
} else if (supports_clearbhb(SCOPE_LOCAL_CPU)) {
993+
/*
994+
* Ensure KVM uses the indirect vector which will have ClearBHB
995+
* added.
996+
*/
997+
if (!data->slot)
998+
data->slot = HYP_VECTOR_INDIRECT;
999+
1000+
this_cpu_set_vectors(EL1_VECTOR_BHB_CLEAR_INSN);
1001+
state = SPECTRE_MITIGATED;
1002+
set_bit(BHB_INSN, &system_bhb_mitigations);
9871003
} else if (spectre_bhb_loop_affected(SCOPE_LOCAL_CPU)) {
9881004
/*
9891005
* Ensure KVM uses the indirect vector which will have the
@@ -1096,3 +1112,16 @@ void noinstr spectre_bhb_patch_wa3(struct alt_instr *alt,
10961112

10971113
*updptr++ = cpu_to_le32(insn);
10981114
}
1115+
1116+
/* Patched to NOP when not supported */
1117+
void __init spectre_bhb_patch_clearbhb(struct alt_instr *alt,
1118+
__le32 *origptr, __le32 *updptr, int nr_inst)
1119+
{
1120+
BUG_ON(nr_inst != 2);
1121+
1122+
if (test_bit(BHB_INSN, &system_bhb_mitigations))
1123+
return;
1124+
1125+
*updptr++ = cpu_to_le32(aarch64_insn_gen_nop());
1126+
*updptr++ = cpu_to_le32(aarch64_insn_gen_nop());
1127+
}

arch/arm64/kvm/hyp/hyp-entry.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ SYM_CODE_END(__kvm_hyp_vector)
213213
.else
214214
stp x0, x1, [sp, #-16]!
215215
mitigate_spectre_bhb_loop x0
216+
mitigate_spectre_bhb_clear_insn
216217
.endif
217218
.if \indirect != 0
218219
alternative_cb kvm_patch_vector_branch

0 commit comments

Comments
 (0)