162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Interface for managing mitigations for Spectre vulnerabilities.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2020 Google LLC
662306a36Sopenharmony_ci * Author: Will Deacon <will@kernel.org>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#ifndef __ASM_SPECTRE_H
1062306a36Sopenharmony_ci#define __ASM_SPECTRE_H
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define BP_HARDEN_EL2_SLOTS 4
1362306a36Sopenharmony_ci#define __BP_HARDEN_HYP_VECS_SZ	((BP_HARDEN_EL2_SLOTS - 1) * SZ_2K)
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#ifndef __ASSEMBLY__
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/percpu.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <asm/cpufeature.h>
2062306a36Sopenharmony_ci#include <asm/virt.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/* Watch out, ordering is important here. */
2362306a36Sopenharmony_cienum mitigation_state {
2462306a36Sopenharmony_ci	SPECTRE_UNAFFECTED,
2562306a36Sopenharmony_ci	SPECTRE_MITIGATED,
2662306a36Sopenharmony_ci	SPECTRE_VULNERABLE,
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistruct pt_regs;
3062306a36Sopenharmony_cistruct task_struct;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci * Note: the order of this enum corresponds to __bp_harden_hyp_vecs and
3462306a36Sopenharmony_ci * we rely on having the direct vectors first.
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_cienum arm64_hyp_spectre_vector {
3762306a36Sopenharmony_ci	/*
3862306a36Sopenharmony_ci	 * Take exceptions directly to __kvm_hyp_vector. This must be
3962306a36Sopenharmony_ci	 * 0 so that it used by default when mitigations are not needed.
4062306a36Sopenharmony_ci	 */
4162306a36Sopenharmony_ci	HYP_VECTOR_DIRECT,
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	/*
4462306a36Sopenharmony_ci	 * Bounce via a slot in the hypervisor text mapping of
4562306a36Sopenharmony_ci	 * __bp_harden_hyp_vecs, which contains an SMC call.
4662306a36Sopenharmony_ci	 */
4762306a36Sopenharmony_ci	HYP_VECTOR_SPECTRE_DIRECT,
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/*
5062306a36Sopenharmony_ci	 * Bounce via a slot in a special mapping of __bp_harden_hyp_vecs
5162306a36Sopenharmony_ci	 * next to the idmap page.
5262306a36Sopenharmony_ci	 */
5362306a36Sopenharmony_ci	HYP_VECTOR_INDIRECT,
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	/*
5662306a36Sopenharmony_ci	 * Bounce via a slot in a special mapping of __bp_harden_hyp_vecs
5762306a36Sopenharmony_ci	 * next to the idmap page, which contains an SMC call.
5862306a36Sopenharmony_ci	 */
5962306a36Sopenharmony_ci	HYP_VECTOR_SPECTRE_INDIRECT,
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_citypedef void (*bp_hardening_cb_t)(void);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistruct bp_hardening_data {
6562306a36Sopenharmony_ci	enum arm64_hyp_spectre_vector	slot;
6662306a36Sopenharmony_ci	bp_hardening_cb_t		fn;
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ciDECLARE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* Called during entry so must be __always_inline */
7262306a36Sopenharmony_cistatic __always_inline void arm64_apply_bp_hardening(void)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	struct bp_hardening_data *d;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (!cpus_have_const_cap(ARM64_SPECTRE_V2))
7762306a36Sopenharmony_ci		return;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	d = this_cpu_ptr(&bp_hardening_data);
8062306a36Sopenharmony_ci	if (d->fn)
8162306a36Sopenharmony_ci		d->fn();
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cienum mitigation_state arm64_get_spectre_v2_state(void);
8562306a36Sopenharmony_cibool has_spectre_v2(const struct arm64_cpu_capabilities *cap, int scope);
8662306a36Sopenharmony_civoid spectre_v2_enable_mitigation(const struct arm64_cpu_capabilities *__unused);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cibool has_spectre_v3a(const struct arm64_cpu_capabilities *cap, int scope);
8962306a36Sopenharmony_civoid spectre_v3a_enable_mitigation(const struct arm64_cpu_capabilities *__unused);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cienum mitigation_state arm64_get_spectre_v4_state(void);
9262306a36Sopenharmony_cibool has_spectre_v4(const struct arm64_cpu_capabilities *cap, int scope);
9362306a36Sopenharmony_civoid spectre_v4_enable_mitigation(const struct arm64_cpu_capabilities *__unused);
9462306a36Sopenharmony_civoid spectre_v4_enable_task_mitigation(struct task_struct *tsk);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cienum mitigation_state arm64_get_meltdown_state(void);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cienum mitigation_state arm64_get_spectre_bhb_state(void);
9962306a36Sopenharmony_cibool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, int scope);
10062306a36Sopenharmony_ciu8 spectre_bhb_loop_affected(int scope);
10162306a36Sopenharmony_civoid spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *__unused);
10262306a36Sopenharmony_cibool try_emulate_el1_ssbs(struct pt_regs *regs, u32 instr);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_civoid spectre_v4_patch_fw_mitigation_enable(struct alt_instr *alt, __le32 *origptr,
10562306a36Sopenharmony_ci					   __le32 *updptr, int nr_inst);
10662306a36Sopenharmony_civoid smccc_patch_fw_mitigation_conduit(struct alt_instr *alt, __le32 *origptr,
10762306a36Sopenharmony_ci				       __le32 *updptr, int nr_inst);
10862306a36Sopenharmony_civoid spectre_bhb_patch_loop_mitigation_enable(struct alt_instr *alt, __le32 *origptr,
10962306a36Sopenharmony_ci					      __le32 *updptr, int nr_inst);
11062306a36Sopenharmony_civoid spectre_bhb_patch_fw_mitigation_enabled(struct alt_instr *alt, __le32 *origptr,
11162306a36Sopenharmony_ci					     __le32 *updptr, int nr_inst);
11262306a36Sopenharmony_civoid spectre_bhb_patch_loop_iter(struct alt_instr *alt,
11362306a36Sopenharmony_ci				 __le32 *origptr, __le32 *updptr, int nr_inst);
11462306a36Sopenharmony_civoid spectre_bhb_patch_wa3(struct alt_instr *alt,
11562306a36Sopenharmony_ci			   __le32 *origptr, __le32 *updptr, int nr_inst);
11662306a36Sopenharmony_civoid spectre_bhb_patch_clearbhb(struct alt_instr *alt,
11762306a36Sopenharmony_ci				__le32 *origptr, __le32 *updptr, int nr_inst);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci#endif	/* __ASSEMBLY__ */
12062306a36Sopenharmony_ci#endif	/* __ASM_SPECTRE_H */
121