diff options
-rw-r--r-- | arch/x86/Kconfig.debug | 10 | ||||
-rw-r--r-- | arch/x86/include/asm/cpufeature.h | 30 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 8 |
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 | ||
307 | config 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 | |||
307 | endmenu | 317 | endmenu |
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 |
359 | extern 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 | */ |
365 | static __always_inline __pure bool __static_cpu_has(u16 bit) | 366 | static __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 | ||
1369 | void warn_pre_alternatives(void) | ||
1370 | { | ||
1371 | WARN(1, "You're using static_cpu_has before alternatives have run!\n"); | ||
1372 | } | ||
1373 | EXPORT_SYMBOL_GPL(warn_pre_alternatives); | ||
1374 | #endif | ||