diff options
author | Borislav Petkov <bp@suse.de> | 2013-06-09 06:07:33 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2013-06-20 20:38:14 -0400 |
commit | 4a90a99c4f8002edaa6be11bd756872ebf3f3d97 (patch) | |
tree | 1cd36003313ca46b1d725d508d5918cf6aaac254 | |
parent | 5700f743b597951743da9c7d891d3989aac0486e (diff) |
x86: Add a static_cpu_has_safe variant
We want to use this in early code where alternatives might not have run
yet and for that case we fall back to the dynamic boot_cpu_has.
For that, force a 5-byte jump since the compiler could be generating
differently sized jumps for each label.
Signed-off-by: Borislav Petkov <bp@suse.de>
Link: http://lkml.kernel.org/r/1370772454-6106-5-git-send-email-bp@alien8.de
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r-- | arch/x86/include/asm/cpufeature.h | 86 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 6 |
2 files changed, 91 insertions, 1 deletions
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 252b28f1176a..47538a61c91b 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h | |||
@@ -357,6 +357,7 @@ extern const char * const x86_power_flags[32]; | |||
357 | 357 | ||
358 | #if __GNUC__ >= 4 | 358 | #if __GNUC__ >= 4 |
359 | extern void warn_pre_alternatives(void); | 359 | extern void warn_pre_alternatives(void); |
360 | extern bool __static_cpu_has_safe(u16 bit); | ||
360 | 361 | ||
361 | /* | 362 | /* |
362 | * Static testing of CPU features. Used the same as boot_cpu_has(). | 363 | * Static testing of CPU features. Used the same as boot_cpu_has(). |
@@ -437,11 +438,94 @@ static __always_inline __pure bool __static_cpu_has(u16 bit) | |||
437 | __static_cpu_has(bit) : \ | 438 | __static_cpu_has(bit) : \ |
438 | boot_cpu_has(bit) \ | 439 | boot_cpu_has(bit) \ |
439 | ) | 440 | ) |
441 | |||
442 | static __always_inline __pure bool _static_cpu_has_safe(u16 bit) | ||
443 | { | ||
444 | #if __GNUC__ > 4 || __GNUC_MINOR__ >= 5 | ||
445 | /* | ||
446 | * We need to spell the jumps to the compiler because, depending on the offset, | ||
447 | * the replacement jump can be bigger than the original jump, and this we cannot | ||
448 | * have. Thus, we force the jump to the widest, 4-byte, signed relative | ||
449 | * offset even though the last would often fit in less bytes. | ||
450 | */ | ||
451 | asm goto("1: .byte 0xe9\n .long %l[t_dynamic] - 2f\n" | ||
452 | "2:\n" | ||
453 | ".section .altinstructions,\"a\"\n" | ||
454 | " .long 1b - .\n" /* src offset */ | ||
455 | " .long 3f - .\n" /* repl offset */ | ||
456 | " .word %P1\n" /* always replace */ | ||
457 | " .byte 2b - 1b\n" /* src len */ | ||
458 | " .byte 4f - 3f\n" /* repl len */ | ||
459 | ".previous\n" | ||
460 | ".section .altinstr_replacement,\"ax\"\n" | ||
461 | "3: .byte 0xe9\n .long %l[t_no] - 2b\n" | ||
462 | "4:\n" | ||
463 | ".previous\n" | ||
464 | ".section .altinstructions,\"a\"\n" | ||
465 | " .long 1b - .\n" /* src offset */ | ||
466 | " .long 0\n" /* no replacement */ | ||
467 | " .word %P0\n" /* feature bit */ | ||
468 | " .byte 2b - 1b\n" /* src len */ | ||
469 | " .byte 0\n" /* repl len */ | ||
470 | ".previous\n" | ||
471 | : : "i" (bit), "i" (X86_FEATURE_ALWAYS) | ||
472 | : : t_dynamic, t_no); | ||
473 | return true; | ||
474 | t_no: | ||
475 | return false; | ||
476 | t_dynamic: | ||
477 | return __static_cpu_has_safe(bit); | ||
478 | #else /* GCC_VERSION >= 40500 */ | ||
479 | u8 flag; | ||
480 | /* Open-coded due to __stringify() in ALTERNATIVE() */ | ||
481 | asm volatile("1: movb $2,%0\n" | ||
482 | "2:\n" | ||
483 | ".section .altinstructions,\"a\"\n" | ||
484 | " .long 1b - .\n" /* src offset */ | ||
485 | " .long 3f - .\n" /* repl offset */ | ||
486 | " .word %P2\n" /* always replace */ | ||
487 | " .byte 2b - 1b\n" /* source len */ | ||
488 | " .byte 4f - 3f\n" /* replacement len */ | ||
489 | ".previous\n" | ||
490 | ".section .discard,\"aw\",@progbits\n" | ||
491 | " .byte 0xff + (4f-3f) - (2b-1b)\n" /* size check */ | ||
492 | ".previous\n" | ||
493 | ".section .altinstr_replacement,\"ax\"\n" | ||
494 | "3: movb $0,%0\n" | ||
495 | "4:\n" | ||
496 | ".previous\n" | ||
497 | ".section .altinstructions,\"a\"\n" | ||
498 | " .long 1b - .\n" /* src offset */ | ||
499 | " .long 5f - .\n" /* repl offset */ | ||
500 | " .word %P1\n" /* feature bit */ | ||
501 | " .byte 4b - 3b\n" /* src len */ | ||
502 | " .byte 6f - 5f\n" /* repl len */ | ||
503 | ".previous\n" | ||
504 | ".section .discard,\"aw\",@progbits\n" | ||
505 | " .byte 0xff + (6f-5f) - (4b-3b)\n" /* size check */ | ||
506 | ".previous\n" | ||
507 | ".section .altinstr_replacement,\"ax\"\n" | ||
508 | "5: movb $1,%0\n" | ||
509 | "6:\n" | ||
510 | ".previous\n" | ||
511 | : "=qm" (flag) | ||
512 | : "i" (bit), "i" (X86_FEATURE_ALWAYS)); | ||
513 | return (flag == 2 ? __static_cpu_has_safe(bit) : flag); | ||
514 | #endif | ||
515 | } | ||
516 | |||
517 | #define static_cpu_has_safe(bit) \ | ||
518 | ( \ | ||
519 | __builtin_constant_p(boot_cpu_has(bit)) ? \ | ||
520 | boot_cpu_has(bit) : \ | ||
521 | _static_cpu_has_safe(bit) \ | ||
522 | ) | ||
440 | #else | 523 | #else |
441 | /* | 524 | /* |
442 | * gcc 3.x is too stupid to do the static test; fall back to dynamic. | 525 | * gcc 3.x is too stupid to do the static test; fall back to dynamic. |
443 | */ | 526 | */ |
444 | #define static_cpu_has(bit) boot_cpu_has(bit) | 527 | #define static_cpu_has(bit) boot_cpu_has(bit) |
528 | #define static_cpu_has_safe(bit) boot_cpu_has(bit) | ||
445 | #endif | 529 | #endif |
446 | 530 | ||
447 | #define cpu_has_bug(c, bit) cpu_has(c, (bit)) | 531 | #define cpu_has_bug(c, bit) cpu_has(c, (bit)) |
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 59adaa17e220..a4a07c0acb1f 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -1372,3 +1372,9 @@ void warn_pre_alternatives(void) | |||
1372 | } | 1372 | } |
1373 | EXPORT_SYMBOL_GPL(warn_pre_alternatives); | 1373 | EXPORT_SYMBOL_GPL(warn_pre_alternatives); |
1374 | #endif | 1374 | #endif |
1375 | |||
1376 | inline bool __static_cpu_has_safe(u16 bit) | ||
1377 | { | ||
1378 | return boot_cpu_has(bit); | ||
1379 | } | ||
1380 | EXPORT_SYMBOL_GPL(__static_cpu_has_safe); | ||