aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/Kconfig.debug10
-rw-r--r--arch/x86/include/asm/cpufeature.h30
-rw-r--r--arch/x86/kernel/cpu/common.c8
3 files changed, 46 insertions, 2 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index c198b7e13e7b..c6acdf752715 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -304,4 +304,14 @@ config DEBUG_NMI_SELFTEST
304 304
305 If unsure, say N. 305 If unsure, say N.
306 306
307config X86_DEBUG_STATIC_CPU_HAS
308 bool "Debug alternatives"
309 depends on DEBUG_KERNEL
310 ---help---
311 This option causes additional code to be generated which
312 fails if static_cpu_has() is used before alternatives have
313 run.
314
315 If unsure, say N.
316
307endmenu 317endmenu
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 043d61e66efc..252b28f1176a 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -356,15 +356,35 @@ extern const char * const x86_power_flags[32];
356#endif /* CONFIG_X86_64 */ 356#endif /* CONFIG_X86_64 */
357 357
358#if __GNUC__ >= 4 358#if __GNUC__ >= 4
359extern void warn_pre_alternatives(void);
360
359/* 361/*
360 * Static testing of CPU features. Used the same as boot_cpu_has(). 362 * Static testing of CPU features. Used the same as boot_cpu_has().
361 * These are only valid after alternatives have run, but will statically 363 * These are only valid after alternatives have run, but will statically
362 * patch the target code for additional performance. 364 * patch the target code for additional performance.
363 *
364 */ 365 */
365static __always_inline __pure bool __static_cpu_has(u16 bit) 366static __always_inline __pure bool __static_cpu_has(u16 bit)
366{ 367{
367#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5 368#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5
369
370#ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS
371 /*
372 * Catch too early usage of this before alternatives
373 * have run.
374 */
375 asm goto("1: jmp %l[t_warn]\n"
376 "2:\n"
377 ".section .altinstructions,\"a\"\n"
378 " .long 1b - .\n"
379 " .long 0\n" /* no replacement */
380 " .word %P0\n" /* 1: do replace */
381 " .byte 2b - 1b\n" /* source len */
382 " .byte 0\n" /* replacement len */
383 ".previous\n"
384 /* skipping size check since replacement size = 0 */
385 : : "i" (X86_FEATURE_ALWAYS) : : t_warn);
386#endif
387
368 asm goto("1: jmp %l[t_no]\n" 388 asm goto("1: jmp %l[t_no]\n"
369 "2:\n" 389 "2:\n"
370 ".section .altinstructions,\"a\"\n" 390 ".section .altinstructions,\"a\"\n"
@@ -379,7 +399,13 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
379 return true; 399 return true;
380 t_no: 400 t_no:
381 return false; 401 return false;
382#else 402
403#ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS
404 t_warn:
405 warn_pre_alternatives();
406 return false;
407#endif
408#else /* GCC_VERSION >= 40500 */
383 u8 flag; 409 u8 flag;
384 /* Open-coded due to __stringify() in ALTERNATIVE() */ 410 /* Open-coded due to __stringify() in ALTERNATIVE() */
385 asm volatile("1: movb $0,%0\n" 411 asm volatile("1: movb $0,%0\n"
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index d388ce1f3e1b..59adaa17e220 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1364,3 +1364,11 @@ void __cpuinit cpu_init(void)
1364 fpu_init(); 1364 fpu_init();
1365} 1365}
1366#endif 1366#endif
1367
1368#ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS
1369void warn_pre_alternatives(void)
1370{
1371 WARN(1, "You're using static_cpu_has before alternatives have run!\n");
1372}
1373EXPORT_SYMBOL_GPL(warn_pre_alternatives);
1374#endif