|
@@ -46,6 +46,80 @@ static int cpu_enable_trap_ctr_access(void *__unused)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
|
|
|
+#include <asm/mmu_context.h>
|
|
|
+#include <asm/cacheflush.h>
|
|
|
+
|
|
|
+DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
|
|
|
+
|
|
|
+#ifdef CONFIG_KVM
|
|
|
+static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
|
|
|
+ const char *hyp_vecs_end)
|
|
|
+{
|
|
|
+ void *dst = lm_alias(__bp_harden_hyp_vecs_start + slot * SZ_2K);
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < SZ_2K; i += 0x80)
|
|
|
+ memcpy(dst + i, hyp_vecs_start, hyp_vecs_end - hyp_vecs_start);
|
|
|
+
|
|
|
+ flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K);
|
|
|
+}
|
|
|
+
|
|
|
+static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
|
|
|
+ const char *hyp_vecs_start,
|
|
|
+ const char *hyp_vecs_end)
|
|
|
+{
|
|
|
+ static int last_slot = -1;
|
|
|
+ static DEFINE_SPINLOCK(bp_lock);
|
|
|
+ int cpu, slot = -1;
|
|
|
+
|
|
|
+ spin_lock(&bp_lock);
|
|
|
+ for_each_possible_cpu(cpu) {
|
|
|
+ if (per_cpu(bp_hardening_data.fn, cpu) == fn) {
|
|
|
+ slot = per_cpu(bp_hardening_data.hyp_vectors_slot, cpu);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (slot == -1) {
|
|
|
+ last_slot++;
|
|
|
+ BUG_ON(((__bp_harden_hyp_vecs_end - __bp_harden_hyp_vecs_start)
|
|
|
+ / SZ_2K) <= last_slot);
|
|
|
+ slot = last_slot;
|
|
|
+ __copy_hyp_vect_bpi(slot, hyp_vecs_start, hyp_vecs_end);
|
|
|
+ }
|
|
|
+
|
|
|
+ __this_cpu_write(bp_hardening_data.hyp_vectors_slot, slot);
|
|
|
+ __this_cpu_write(bp_hardening_data.fn, fn);
|
|
|
+ spin_unlock(&bp_lock);
|
|
|
+}
|
|
|
+#else
|
|
|
+static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
|
|
|
+ const char *hyp_vecs_start,
|
|
|
+ const char *hyp_vecs_end)
|
|
|
+{
|
|
|
+ __this_cpu_write(bp_hardening_data.fn, fn);
|
|
|
+}
|
|
|
+#endif /* CONFIG_KVM */
|
|
|
+
|
|
|
+static void install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
|
|
|
+ bp_hardening_cb_t fn,
|
|
|
+ const char *hyp_vecs_start,
|
|
|
+ const char *hyp_vecs_end)
|
|
|
+{
|
|
|
+ u64 pfr0;
|
|
|
+
|
|
|
+ if (!entry->matches(entry, SCOPE_LOCAL_CPU))
|
|
|
+ return;
|
|
|
+
|
|
|
+ pfr0 = read_cpuid(ID_AA64PFR0_EL1);
|
|
|
+ if (cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_CSV2_SHIFT))
|
|
|
+ return;
|
|
|
+
|
|
|
+ __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
|
|
|
+}
|
|
|
+#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */
|
|
|
+
|
|
|
#define MIDR_RANGE(model, min, max) \
|
|
|
.def_scope = SCOPE_LOCAL_CPU, \
|
|
|
.matches = is_affected_midr_range, \
|