11
11
#include <linux/init.h>
12
12
#include <linux/utsname.h>
13
13
#include <linux/cpu.h>
14
+
15
+ #include <asm/nospec-branch.h>
16
+ #include <asm/cmdline.h>
14
17
#include <asm/bugs.h>
15
18
#include <asm/processor.h>
16
19
#include <asm/processor-flags.h>
21
24
#include <asm/pgtable.h>
22
25
#include <asm/set_memory.h>
23
26
27
+ static void __init spectre_v2_select_mitigation (void );
28
+
24
29
void __init check_bugs (void )
25
30
{
26
31
identify_boot_cpu ();
@@ -30,6 +35,9 @@ void __init check_bugs(void)
30
35
print_cpu_info (& boot_cpu_data );
31
36
}
32
37
38
+ /* Select the proper spectre mitigation before patching alternatives */
39
+ spectre_v2_select_mitigation ();
40
+
33
41
#ifdef CONFIG_X86_32
34
42
/*
35
43
* Check whether we are able to run this kernel safely on SMP.
@@ -62,6 +70,153 @@ void __init check_bugs(void)
62
70
#endif
63
71
}
64
72
73
+ /* The kernel command line selection */
74
+ enum spectre_v2_mitigation_cmd {
75
+ SPECTRE_V2_CMD_NONE ,
76
+ SPECTRE_V2_CMD_AUTO ,
77
+ SPECTRE_V2_CMD_FORCE ,
78
+ SPECTRE_V2_CMD_RETPOLINE ,
79
+ SPECTRE_V2_CMD_RETPOLINE_GENERIC ,
80
+ SPECTRE_V2_CMD_RETPOLINE_AMD ,
81
+ };
82
+
83
+ static const char * spectre_v2_strings [] = {
84
+ [SPECTRE_V2_NONE ] = "Vulnerable" ,
85
+ [SPECTRE_V2_RETPOLINE_MINIMAL ] = "Vulnerable: Minimal generic ASM retpoline" ,
86
+ [SPECTRE_V2_RETPOLINE_MINIMAL_AMD ] = "Vulnerable: Minimal AMD ASM retpoline" ,
87
+ [SPECTRE_V2_RETPOLINE_GENERIC ] = "Mitigation: Full generic retpoline" ,
88
+ [SPECTRE_V2_RETPOLINE_AMD ] = "Mitigation: Full AMD retpoline" ,
89
+ };
90
+
91
+ #undef pr_fmt
92
+ #define pr_fmt (fmt ) "Spectre V2 mitigation: " fmt
93
+
94
+ static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE ;
95
+
96
+ static void __init spec2_print_if_insecure (const char * reason )
97
+ {
98
+ if (boot_cpu_has_bug (X86_BUG_SPECTRE_V2 ))
99
+ pr_info ("%s\n" , reason );
100
+ }
101
+
102
+ static void __init spec2_print_if_secure (const char * reason )
103
+ {
104
+ if (!boot_cpu_has_bug (X86_BUG_SPECTRE_V2 ))
105
+ pr_info ("%s\n" , reason );
106
+ }
107
+
108
+ static inline bool retp_compiler (void )
109
+ {
110
+ return __is_defined (RETPOLINE );
111
+ }
112
+
113
+ static inline bool match_option (const char * arg , int arglen , const char * opt )
114
+ {
115
+ int len = strlen (opt );
116
+
117
+ return len == arglen && !strncmp (arg , opt , len );
118
+ }
119
+
120
+ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline (void )
121
+ {
122
+ char arg [20 ];
123
+ int ret ;
124
+
125
+ ret = cmdline_find_option (boot_command_line , "spectre_v2" , arg ,
126
+ sizeof (arg ));
127
+ if (ret > 0 ) {
128
+ if (match_option (arg , ret , "off" )) {
129
+ goto disable ;
130
+ } else if (match_option (arg , ret , "on" )) {
131
+ spec2_print_if_secure ("force enabled on command line." );
132
+ return SPECTRE_V2_CMD_FORCE ;
133
+ } else if (match_option (arg , ret , "retpoline" )) {
134
+ spec2_print_if_insecure ("retpoline selected on command line." );
135
+ return SPECTRE_V2_CMD_RETPOLINE ;
136
+ } else if (match_option (arg , ret , "retpoline,amd" )) {
137
+ if (boot_cpu_data .x86_vendor != X86_VENDOR_AMD ) {
138
+ pr_err ("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n" );
139
+ return SPECTRE_V2_CMD_AUTO ;
140
+ }
141
+ spec2_print_if_insecure ("AMD retpoline selected on command line." );
142
+ return SPECTRE_V2_CMD_RETPOLINE_AMD ;
143
+ } else if (match_option (arg , ret , "retpoline,generic" )) {
144
+ spec2_print_if_insecure ("generic retpoline selected on command line." );
145
+ return SPECTRE_V2_CMD_RETPOLINE_GENERIC ;
146
+ } else if (match_option (arg , ret , "auto" )) {
147
+ return SPECTRE_V2_CMD_AUTO ;
148
+ }
149
+ }
150
+
151
+ if (!cmdline_find_option_bool (boot_command_line , "nospectre_v2" ))
152
+ return SPECTRE_V2_CMD_AUTO ;
153
+ disable :
154
+ spec2_print_if_insecure ("disabled on command line." );
155
+ return SPECTRE_V2_CMD_NONE ;
156
+ }
157
+
158
+ static void __init spectre_v2_select_mitigation (void )
159
+ {
160
+ enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline ();
161
+ enum spectre_v2_mitigation mode = SPECTRE_V2_NONE ;
162
+
163
+ /*
164
+ * If the CPU is not affected and the command line mode is NONE or AUTO
165
+ * then nothing to do.
166
+ */
167
+ if (!boot_cpu_has_bug (X86_BUG_SPECTRE_V2 ) &&
168
+ (cmd == SPECTRE_V2_CMD_NONE || cmd == SPECTRE_V2_CMD_AUTO ))
169
+ return ;
170
+
171
+ switch (cmd ) {
172
+ case SPECTRE_V2_CMD_NONE :
173
+ return ;
174
+
175
+ case SPECTRE_V2_CMD_FORCE :
176
+ /* FALLTRHU */
177
+ case SPECTRE_V2_CMD_AUTO :
178
+ goto retpoline_auto ;
179
+
180
+ case SPECTRE_V2_CMD_RETPOLINE_AMD :
181
+ if (IS_ENABLED (CONFIG_RETPOLINE ))
182
+ goto retpoline_amd ;
183
+ break ;
184
+ case SPECTRE_V2_CMD_RETPOLINE_GENERIC :
185
+ if (IS_ENABLED (CONFIG_RETPOLINE ))
186
+ goto retpoline_generic ;
187
+ break ;
188
+ case SPECTRE_V2_CMD_RETPOLINE :
189
+ if (IS_ENABLED (CONFIG_RETPOLINE ))
190
+ goto retpoline_auto ;
191
+ break ;
192
+ }
193
+ pr_err ("kernel not compiled with retpoline; no mitigation available!" );
194
+ return ;
195
+
196
+ retpoline_auto :
197
+ if (boot_cpu_data .x86_vendor == X86_VENDOR_AMD ) {
198
+ retpoline_amd :
199
+ if (!boot_cpu_has (X86_FEATURE_LFENCE_RDTSC )) {
200
+ pr_err ("LFENCE not serializing. Switching to generic retpoline\n" );
201
+ goto retpoline_generic ;
202
+ }
203
+ mode = retp_compiler () ? SPECTRE_V2_RETPOLINE_AMD :
204
+ SPECTRE_V2_RETPOLINE_MINIMAL_AMD ;
205
+ setup_force_cpu_cap (X86_FEATURE_RETPOLINE_AMD );
206
+ setup_force_cpu_cap (X86_FEATURE_RETPOLINE );
207
+ } else {
208
+ retpoline_generic :
209
+ mode = retp_compiler () ? SPECTRE_V2_RETPOLINE_GENERIC :
210
+ SPECTRE_V2_RETPOLINE_MINIMAL ;
211
+ setup_force_cpu_cap (X86_FEATURE_RETPOLINE );
212
+ }
213
+
214
+ spectre_v2_enabled = mode ;
215
+ pr_info ("%s\n" , spectre_v2_strings [mode ]);
216
+ }
217
+
218
+ #undef pr_fmt
219
+
65
220
#ifdef CONFIG_SYSFS
66
221
ssize_t cpu_show_meltdown (struct device * dev ,
67
222
struct device_attribute * attr , char * buf )
@@ -86,6 +241,7 @@ ssize_t cpu_show_spectre_v2(struct device *dev,
86
241
{
87
242
if (!boot_cpu_has_bug (X86_BUG_SPECTRE_V2 ))
88
243
return sprintf (buf , "Not affected\n" );
89
- return sprintf (buf , "Vulnerable\n" );
244
+
245
+ return sprintf (buf , "%s\n" , spectre_v2_strings [spectre_v2_enabled ]);
90
246
}
91
247
#endif
0 commit comments