diff options
| author | H. Peter Anvin <hpa@zytor.com> | 2008-08-18 20:39:32 -0400 |
|---|---|---|
| committer | H. Peter Anvin <hpa@zytor.com> | 2008-09-05 19:13:52 -0400 |
| commit | b6734c35af028f06772c0b2c836c7d579e6d4dad (patch) | |
| tree | ecdfc0dc851f440b0f5861b8c3fe6b582d516d1b | |
| parent | b74b06c5f6612a72298f37baa65460a59c26ca67 (diff) | |
x86: add NOPL as a synthetic CPU feature bit
The long noops ("NOPL") are supposed to be detected by family >= 6.
Unfortunately, several non-Intel x86 implementations, both hardware
and software, don't obey this dictum. Instead, probe for NOPL
directly by executing a NOPL instruction and see if we get #UD.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
| -rw-r--r-- | arch/x86/kernel/cpu/common.c | 32 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/common_64.c | 36 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/feature_names.c | 3 | ||||
| -rw-r--r-- | include/asm-x86/cpufeature.h | 11 | ||||
| -rw-r--r-- | include/asm-x86/required-features.h | 8 |
5 files changed, 82 insertions, 8 deletions
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 80ab20d4fa39..0785b3c8d043 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <asm/mtrr.h> | 13 | #include <asm/mtrr.h> |
| 14 | #include <asm/mce.h> | 14 | #include <asm/mce.h> |
| 15 | #include <asm/pat.h> | 15 | #include <asm/pat.h> |
| 16 | #include <asm/asm.h> | ||
| 16 | #ifdef CONFIG_X86_LOCAL_APIC | 17 | #ifdef CONFIG_X86_LOCAL_APIC |
| 17 | #include <asm/mpspec.h> | 18 | #include <asm/mpspec.h> |
| 18 | #include <asm/apic.h> | 19 | #include <asm/apic.h> |
| @@ -341,6 +342,35 @@ static void __init early_cpu_detect(void) | |||
| 341 | early_get_cap(c); | 342 | early_get_cap(c); |
| 342 | } | 343 | } |
| 343 | 344 | ||
| 345 | /* | ||
| 346 | * The NOPL instruction is supposed to exist on all CPUs with | ||
| 347 | * family >= 6, unfortunately, that's not true in practice because | ||
| 348 | * of early VIA chips and (more importantly) broken virtualizers that | ||
| 349 | * are not easy to detect. Hence, probe for it based on first | ||
| 350 | * principles. | ||
| 351 | */ | ||
| 352 | static void __cpuinit detect_nopl(struct cpuinfo_x86 *c) | ||
| 353 | { | ||
| 354 | const u32 nopl_signature = 0x888c53b1; /* Random number */ | ||
| 355 | u32 has_nopl = nopl_signature; | ||
| 356 | |||
| 357 | clear_cpu_cap(c, X86_FEATURE_NOPL); | ||
| 358 | if (c->x86 >= 6) { | ||
| 359 | asm volatile("\n" | ||
| 360 | "1: .byte 0x0f,0x1f,0xc0\n" /* nopl %eax */ | ||
| 361 | "2:\n" | ||
| 362 | " .section .fixup,\"ax\"\n" | ||
| 363 | "3: xor %0,%0\n" | ||
| 364 | " jmp 2b\n" | ||
| 365 | " .previous\n" | ||
| 366 | _ASM_EXTABLE(1b,3b) | ||
| 367 | : "+a" (has_nopl)); | ||
| 368 | |||
| 369 | if (has_nopl == nopl_signature) | ||
| 370 | set_cpu_cap(c, X86_FEATURE_NOPL); | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 344 | static void __cpuinit generic_identify(struct cpuinfo_x86 *c) | 374 | static void __cpuinit generic_identify(struct cpuinfo_x86 *c) |
| 345 | { | 375 | { |
| 346 | u32 tfms, xlvl; | 376 | u32 tfms, xlvl; |
| @@ -395,8 +425,8 @@ static void __cpuinit generic_identify(struct cpuinfo_x86 *c) | |||
| 395 | } | 425 | } |
| 396 | 426 | ||
| 397 | init_scattered_cpuid_features(c); | 427 | init_scattered_cpuid_features(c); |
| 428 | detect_nopl(c); | ||
| 398 | } | 429 | } |
| 399 | |||
| 400 | } | 430 | } |
| 401 | 431 | ||
| 402 | static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c) | 432 | static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c) |
diff --git a/arch/x86/kernel/cpu/common_64.c b/arch/x86/kernel/cpu/common_64.c index dd6e3f15017e..c3afba5a81a7 100644 --- a/arch/x86/kernel/cpu/common_64.c +++ b/arch/x86/kernel/cpu/common_64.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <asm/mtrr.h> | 18 | #include <asm/mtrr.h> |
| 19 | #include <asm/mce.h> | 19 | #include <asm/mce.h> |
| 20 | #include <asm/pat.h> | 20 | #include <asm/pat.h> |
| 21 | #include <asm/asm.h> | ||
| 21 | #include <asm/numa.h> | 22 | #include <asm/numa.h> |
| 22 | #ifdef CONFIG_X86_LOCAL_APIC | 23 | #ifdef CONFIG_X86_LOCAL_APIC |
| 23 | #include <asm/mpspec.h> | 24 | #include <asm/mpspec.h> |
| @@ -215,6 +216,39 @@ static void __init early_cpu_support_print(void) | |||
| 215 | } | 216 | } |
| 216 | } | 217 | } |
| 217 | 218 | ||
| 219 | /* | ||
| 220 | * The NOPL instruction is supposed to exist on all CPUs with | ||
| 221 | * family >= 6, unfortunately, that's not true in practice because | ||
| 222 | * of early VIA chips and (more importantly) broken virtualizers that | ||
| 223 | * are not easy to detect. Hence, probe for it based on first | ||
| 224 | * principles. | ||
| 225 | * | ||
| 226 | * Note: no 64-bit chip is known to lack these, but put the code here | ||
| 227 | * for consistency with 32 bits, and to make it utterly trivial to | ||
| 228 | * diagnose the problem should it ever surface. | ||
| 229 | */ | ||
| 230 | static void __cpuinit detect_nopl(struct cpuinfo_x86 *c) | ||
| 231 | { | ||
| 232 | const u32 nopl_signature = 0x888c53b1; /* Random number */ | ||
| 233 | u32 has_nopl = nopl_signature; | ||
| 234 | |||
| 235 | clear_cpu_cap(c, X86_FEATURE_NOPL); | ||
| 236 | if (c->x86 >= 6) { | ||
| 237 | asm volatile("\n" | ||
| 238 | "1: .byte 0x0f,0x1f,0xc0\n" /* nopl %eax */ | ||
| 239 | "2:\n" | ||
| 240 | " .section .fixup,\"ax\"\n" | ||
| 241 | "3: xor %0,%0\n" | ||
| 242 | " jmp 2b\n" | ||
| 243 | " .previous\n" | ||
| 244 | _ASM_EXTABLE(1b,3b) | ||
| 245 | : "+a" (has_nopl)); | ||
| 246 | |||
| 247 | if (has_nopl == nopl_signature) | ||
| 248 | set_cpu_cap(c, X86_FEATURE_NOPL); | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 218 | static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c); | 252 | static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c); |
| 219 | 253 | ||
| 220 | void __init early_cpu_init(void) | 254 | void __init early_cpu_init(void) |
| @@ -313,6 +347,8 @@ static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c) | |||
| 313 | c->x86_phys_bits = eax & 0xff; | 347 | c->x86_phys_bits = eax & 0xff; |
| 314 | } | 348 | } |
| 315 | 349 | ||
| 350 | detect_nopl(c); | ||
| 351 | |||
| 316 | if (c->x86_vendor != X86_VENDOR_UNKNOWN && | 352 | if (c->x86_vendor != X86_VENDOR_UNKNOWN && |
| 317 | cpu_devs[c->x86_vendor]->c_early_init) | 353 | cpu_devs[c->x86_vendor]->c_early_init) |
| 318 | cpu_devs[c->x86_vendor]->c_early_init(c); | 354 | cpu_devs[c->x86_vendor]->c_early_init(c); |
diff --git a/arch/x86/kernel/cpu/feature_names.c b/arch/x86/kernel/cpu/feature_names.c index e43ad4ad4cba..c9017799497c 100644 --- a/arch/x86/kernel/cpu/feature_names.c +++ b/arch/x86/kernel/cpu/feature_names.c | |||
| @@ -39,7 +39,8 @@ const char * const x86_cap_flags[NCAPINTS*32] = { | |||
| 39 | NULL, NULL, NULL, NULL, | 39 | NULL, NULL, NULL, NULL, |
| 40 | "constant_tsc", "up", NULL, "arch_perfmon", | 40 | "constant_tsc", "up", NULL, "arch_perfmon", |
| 41 | "pebs", "bts", NULL, NULL, | 41 | "pebs", "bts", NULL, NULL, |
| 42 | "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL, | 42 | "rep_good", NULL, NULL, NULL, |
| 43 | "nopl", NULL, NULL, NULL, | ||
| 43 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | 44 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
| 44 | 45 | ||
| 45 | /* Intel-defined (#2) */ | 46 | /* Intel-defined (#2) */ |
diff --git a/include/asm-x86/cpufeature.h b/include/asm-x86/cpufeature.h index 762f6a6bc707..9489283a4bcf 100644 --- a/include/asm-x86/cpufeature.h +++ b/include/asm-x86/cpufeature.h | |||
| @@ -72,14 +72,15 @@ | |||
| 72 | #define X86_FEATURE_UP (3*32+ 9) /* smp kernel running on up */ | 72 | #define X86_FEATURE_UP (3*32+ 9) /* smp kernel running on up */ |
| 73 | #define X86_FEATURE_FXSAVE_LEAK (3*32+10) /* FXSAVE leaks FOP/FIP/FOP */ | 73 | #define X86_FEATURE_FXSAVE_LEAK (3*32+10) /* FXSAVE leaks FOP/FIP/FOP */ |
| 74 | #define X86_FEATURE_ARCH_PERFMON (3*32+11) /* Intel Architectural PerfMon */ | 74 | #define X86_FEATURE_ARCH_PERFMON (3*32+11) /* Intel Architectural PerfMon */ |
| 75 | #define X86_FEATURE_PEBS (3*32+12) /* Precise-Event Based Sampling */ | 75 | #define X86_FEATURE_PEBS (3*32+12) /* Precise-Event Based Sampling */ |
| 76 | #define X86_FEATURE_BTS (3*32+13) /* Branch Trace Store */ | 76 | #define X86_FEATURE_BTS (3*32+13) /* Branch Trace Store */ |
| 77 | #define X86_FEATURE_SYSCALL32 (3*32+14) /* syscall in ia32 userspace */ | 77 | #define X86_FEATURE_SYSCALL32 (3*32+14) /* syscall in ia32 userspace */ |
| 78 | #define X86_FEATURE_SYSENTER32 (3*32+15) /* sysenter in ia32 userspace */ | 78 | #define X86_FEATURE_SYSENTER32 (3*32+15) /* sysenter in ia32 userspace */ |
| 79 | #define X86_FEATURE_REP_GOOD (3*32+16) /* rep microcode works well on this CPU */ | 79 | #define X86_FEATURE_REP_GOOD (3*32+16) /* rep microcode works well on this CPU */ |
| 80 | #define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* Mfence synchronizes RDTSC */ | 80 | #define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* Mfence synchronizes RDTSC */ |
| 81 | #define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* Lfence synchronizes RDTSC */ | 81 | #define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* Lfence synchronizes RDTSC */ |
| 82 | #define X86_FEATURE_11AP (3*32+19) /* Bad local APIC aka 11AP */ | 82 | #define X86_FEATURE_11AP (3*32+19) /* Bad local APIC aka 11AP */ |
| 83 | #define X86_FEATURE_NOPL (3*32+20) /* The NOPL (0F 1F) instructions */ | ||
| 83 | 84 | ||
| 84 | /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ | 85 | /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ |
| 85 | #define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */ | 86 | #define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */ |
diff --git a/include/asm-x86/required-features.h b/include/asm-x86/required-features.h index adec887dd7cd..5c2ff4bc2980 100644 --- a/include/asm-x86/required-features.h +++ b/include/asm-x86/required-features.h | |||
| @@ -41,6 +41,12 @@ | |||
| 41 | # define NEED_3DNOW 0 | 41 | # define NEED_3DNOW 0 |
| 42 | #endif | 42 | #endif |
| 43 | 43 | ||
| 44 | #if defined(CONFIG_X86_P6_NOP) || defined(CONFIG_X86_64) | ||
| 45 | # define NEED_NOPL (1<<(X86_FEATURE_NOPL & 31)) | ||
| 46 | #else | ||
| 47 | # define NEED_NOPL 0 | ||
| 48 | #endif | ||
| 49 | |||
| 44 | #ifdef CONFIG_X86_64 | 50 | #ifdef CONFIG_X86_64 |
| 45 | #define NEED_PSE 0 | 51 | #define NEED_PSE 0 |
| 46 | #define NEED_MSR (1<<(X86_FEATURE_MSR & 31)) | 52 | #define NEED_MSR (1<<(X86_FEATURE_MSR & 31)) |
| @@ -67,7 +73,7 @@ | |||
| 67 | #define REQUIRED_MASK1 (NEED_LM|NEED_3DNOW) | 73 | #define REQUIRED_MASK1 (NEED_LM|NEED_3DNOW) |
| 68 | 74 | ||
| 69 | #define REQUIRED_MASK2 0 | 75 | #define REQUIRED_MASK2 0 |
| 70 | #define REQUIRED_MASK3 0 | 76 | #define REQUIRED_MASK3 (NEED_NOPL) |
| 71 | #define REQUIRED_MASK4 0 | 77 | #define REQUIRED_MASK4 0 |
| 72 | #define REQUIRED_MASK5 0 | 78 | #define REQUIRED_MASK5 0 |
| 73 | #define REQUIRED_MASK6 0 | 79 | #define REQUIRED_MASK6 0 |
