Skip to content

Commit 9dd7819

Browse files
author
Russell King (Oracle)
committed
ARM: report Spectre v2 status through sysfs
As per other architectures, add support for reporting the Spectre vulnerability status via sysfs CPU. Acked-by: Catalin Marinas <[email protected]> Signed-off-by: Russell King (Oracle) <[email protected]>
1 parent df0cc57 commit 9dd7819

File tree

5 files changed

+187
-39
lines changed

5 files changed

+187
-39
lines changed

arch/arm/include/asm/spectre.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
3+
#ifndef __ASM_SPECTRE_H
4+
#define __ASM_SPECTRE_H
5+
6+
enum {
7+
SPECTRE_UNAFFECTED,
8+
SPECTRE_MITIGATED,
9+
SPECTRE_VULNERABLE,
10+
};
11+
12+
enum {
13+
__SPECTRE_V2_METHOD_BPIALL,
14+
__SPECTRE_V2_METHOD_ICIALLU,
15+
__SPECTRE_V2_METHOD_SMC,
16+
__SPECTRE_V2_METHOD_HVC,
17+
};
18+
19+
enum {
20+
SPECTRE_V2_METHOD_BPIALL = BIT(__SPECTRE_V2_METHOD_BPIALL),
21+
SPECTRE_V2_METHOD_ICIALLU = BIT(__SPECTRE_V2_METHOD_ICIALLU),
22+
SPECTRE_V2_METHOD_SMC = BIT(__SPECTRE_V2_METHOD_SMC),
23+
SPECTRE_V2_METHOD_HVC = BIT(__SPECTRE_V2_METHOD_HVC),
24+
};
25+
26+
void spectre_v2_update_state(unsigned int state, unsigned int methods);
27+
28+
#endif

arch/arm/kernel/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,6 @@ endif
106106

107107
obj-$(CONFIG_HAVE_ARM_SMCCC) += smccc-call.o
108108

109+
obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += spectre.o
110+
109111
extra-y := $(head-y) vmlinux.lds

arch/arm/kernel/spectre.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
#include <linux/cpu.h>
3+
#include <linux/device.h>
4+
5+
#include <asm/spectre.h>
6+
7+
ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr,
8+
char *buf)
9+
{
10+
return sprintf(buf, "Mitigation: __user pointer sanitization\n");
11+
}
12+
13+
static unsigned int spectre_v2_state;
14+
static unsigned int spectre_v2_methods;
15+
16+
void spectre_v2_update_state(unsigned int state, unsigned int method)
17+
{
18+
if (state > spectre_v2_state)
19+
spectre_v2_state = state;
20+
spectre_v2_methods |= method;
21+
}
22+
23+
ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr,
24+
char *buf)
25+
{
26+
const char *method;
27+
28+
if (spectre_v2_state == SPECTRE_UNAFFECTED)
29+
return sprintf(buf, "%s\n", "Not affected");
30+
31+
if (spectre_v2_state != SPECTRE_MITIGATED)
32+
return sprintf(buf, "%s\n", "Vulnerable");
33+
34+
switch (spectre_v2_methods) {
35+
case SPECTRE_V2_METHOD_BPIALL:
36+
method = "Branch predictor hardening";
37+
break;
38+
39+
case SPECTRE_V2_METHOD_ICIALLU:
40+
method = "I-cache invalidation";
41+
break;
42+
43+
case SPECTRE_V2_METHOD_SMC:
44+
case SPECTRE_V2_METHOD_HVC:
45+
method = "Firmware call";
46+
break;
47+
48+
default:
49+
method = "Multiple mitigations";
50+
break;
51+
}
52+
53+
return sprintf(buf, "Mitigation: %s\n", method);
54+
}

arch/arm/mm/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,7 @@ config CPU_BPREDICT_DISABLE
830830

831831
config CPU_SPECTRE
832832
bool
833+
select GENERIC_CPU_VULNERABILITIES
833834

834835
config HARDEN_BRANCH_PREDICTOR
835836
bool "Harden the branch predictor against aliasing attacks" if EXPERT

arch/arm/mm/proc-v7-bugs.c

Lines changed: 102 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,35 @@
66
#include <asm/cp15.h>
77
#include <asm/cputype.h>
88
#include <asm/proc-fns.h>
9+
#include <asm/spectre.h>
910
#include <asm/system_misc.h>
1011

12+
#ifdef CONFIG_ARM_PSCI
13+
static int __maybe_unused spectre_v2_get_cpu_fw_mitigation_state(void)
14+
{
15+
struct arm_smccc_res res;
16+
17+
arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
18+
ARM_SMCCC_ARCH_WORKAROUND_1, &res);
19+
20+
switch ((int)res.a0) {
21+
case SMCCC_RET_SUCCESS:
22+
return SPECTRE_MITIGATED;
23+
24+
case SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED:
25+
return SPECTRE_UNAFFECTED;
26+
27+
default:
28+
return SPECTRE_VULNERABLE;
29+
}
30+
}
31+
#else
32+
static int __maybe_unused spectre_v2_get_cpu_fw_mitigation_state(void)
33+
{
34+
return SPECTRE_VULNERABLE;
35+
}
36+
#endif
37+
1138
#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
1239
DEFINE_PER_CPU(harden_branch_predictor_fn_t, harden_branch_predictor_fn);
1340

@@ -36,13 +63,60 @@ static void __maybe_unused call_hvc_arch_workaround_1(void)
3663
arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
3764
}
3865

39-
static void cpu_v7_spectre_init(void)
66+
static unsigned int spectre_v2_install_workaround(unsigned int method)
4067
{
4168
const char *spectre_v2_method = NULL;
4269
int cpu = smp_processor_id();
4370

4471
if (per_cpu(harden_branch_predictor_fn, cpu))
45-
return;
72+
return SPECTRE_MITIGATED;
73+
74+
switch (method) {
75+
case SPECTRE_V2_METHOD_BPIALL:
76+
per_cpu(harden_branch_predictor_fn, cpu) =
77+
harden_branch_predictor_bpiall;
78+
spectre_v2_method = "BPIALL";
79+
break;
80+
81+
case SPECTRE_V2_METHOD_ICIALLU:
82+
per_cpu(harden_branch_predictor_fn, cpu) =
83+
harden_branch_predictor_iciallu;
84+
spectre_v2_method = "ICIALLU";
85+
break;
86+
87+
case SPECTRE_V2_METHOD_HVC:
88+
per_cpu(harden_branch_predictor_fn, cpu) =
89+
call_hvc_arch_workaround_1;
90+
cpu_do_switch_mm = cpu_v7_hvc_switch_mm;
91+
spectre_v2_method = "hypervisor";
92+
break;
93+
94+
case SPECTRE_V2_METHOD_SMC:
95+
per_cpu(harden_branch_predictor_fn, cpu) =
96+
call_smc_arch_workaround_1;
97+
cpu_do_switch_mm = cpu_v7_smc_switch_mm;
98+
spectre_v2_method = "firmware";
99+
break;
100+
}
101+
102+
if (spectre_v2_method)
103+
pr_info("CPU%u: Spectre v2: using %s workaround\n",
104+
smp_processor_id(), spectre_v2_method);
105+
106+
return SPECTRE_MITIGATED;
107+
}
108+
#else
109+
static unsigned int spectre_v2_install_workaround(unsigned int method)
110+
{
111+
pr_info("CPU%u: Spectre V2: workarounds disabled by configuration\n");
112+
113+
return SPECTRE_VULNERABLE;
114+
}
115+
#endif
116+
117+
static void cpu_v7_spectre_v2_init(void)
118+
{
119+
unsigned int state, method = 0;
46120

47121
switch (read_cpuid_part()) {
48122
case ARM_CPU_PART_CORTEX_A8:
@@ -51,68 +125,57 @@ static void cpu_v7_spectre_init(void)
51125
case ARM_CPU_PART_CORTEX_A17:
52126
case ARM_CPU_PART_CORTEX_A73:
53127
case ARM_CPU_PART_CORTEX_A75:
54-
per_cpu(harden_branch_predictor_fn, cpu) =
55-
harden_branch_predictor_bpiall;
56-
spectre_v2_method = "BPIALL";
128+
state = SPECTRE_MITIGATED;
129+
method = SPECTRE_V2_METHOD_BPIALL;
57130
break;
58131

59132
case ARM_CPU_PART_CORTEX_A15:
60133
case ARM_CPU_PART_BRAHMA_B15:
61-
per_cpu(harden_branch_predictor_fn, cpu) =
62-
harden_branch_predictor_iciallu;
63-
spectre_v2_method = "ICIALLU";
134+
state = SPECTRE_MITIGATED;
135+
method = SPECTRE_V2_METHOD_ICIALLU;
64136
break;
65137

66-
#ifdef CONFIG_ARM_PSCI
67138
case ARM_CPU_PART_BRAHMA_B53:
68139
/* Requires no workaround */
140+
state = SPECTRE_UNAFFECTED;
69141
break;
142+
70143
default:
71144
/* Other ARM CPUs require no workaround */
72-
if (read_cpuid_implementor() == ARM_CPU_IMP_ARM)
145+
if (read_cpuid_implementor() == ARM_CPU_IMP_ARM) {
146+
state = SPECTRE_UNAFFECTED;
73147
break;
148+
}
149+
74150
fallthrough;
75-
/* Cortex A57/A72 require firmware workaround */
76-
case ARM_CPU_PART_CORTEX_A57:
77-
case ARM_CPU_PART_CORTEX_A72: {
78-
struct arm_smccc_res res;
79151

80-
arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
81-
ARM_SMCCC_ARCH_WORKAROUND_1, &res);
82-
if ((int)res.a0 != 0)
83-
return;
152+
/* Cortex A57/A72 require firmware workaround */
153+
case ARM_CPU_PART_CORTEX_A57:
154+
case ARM_CPU_PART_CORTEX_A72:
155+
state = spectre_v2_get_cpu_fw_mitigation_state();
156+
if (state != SPECTRE_MITIGATED)
157+
break;
84158

85159
switch (arm_smccc_1_1_get_conduit()) {
86160
case SMCCC_CONDUIT_HVC:
87-
per_cpu(harden_branch_predictor_fn, cpu) =
88-
call_hvc_arch_workaround_1;
89-
cpu_do_switch_mm = cpu_v7_hvc_switch_mm;
90-
spectre_v2_method = "hypervisor";
161+
method = SPECTRE_V2_METHOD_HVC;
91162
break;
92163

93164
case SMCCC_CONDUIT_SMC:
94-
per_cpu(harden_branch_predictor_fn, cpu) =
95-
call_smc_arch_workaround_1;
96-
cpu_do_switch_mm = cpu_v7_smc_switch_mm;
97-
spectre_v2_method = "firmware";
165+
method = SPECTRE_V2_METHOD_SMC;
98166
break;
99167

100168
default:
169+
state = SPECTRE_VULNERABLE;
101170
break;
102171
}
103172
}
104-
#endif
105-
}
106173

107-
if (spectre_v2_method)
108-
pr_info("CPU%u: Spectre v2: using %s workaround\n",
109-
smp_processor_id(), spectre_v2_method);
110-
}
111-
#else
112-
static void cpu_v7_spectre_init(void)
113-
{
174+
if (state == SPECTRE_MITIGATED)
175+
state = spectre_v2_install_workaround(method);
176+
177+
spectre_v2_update_state(state, method);
114178
}
115-
#endif
116179

117180
static __maybe_unused bool cpu_v7_check_auxcr_set(bool *warned,
118181
u32 mask, const char *msg)
@@ -142,16 +205,16 @@ static bool check_spectre_auxcr(bool *warned, u32 bit)
142205
void cpu_v7_ca8_ibe(void)
143206
{
144207
if (check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(6)))
145-
cpu_v7_spectre_init();
208+
cpu_v7_spectre_v2_init();
146209
}
147210

148211
void cpu_v7_ca15_ibe(void)
149212
{
150213
if (check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(0)))
151-
cpu_v7_spectre_init();
214+
cpu_v7_spectre_v2_init();
152215
}
153216

154217
void cpu_v7_bugs_init(void)
155218
{
156-
cpu_v7_spectre_init();
219+
cpu_v7_spectre_v2_init();
157220
}

0 commit comments

Comments
 (0)