]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
arm64: Mitigate spectre style branch history side channels
authorJames Morse <james.morse@arm.com>
Wed, 10 Nov 2021 14:48:00 +0000 (14:48 +0000)
committerJames Morse <james.morse@arm.com>
Thu, 24 Feb 2022 13:58:52 +0000 (13:58 +0000)
Speculation attacks against some high-performance processors can
make use of branch history to influence future speculation.
When taking an exception from user-space, a sequence of branches
or a firmware call overwrites or invalidates the branch history.

The sequence of branches is added to the vectors, and should appear
before the first indirect branch. For systems using KPTI the sequence
is added to the kpti trampoline where it has a free register as the exit
from the trampoline is via a 'ret'. For systems not using KPTI, the same
register tricks are used to free up a register in the vectors.

For the firmware call, arch-workaround-3 clobbers 4 registers, so
there is no choice but to save them to the EL1 stack. This only happens
for entry from EL0, so if we take an exception due to the stack access,
it will not become re-entrant.

For KVM, the existing branch-predictor-hardening vectors are used.
When a spectre version of these vectors is in use, the firmware call
is sufficient to mitigate against Spectre-BHB. For the non-spectre
versions, the sequence of branches is added to the indirect vector.

Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: James Morse <james.morse@arm.com>
12 files changed:
arch/arm64/Kconfig
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/cputype.h
arch/arm64/include/asm/spectre.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/vectors.h
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/image-vars.h
arch/arm64/kernel/proton-pack.c
arch/arm64/kvm/hyp/hyp-entry.S
arch/arm64/tools/cpucaps

index cbcd42decb2add4924f5b4801d388da90d65404c..c9631626c0b3cd2b5d0601e84811804271789ef8 100644 (file)
@@ -1382,6 +1382,15 @@ config UNMAP_KERNEL_AT_EL0
 
          If unsure, say Y.
 
+config MITIGATE_SPECTRE_BRANCH_HISTORY
+       bool "Mitigate Spectre style attacks against branch history" if EXPERT
+       default y
+       help
+         Speculation attacks against some high-performance processors can
+         make use of branch history to influence future speculation.
+         When taking an exception from user-space, a sequence of branches
+         or a firmware call overwrites the branch history.
+
 config RODATA_FULL_DEFAULT_ENABLED
        bool "Apply r/o permissions of VM areas also to their linear aliases"
        default y
index 046c38ee2841a030b7add99192918b3969de5824..5cc97130843f0637418a00749353e879b3939042 100644 (file)
@@ -852,7 +852,9 @@ alternative_endif
 
        .macro __mitigate_spectre_bhb_loop      tmp
 #ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
-       mov     \tmp, #32
+alternative_cb  spectre_bhb_patch_loop_iter
+       mov     \tmp, #32               // Patched to correct the immediate
+alternative_cb_end
 .Lspectre_bhb_loop\@:
        b       . + 4
        subs    \tmp, \tmp, #1
@@ -861,6 +863,16 @@ alternative_endif
 #endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
        .endm
 
+       .macro mitigate_spectre_bhb_loop        tmp
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+alternative_cb spectre_bhb_patch_loop_mitigation_enable
+       b       .L_spectre_bhb_loop_done\@      // Patched to NOP
+alternative_cb_end
+       __mitigate_spectre_bhb_loop     \tmp
+.L_spectre_bhb_loop_done\@:
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+       .endm
+
        /* Save/restores x0-x3 to the stack */
        .macro __mitigate_spectre_bhb_fw
 #ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
index ef6be92b1921aea1d6ccece91a2ddfeced9e5726..b158fd447f3a3eed546edd215cb504ba6a2ad3a5 100644 (file)
@@ -637,6 +637,22 @@ static inline bool cpu_supports_mixed_endian_el0(void)
        return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1));
 }
 
+
+static inline bool supports_csv2p3(int scope)
+{
+       u64 pfr0;
+       u8 csv2_val;
+
+       if (scope == SCOPE_LOCAL_CPU)
+               pfr0 = read_sysreg_s(SYS_ID_AA64PFR0_EL1);
+       else
+               pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
+
+       csv2_val = cpuid_feature_extract_unsigned_field(pfr0,
+                                                       ID_AA64PFR0_CSV2_SHIFT);
+       return csv2_val == 3;
+}
+
 const struct cpumask *system_32bit_el0_cpumask(void);
 DECLARE_STATIC_KEY_FALSE(arm64_mismatched_32bit_el0);
 
index 999b9149f85681e014d7fa6ab539edcfc621cdcb..bfbf0c4c7c5e5e6f43c60a8ebd2030ec12b7d233 100644 (file)
 #define ARM_CPU_PART_CORTEX_A76                0xD0B
 #define ARM_CPU_PART_NEOVERSE_N1       0xD0C
 #define ARM_CPU_PART_CORTEX_A77                0xD0D
+#define ARM_CPU_PART_NEOVERSE_V1       0xD40
+#define ARM_CPU_PART_CORTEX_A78                0xD41
+#define ARM_CPU_PART_CORTEX_X1         0xD44
 #define ARM_CPU_PART_CORTEX_A510       0xD46
 #define ARM_CPU_PART_CORTEX_A710       0xD47
 #define ARM_CPU_PART_CORTEX_X2         0xD48
 #define ARM_CPU_PART_NEOVERSE_N2       0xD49
+#define ARM_CPU_PART_CORTEX_A78C       0xD4B
 
 #define APM_CPU_PART_POTENZA           0x000
 
 #define MIDR_CORTEX_A76        MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76)
 #define MIDR_NEOVERSE_N1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N1)
 #define MIDR_CORTEX_A77        MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A77)
+#define MIDR_NEOVERSE_V1       MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V1)
+#define MIDR_CORTEX_A78        MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78)
+#define MIDR_CORTEX_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1)
 #define MIDR_CORTEX_A510 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A510)
 #define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710)
 #define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2)
 #define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2)
+#define MIDR_CORTEX_A78C       MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78C)
 #define MIDR_THUNDERX  MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
 #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
 #define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
index c617fe90a8432af3138c611945998a02f7b36df0..86e0cc9b9c685496a15869414f2b1999e052a891 100644 (file)
@@ -94,6 +94,8 @@ void spectre_v4_enable_task_mitigation(struct task_struct *tsk);
 enum mitigation_state arm64_get_meltdown_state(void);
 
 enum mitigation_state arm64_get_spectre_bhb_state(void);
-
+bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, int scope);
+u8 spectre_bhb_loop_affected(int scope);
+void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *__unused);
 #endif /* __ASSEMBLY__ */
 #endif /* __ASM_SPECTRE_H */
index 898bee0004aee603d7e51717bbb4643dbd0e6d2b..238b9f6a28fcf26233ff1a29751da7fdaac21c7a 100644 (file)
 #endif
 
 /* id_aa64mmfr1 */
+#define ID_AA64MMFR1_ECBHB_SHIFT       60
 #define ID_AA64MMFR1_AFP_SHIFT         44
 #define ID_AA64MMFR1_ETS_SHIFT         36
 #define ID_AA64MMFR1_TWED_SHIFT                32
index 3f76dfd9e0744f06d0d67bd8f11dc1fc65581297..1f65c37dc653bfdfd3daca6c6a605974b0de628b 100644 (file)
@@ -40,6 +40,11 @@ enum arm64_bp_harden_el1_vectors {
        EL1_VECTOR_KPTI,
 };
 
+#ifndef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+#define EL1_VECTOR_BHB_LOOP            -1
+#define EL1_VECTOR_BHB_FW              -1
+#endif /* !CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+
 /* The vectors to use on return from EL0. e.g. to remap the kernel */
 DECLARE_PER_CPU_READ_MOSTLY(const char *, this_cpu_vector);
 
index b217941713a8d652a710795af632e2ed8ab5576d..a401180e8d66cea4cb5b077c8b89f68d84b022d3 100644 (file)
@@ -502,6 +502,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
                .matches = has_spectre_v4,
                .cpu_enable = spectre_v4_enable_mitigation,
        },
+       {
+               .desc = "Spectre-BHB",
+               .capability = ARM64_SPECTRE_BHB,
+               .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
+               .matches = is_spectre_bhb_affected,
+               .cpu_enable = spectre_bhb_enable_mitigation,
+       },
 #ifdef CONFIG_ARM64_ERRATUM_1418040
        {
                .desc = "ARM erratum 1418040",
index 7eaf1f7c4168dbd394f4b01e1000e5e3703a3bad..56db964a4f0c2f172b4f0e8485556b8aab75559b 100644 (file)
@@ -66,6 +66,9 @@ KVM_NVHE_ALIAS(kvm_patch_vector_branch);
 KVM_NVHE_ALIAS(kvm_update_va_mask);
 KVM_NVHE_ALIAS(kvm_get_kimage_voffset);
 KVM_NVHE_ALIAS(kvm_compute_final_ctr_el0);
+KVM_NVHE_ALIAS(spectre_bhb_patch_loop_iter);
+KVM_NVHE_ALIAS(spectre_bhb_patch_loop_mitigation_enable);
+KVM_NVHE_ALIAS(spectre_bhb_patch_wa3);
 
 /* Global kernel state accessed by nVHE hyp code. */
 KVM_NVHE_ALIAS(kvm_vgic_global_state);
index 8a499b8373c0fdeef7a8367f34edfda969237f7c..fbbcd1d2eb192e804bcf938b88ae37634eb4f787 100644 (file)
 #include <linux/prctl.h>
 #include <linux/sched/task_stack.h>
 
+#include <asm/debug-monitors.h>
 #include <asm/insn.h>
 #include <asm/spectre.h>
 #include <asm/traps.h>
+#include <asm/vectors.h>
 #include <asm/virt.h>
 
 /*
@@ -796,6 +798,17 @@ int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
        }
 }
 
+/*
+ * Spectre BHB.
+ *
+ * A CPU is either:
+ * - Mitigated by a branchy loop a CPU specific number of times, and listed
+ *   in our "loop mitigated list".
+ * - Mitigated in software by the firmware Spectre v2 call.
+ * - Has the 'Exception Clears Branch History Buffer' (ECBHB) feature, so no
+ *   software mitigation in the vectors is needed.
+ * - Has CSV2.3, so is unaffected.
+ */
 static enum mitigation_state spectre_bhb_state;
 
 enum mitigation_state arm64_get_spectre_bhb_state(void)
@@ -803,12 +816,227 @@ enum mitigation_state arm64_get_spectre_bhb_state(void)
        return spectre_bhb_state;
 }
 
+enum bhb_mitigation_bits {
+       BHB_LOOP,
+       BHB_FW,
+       BHB_HW,
+};
+static unsigned long system_bhb_mitigations;
+
+/*
+ * This must be called with SCOPE_LOCAL_CPU for each type of CPU, before any
+ * SCOPE_SYSTEM call will give the right answer.
+ */
+u8 spectre_bhb_loop_affected(int scope)
+{
+       u8 k = 0;
+       static u8 max_bhb_k;
+
+       if (scope == SCOPE_LOCAL_CPU) {
+               static const struct midr_range spectre_bhb_k32_list[] = {
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_A78),
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_A78C),
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_X1),
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_A710),
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_X2),
+                       MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2),
+                       MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1),
+                       {},
+               };
+               static const struct midr_range spectre_bhb_k24_list[] = {
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_A76),
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_A77),
+                       MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1),
+                       {},
+               };
+               static const struct midr_range spectre_bhb_k8_list[] = {
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
+                       {},
+               };
+
+               if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k32_list))
+                       k = 32;
+               else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k24_list))
+                       k = 24;
+               else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k8_list))
+                       k =  8;
+
+               max_bhb_k = max(max_bhb_k, k);
+       } else {
+               k = max_bhb_k;
+       }
+
+       return k;
+}
+
+static enum mitigation_state spectre_bhb_get_cpu_fw_mitigation_state(void)
+{
+       int ret;
+       struct arm_smccc_res res;
+
+       arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+                            ARM_SMCCC_ARCH_WORKAROUND_3, &res);
+
+       ret = res.a0;
+       switch (ret) {
+       case SMCCC_RET_SUCCESS:
+               return SPECTRE_MITIGATED;
+       case SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED:
+               return SPECTRE_UNAFFECTED;
+       default:
+               fallthrough;
+       case SMCCC_RET_NOT_SUPPORTED:
+               return SPECTRE_VULNERABLE;
+       }
+}
+
+static bool is_spectre_bhb_fw_affected(int scope)
+{
+       static bool system_affected;
+       enum mitigation_state fw_state;
+       bool has_smccc = arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_NONE;
+       static const struct midr_range spectre_bhb_firmware_mitigated_list[] = {
+               MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
+               MIDR_ALL_VERSIONS(MIDR_CORTEX_A75),
+               {},
+       };
+       bool cpu_in_list = is_midr_in_range_list(read_cpuid_id(),
+                                        spectre_bhb_firmware_mitigated_list);
+
+       if (scope != SCOPE_LOCAL_CPU)
+               return system_affected;
+
+       fw_state = spectre_bhb_get_cpu_fw_mitigation_state();
+       if (cpu_in_list || (has_smccc && fw_state == SPECTRE_MITIGATED)) {
+               system_affected = true;
+               return true;
+       }
+
+       return false;
+}
+
+static bool supports_ecbhb(int scope)
+{
+       u64 mmfr1;
+
+       if (scope == SCOPE_LOCAL_CPU)
+               mmfr1 = read_sysreg_s(SYS_ID_AA64MMFR1_EL1);
+       else
+               mmfr1 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
+
+       return cpuid_feature_extract_unsigned_field(mmfr1,
+                                                   ID_AA64MMFR1_ECBHB_SHIFT);
+}
+
+bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry,
+                            int scope)
+{
+       WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
+
+       if (supports_csv2p3(scope))
+               return false;
+
+       if (spectre_bhb_loop_affected(scope))
+               return true;
+
+       if (is_spectre_bhb_fw_affected(scope))
+               return true;
+
+       return false;
+}
+
+static void this_cpu_set_vectors(enum arm64_bp_harden_el1_vectors slot)
+{
+       const char *v = arm64_get_bp_hardening_vector(slot);
+
+       if (slot < 0)
+               return;
+
+       __this_cpu_write(this_cpu_vector, v);
+
+       /*
+        * When KPTI is in use, the vectors are switched when exiting to
+        * user-space.
+        */
+       if (arm64_kernel_unmapped_at_el0())
+               return;
+
+       write_sysreg(v, vbar_el1);
+       isb();
+}
+
+void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *entry)
+{
+       bp_hardening_cb_t cpu_cb;
+       enum mitigation_state fw_state, state = SPECTRE_VULNERABLE;
+       struct bp_hardening_data *data = this_cpu_ptr(&bp_hardening_data);
+
+       if (!is_spectre_bhb_affected(entry, SCOPE_LOCAL_CPU))
+               return;
+
+       if (arm64_get_spectre_v2_state() == SPECTRE_VULNERABLE) {
+               /* No point mitigating Spectre-BHB alone. */
+       } else if (!IS_ENABLED(CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY)) {
+               pr_info_once("spectre-bhb mitigation disabled by compile time option\n");
+       } else if (cpu_mitigations_off()) {
+               pr_info_once("spectre-bhb mitigation disabled by command line option\n");
+       } else if (supports_ecbhb(SCOPE_LOCAL_CPU)) {
+               state = SPECTRE_MITIGATED;
+               set_bit(BHB_HW, &system_bhb_mitigations);
+       } else if (spectre_bhb_loop_affected(SCOPE_LOCAL_CPU)) {
+               /*
+                * Ensure KVM uses the indirect vector which will have the
+                * branchy-loop added. A57/A72-r0 will already have selected
+                * the spectre-indirect vector, which is sufficient for BHB
+                * too.
+                */
+               if (!data->slot)
+                       data->slot = HYP_VECTOR_INDIRECT;
+
+               this_cpu_set_vectors(EL1_VECTOR_BHB_LOOP);
+               state = SPECTRE_MITIGATED;
+               set_bit(BHB_LOOP, &system_bhb_mitigations);
+       } else if (is_spectre_bhb_fw_affected(SCOPE_LOCAL_CPU)) {
+               fw_state = spectre_bhb_get_cpu_fw_mitigation_state();
+               if (fw_state == SPECTRE_MITIGATED) {
+                       /*
+                        * Ensure KVM uses one of the spectre bp_hardening
+                        * vectors. The indirect vector doesn't include the EL3
+                        * call, so needs upgrading to
+                        * HYP_VECTOR_SPECTRE_INDIRECT.
+                        */
+                       if (!data->slot || data->slot == HYP_VECTOR_INDIRECT)
+                               data->slot += 1;
+
+                       this_cpu_set_vectors(EL1_VECTOR_BHB_FW);
+
+                       /*
+                        * The WA3 call in the vectors supersedes the WA1 call
+                        * made during context-switch. Uninstall any firmware
+                        * bp_hardening callback.
+                        */
+                       cpu_cb = spectre_v2_get_sw_mitigation_cb();
+                       if (__this_cpu_read(bp_hardening_data.fn) != cpu_cb)
+                               __this_cpu_write(bp_hardening_data.fn, NULL);
+
+                       state = SPECTRE_MITIGATED;
+                       set_bit(BHB_FW, &system_bhb_mitigations);
+               }
+       }
+
+       update_mitigation_state(&spectre_bhb_state, state);
+}
+
 /* Patched to NOP when enabled */
 void noinstr spectre_bhb_patch_loop_mitigation_enable(struct alt_instr *alt,
                                                     __le32 *origptr,
                                                      __le32 *updptr, int nr_inst)
 {
        BUG_ON(nr_inst != 1);
+
+       if (test_bit(BHB_LOOP, &system_bhb_mitigations))
+               *updptr++ = cpu_to_le32(aarch64_insn_gen_nop());
 }
 
 /* Patched to NOP when enabled */
@@ -817,4 +1045,54 @@ void noinstr spectre_bhb_patch_fw_mitigation_enabled(struct alt_instr *alt,
                                                   __le32 *updptr, int nr_inst)
 {
        BUG_ON(nr_inst != 1);
+
+       if (test_bit(BHB_FW, &system_bhb_mitigations))
+               *updptr++ = cpu_to_le32(aarch64_insn_gen_nop());
+}
+
+/* Patched to correct the immediate */
+void noinstr spectre_bhb_patch_loop_iter(struct alt_instr *alt,
+                                  __le32 *origptr, __le32 *updptr, int nr_inst)
+{
+       u8 rd;
+       u32 insn;
+       u16 loop_count = spectre_bhb_loop_affected(SCOPE_SYSTEM);
+
+       BUG_ON(nr_inst != 1); /* MOV -> MOV */
+
+       if (!IS_ENABLED(CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY))
+               return;
+
+       insn = le32_to_cpu(*origptr);
+       rd = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RD, insn);
+       insn = aarch64_insn_gen_movewide(rd, loop_count, 0,
+                                        AARCH64_INSN_VARIANT_64BIT,
+                                        AARCH64_INSN_MOVEWIDE_ZERO);
+       *updptr++ = cpu_to_le32(insn);
+}
+
+/* Patched to mov WA3 when supported */
+void noinstr spectre_bhb_patch_wa3(struct alt_instr *alt,
+                                  __le32 *origptr, __le32 *updptr, int nr_inst)
+{
+       u8 rd;
+       u32 insn;
+
+       BUG_ON(nr_inst != 1); /* MOV -> MOV */
+
+       if (!IS_ENABLED(CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY) ||
+           !test_bit(BHB_FW, &system_bhb_mitigations))
+               return;
+
+       insn = le32_to_cpu(*origptr);
+       rd = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RD, insn);
+
+       insn = aarch64_insn_gen_logical_immediate(AARCH64_INSN_LOGIC_ORR,
+                                                 AARCH64_INSN_VARIANT_32BIT,
+                                                 AARCH64_INSN_REG_ZR, rd,
+                                                 ARM_SMCCC_ARCH_WORKAROUND_3);
+       if (WARN_ON_ONCE(insn == AARCH64_BREAK_FAULT))
+               return;
+
+       *updptr++ = cpu_to_le32(insn);
 }
index b6b6801d96d5a9d48b7636c04976b2e4569d71dd..12aa493249559f3cab7ffdfb8b2b08c0e30565f3 100644 (file)
@@ -62,6 +62,10 @@ el1_sync:                            // Guest trapped into EL2
        /* ARM_SMCCC_ARCH_WORKAROUND_2 handling */
        eor     w1, w1, #(ARM_SMCCC_ARCH_WORKAROUND_1 ^ \
                          ARM_SMCCC_ARCH_WORKAROUND_2)
+       cbz     w1, wa_epilogue
+
+       eor     w1, w1, #(ARM_SMCCC_ARCH_WORKAROUND_2 ^ \
+                         ARM_SMCCC_ARCH_WORKAROUND_3)
        cbnz    w1, el1_trap
 
 wa_epilogue:
@@ -192,7 +196,10 @@ SYM_CODE_END(__kvm_hyp_vector)
        sub     sp, sp, #(8 * 4)
        stp     x2, x3, [sp, #(8 * 0)]
        stp     x0, x1, [sp, #(8 * 2)]
+       alternative_cb spectre_bhb_patch_wa3
+       /* Patched to mov WA3 when supported */
        mov     w0, #ARM_SMCCC_ARCH_WORKAROUND_1
+       alternative_cb_end
        smc     #0
        ldp     x2, x3, [sp, #(8 * 0)]
        add     sp, sp, #(8 * 2)
@@ -205,6 +212,7 @@ SYM_CODE_END(__kvm_hyp_vector)
        spectrev2_smccc_wa1_smc
        .else
        stp     x0, x1, [sp, #-16]!
+       mitigate_spectre_bhb_loop       x0
        .endif
        .if \indirect != 0
        alternative_cb  kvm_patch_vector_branch
index 9c65b1e25a96506a874e578ece7bdce6ec52c309..cea7533cb3043f36c360c3775fc196e0b9325fd5 100644 (file)
@@ -44,6 +44,7 @@ MTE_ASYMM
 SPECTRE_V2
 SPECTRE_V3A
 SPECTRE_V4
+SPECTRE_BHB
 SSBS
 SVE
 UNMAP_KERNEL_AT_EL0