1111#include <linux/init.h>
1212#include <linux/utsname.h>
1313#include <linux/cpu.h>
14+
15+ #include <asm/nospec-branch.h>
16+ #include <asm/cmdline.h>
1417#include <asm/bugs.h>
1518#include <asm/processor.h>
1619#include <asm/processor-flags.h>
2124#include <asm/pgtable.h>
2225#include <asm/set_memory.h>
2326
27+ static void __init spectre_v2_select_mitigation (void );
28+
2429void __init check_bugs (void )
2530{
2631 identify_boot_cpu ();
@@ -30,6 +35,9 @@ void __init check_bugs(void)
3035 print_cpu_info (& boot_cpu_data );
3136 }
3237
38+ /* Select the proper spectre mitigation before patching alternatives */
39+ spectre_v2_select_mitigation ();
40+
3341#ifdef CONFIG_X86_32
3442 /*
3543 * Check whether we are able to run this kernel safely on SMP.
@@ -62,6 +70,153 @@ void __init check_bugs(void)
6270#endif
6371}
6472
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+
65220#ifdef CONFIG_SYSFS
66221ssize_t cpu_show_meltdown (struct device * dev ,
67222 struct device_attribute * attr , char * buf )
@@ -86,6 +241,7 @@ ssize_t cpu_show_spectre_v2(struct device *dev,
86241{
87242 if (!boot_cpu_has_bug (X86_BUG_SPECTRE_V2 ))
88243 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 ]);
90246}
91247#endif
0 commit comments