Skip to content

Commit c287620

Browse files
committed
arm64: Rewrite Spectre-v4 mitigation code
Rewrite the Spectre-v4 mitigation handling code to follow the same approach as that taken by Spectre-v2. For now, report to KVM that the system is vulnerable (by forcing 'ssbd_state' to ARM64_SSBD_UNKNOWN), as this will be cleared up in subsequent steps. Signed-off-by: Will Deacon <will@kernel.org>
1 parent 9e78b65 commit c287620

9 files changed

Lines changed: 401 additions & 352 deletions

File tree

arch/arm64/include/asm/processor.h

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -198,25 +198,12 @@ static inline void start_thread_common(struct pt_regs *regs, unsigned long pc)
198198
regs->pmr_save = GIC_PRIO_IRQON;
199199
}
200200

201-
static inline void set_ssbs_bit(struct pt_regs *regs)
202-
{
203-
regs->pstate |= PSR_SSBS_BIT;
204-
}
205-
206-
static inline void set_compat_ssbs_bit(struct pt_regs *regs)
207-
{
208-
regs->pstate |= PSR_AA32_SSBS_BIT;
209-
}
210-
211201
static inline void start_thread(struct pt_regs *regs, unsigned long pc,
212202
unsigned long sp)
213203
{
214204
start_thread_common(regs, pc);
215205
regs->pstate = PSR_MODE_EL0t;
216-
217-
if (arm64_get_ssbd_state() != ARM64_SSBD_FORCE_ENABLE)
218-
set_ssbs_bit(regs);
219-
206+
spectre_v4_enable_task_mitigation(current);
220207
regs->sp = sp;
221208
}
222209

@@ -233,9 +220,7 @@ static inline void compat_start_thread(struct pt_regs *regs, unsigned long pc,
233220
regs->pstate |= PSR_AA32_E_BIT;
234221
#endif
235222

236-
if (arm64_get_ssbd_state() != ARM64_SSBD_FORCE_ENABLE)
237-
set_compat_ssbs_bit(regs);
238-
223+
spectre_v4_enable_task_mitigation(current);
239224
regs->compat_sp = sp;
240225
}
241226
#endif

arch/arm64/include/asm/spectre.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,9 @@ enum mitigation_state arm64_get_spectre_v2_state(void);
2424
bool has_spectre_v2(const struct arm64_cpu_capabilities *cap, int scope);
2525
void spectre_v2_enable_mitigation(const struct arm64_cpu_capabilities *__unused);
2626

27+
enum mitigation_state arm64_get_spectre_v4_state(void);
28+
bool has_spectre_v4(const struct arm64_cpu_capabilities *cap, int scope);
29+
void spectre_v4_enable_mitigation(const struct arm64_cpu_capabilities *__unused);
30+
void spectre_v4_enable_task_mitigation(struct task_struct *tsk);
31+
2732
#endif /* __ASM_SPECTRE_H */

arch/arm64/kernel/cpu_errata.c

Lines changed: 4 additions & 213 deletions
Original file line numberDiff line numberDiff line change
@@ -106,62 +106,7 @@ cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *cap)
106106
sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCT, 0);
107107
}
108108

109-
DEFINE_PER_CPU_READ_MOSTLY(u64, arm64_ssbd_callback_required);
110-
111-
int ssbd_state __read_mostly = ARM64_SSBD_KERNEL;
112-
static bool __ssb_safe = true;
113-
114-
static const struct ssbd_options {
115-
const char *str;
116-
int state;
117-
} ssbd_options[] = {
118-
{ "force-on", ARM64_SSBD_FORCE_ENABLE, },
119-
{ "force-off", ARM64_SSBD_FORCE_DISABLE, },
120-
{ "kernel", ARM64_SSBD_KERNEL, },
121-
};
122-
123-
static int __init ssbd_cfg(char *buf)
124-
{
125-
int i;
126-
127-
if (!buf || !buf[0])
128-
return -EINVAL;
129-
130-
for (i = 0; i < ARRAY_SIZE(ssbd_options); i++) {
131-
int len = strlen(ssbd_options[i].str);
132-
133-
if (strncmp(buf, ssbd_options[i].str, len))
134-
continue;
135-
136-
ssbd_state = ssbd_options[i].state;
137-
return 0;
138-
}
139-
140-
return -EINVAL;
141-
}
142-
early_param("ssbd", ssbd_cfg);
143-
144-
void __init arm64_update_smccc_conduit(struct alt_instr *alt,
145-
__le32 *origptr, __le32 *updptr,
146-
int nr_inst)
147-
{
148-
u32 insn;
149-
150-
BUG_ON(nr_inst != 1);
151-
152-
switch (arm_smccc_1_1_get_conduit()) {
153-
case SMCCC_CONDUIT_HVC:
154-
insn = aarch64_insn_get_hvc_value();
155-
break;
156-
case SMCCC_CONDUIT_SMC:
157-
insn = aarch64_insn_get_smc_value();
158-
break;
159-
default:
160-
return;
161-
}
162-
163-
*updptr = cpu_to_le32(insn);
164-
}
109+
int ssbd_state __read_mostly = ARM64_SSBD_UNKNOWN;
165110

166111
void __init arm64_enable_wa2_handling(struct alt_instr *alt,
167112
__le32 *origptr, __le32 *updptr,
@@ -177,144 +122,6 @@ void __init arm64_enable_wa2_handling(struct alt_instr *alt,
177122
*updptr = cpu_to_le32(aarch64_insn_gen_nop());
178123
}
179124

180-
void arm64_set_ssbd_mitigation(bool state)
181-
{
182-
int conduit;
183-
184-
if (this_cpu_has_cap(ARM64_SSBS)) {
185-
if (state)
186-
asm volatile(SET_PSTATE_SSBS(0));
187-
else
188-
asm volatile(SET_PSTATE_SSBS(1));
189-
return;
190-
}
191-
192-
conduit = arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_WORKAROUND_2, state,
193-
NULL);
194-
195-
WARN_ON_ONCE(conduit == SMCCC_CONDUIT_NONE);
196-
}
197-
198-
static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry,
199-
int scope)
200-
{
201-
struct arm_smccc_res res;
202-
bool required = true;
203-
s32 val;
204-
bool this_cpu_safe = false;
205-
int conduit;
206-
207-
WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
208-
209-
if (cpu_mitigations_off())
210-
ssbd_state = ARM64_SSBD_FORCE_DISABLE;
211-
212-
/* delay setting __ssb_safe until we get a firmware response */
213-
if (is_midr_in_range_list(read_cpuid_id(), entry->midr_range_list))
214-
this_cpu_safe = true;
215-
216-
if (this_cpu_has_cap(ARM64_SSBS)) {
217-
if (!this_cpu_safe)
218-
__ssb_safe = false;
219-
required = false;
220-
goto out_printmsg;
221-
}
222-
223-
conduit = arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
224-
ARM_SMCCC_ARCH_WORKAROUND_2, &res);
225-
226-
if (conduit == SMCCC_CONDUIT_NONE) {
227-
ssbd_state = ARM64_SSBD_UNKNOWN;
228-
if (!this_cpu_safe)
229-
__ssb_safe = false;
230-
return false;
231-
}
232-
233-
val = (s32)res.a0;
234-
235-
switch (val) {
236-
case SMCCC_RET_NOT_SUPPORTED:
237-
ssbd_state = ARM64_SSBD_UNKNOWN;
238-
if (!this_cpu_safe)
239-
__ssb_safe = false;
240-
return false;
241-
242-
/* machines with mixed mitigation requirements must not return this */
243-
case SMCCC_RET_NOT_REQUIRED:
244-
pr_info_once("%s mitigation not required\n", entry->desc);
245-
ssbd_state = ARM64_SSBD_MITIGATED;
246-
return false;
247-
248-
case SMCCC_RET_SUCCESS:
249-
__ssb_safe = false;
250-
required = true;
251-
break;
252-
253-
case 1: /* Mitigation not required on this CPU */
254-
required = false;
255-
break;
256-
257-
default:
258-
WARN_ON(1);
259-
if (!this_cpu_safe)
260-
__ssb_safe = false;
261-
return false;
262-
}
263-
264-
switch (ssbd_state) {
265-
case ARM64_SSBD_FORCE_DISABLE:
266-
arm64_set_ssbd_mitigation(false);
267-
required = false;
268-
break;
269-
270-
case ARM64_SSBD_KERNEL:
271-
if (required) {
272-
__this_cpu_write(arm64_ssbd_callback_required, 1);
273-
arm64_set_ssbd_mitigation(true);
274-
}
275-
break;
276-
277-
case ARM64_SSBD_FORCE_ENABLE:
278-
arm64_set_ssbd_mitigation(true);
279-
required = true;
280-
break;
281-
282-
default:
283-
WARN_ON(1);
284-
break;
285-
}
286-
287-
out_printmsg:
288-
switch (ssbd_state) {
289-
case ARM64_SSBD_FORCE_DISABLE:
290-
pr_info_once("%s disabled from command-line\n", entry->desc);
291-
break;
292-
293-
case ARM64_SSBD_FORCE_ENABLE:
294-
pr_info_once("%s forced from command-line\n", entry->desc);
295-
break;
296-
}
297-
298-
return required;
299-
}
300-
301-
static void cpu_enable_ssbd_mitigation(const struct arm64_cpu_capabilities *cap)
302-
{
303-
if (ssbd_state != ARM64_SSBD_FORCE_DISABLE)
304-
cap->matches(cap, SCOPE_LOCAL_CPU);
305-
}
306-
307-
/* known invulnerable cores */
308-
static const struct midr_range arm64_ssb_cpus[] = {
309-
MIDR_ALL_VERSIONS(MIDR_CORTEX_A35),
310-
MIDR_ALL_VERSIONS(MIDR_CORTEX_A53),
311-
MIDR_ALL_VERSIONS(MIDR_CORTEX_A55),
312-
MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53),
313-
MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_3XX_SILVER),
314-
MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_SILVER),
315-
{},
316-
};
317-
318125
#ifdef CONFIG_ARM64_ERRATUM_1463225
319126
DEFINE_PER_CPU(int, __in_cortex_a76_erratum_1463225_wa);
320127

@@ -674,12 +481,11 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
674481
},
675482
#endif
676483
{
677-
.desc = "Speculative Store Bypass Disable",
484+
.desc = "Spectre-v4",
678485
.capability = ARM64_SPECTRE_V4,
679486
.type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
680-
.matches = has_ssbd_mitigation,
681-
.cpu_enable = cpu_enable_ssbd_mitigation,
682-
.midr_range_list = arm64_ssb_cpus,
487+
.matches = has_spectre_v4,
488+
.cpu_enable = spectre_v4_enable_mitigation,
683489
},
684490
#ifdef CONFIG_ARM64_ERRATUM_1418040
685491
{
@@ -732,18 +538,3 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
732538
{
733539
}
734540
};
735-
736-
ssize_t cpu_show_spec_store_bypass(struct device *dev,
737-
struct device_attribute *attr, char *buf)
738-
{
739-
if (__ssb_safe)
740-
return sprintf(buf, "Not affected\n");
741-
742-
switch (ssbd_state) {
743-
case ARM64_SSBD_KERNEL:
744-
case ARM64_SSBD_FORCE_ENABLE:
745-
return sprintf(buf, "Mitigation: Speculative Store Bypass disabled via prctl\n");
746-
}
747-
748-
return sprintf(buf, "Vulnerable\n");
749-
}

arch/arm64/kernel/cpufeature.c

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,46 +1583,6 @@ static void cpu_has_fwb(const struct arm64_cpu_capabilities *__unused)
15831583
WARN_ON(val & (7 << 27 | 7 << 21));
15841584
}
15851585

1586-
static int ssbs_emulation_handler(struct pt_regs *regs, u32 instr)
1587-
{
1588-
if (user_mode(regs))
1589-
return 1;
1590-
1591-
if (instr & BIT(PSTATE_Imm_shift))
1592-
regs->pstate |= PSR_SSBS_BIT;
1593-
else
1594-
regs->pstate &= ~PSR_SSBS_BIT;
1595-
1596-
arm64_skip_faulting_instruction(regs, 4);
1597-
return 0;
1598-
}
1599-
1600-
static struct undef_hook ssbs_emulation_hook = {
1601-
.instr_mask = ~(1U << PSTATE_Imm_shift),
1602-
.instr_val = 0xd500401f | PSTATE_SSBS,
1603-
.fn = ssbs_emulation_handler,
1604-
};
1605-
1606-
static void cpu_enable_ssbs(const struct arm64_cpu_capabilities *__unused)
1607-
{
1608-
static bool undef_hook_registered = false;
1609-
static DEFINE_RAW_SPINLOCK(hook_lock);
1610-
1611-
raw_spin_lock(&hook_lock);
1612-
if (!undef_hook_registered) {
1613-
register_undef_hook(&ssbs_emulation_hook);
1614-
undef_hook_registered = true;
1615-
}
1616-
raw_spin_unlock(&hook_lock);
1617-
1618-
if (arm64_get_ssbd_state() == ARM64_SSBD_FORCE_DISABLE) {
1619-
sysreg_clear_set(sctlr_el1, 0, SCTLR_ELx_DSSBS);
1620-
arm64_set_ssbd_mitigation(false);
1621-
} else {
1622-
arm64_set_ssbd_mitigation(true);
1623-
}
1624-
}
1625-
16261586
#ifdef CONFIG_ARM64_PAN
16271587
static void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused)
16281588
{
@@ -1983,7 +1943,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
19831943
.field_pos = ID_AA64PFR1_SSBS_SHIFT,
19841944
.sign = FTR_UNSIGNED,
19851945
.min_field_value = ID_AA64PFR1_SSBS_PSTATE_ONLY,
1986-
.cpu_enable = cpu_enable_ssbs,
19871946
},
19881947
#ifdef CONFIG_ARM64_CNP
19891948
{

arch/arm64/kernel/entry.S

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,16 +132,16 @@ alternative_else_nop_endif
132132
* them if required.
133133
*/
134134
.macro apply_ssbd, state, tmp1, tmp2
135-
alternative_cb arm64_enable_wa2_handling
136-
b .L__asm_ssbd_skip\@
135+
alternative_cb spectre_v4_patch_fw_mitigation_enable
136+
b .L__asm_ssbd_skip\@ // Patched to NOP
137137
alternative_cb_end
138138
ldr_this_cpu \tmp2, arm64_ssbd_callback_required, \tmp1
139139
cbz \tmp2, .L__asm_ssbd_skip\@
140140
ldr \tmp2, [tsk, #TSK_TI_FLAGS]
141141
tbnz \tmp2, #TIF_SSBD, .L__asm_ssbd_skip\@
142142
mov w0, #ARM_SMCCC_ARCH_WORKAROUND_2
143143
mov w1, #\state
144-
alternative_cb arm64_update_smccc_conduit
144+
alternative_cb spectre_v4_patch_fw_mitigation_conduit
145145
nop // Patched to SMC/HVC #0
146146
alternative_cb_end
147147
.L__asm_ssbd_skip\@:

arch/arm64/kernel/hibernate.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -332,11 +332,7 @@ int swsusp_arch_suspend(void)
332332
* mitigation off behind our back, let's set the state
333333
* to what we expect it to be.
334334
*/
335-
switch (arm64_get_ssbd_state()) {
336-
case ARM64_SSBD_FORCE_ENABLE:
337-
case ARM64_SSBD_KERNEL:
338-
arm64_set_ssbd_mitigation(true);
339-
}
335+
spectre_v4_enable_mitigation(NULL);
340336
}
341337

342338
local_daif_restore(flags);

0 commit comments

Comments
 (0)