aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorBorislav Petkov <bp@suse.de>2013-02-11 09:22:16 -0500
committerH. Peter Anvin <hpa@linux.intel.com>2013-02-12 18:48:41 -0500
commit9efb58de919efa8312861d454be014094f6f0ffc (patch)
treedc6edbb3b3e7922a1975f2242dca373bbea248ea /arch
parent166df91daf38f619d4ca90b58ff90983de6e40d2 (diff)
x86: Detect CPUID support early at boot
We detect CPUID function support on each CPU and save it for later use, obviating the need to play the toggle EFLAGS.ID game every time. C code is looking at ->cpuid_level anyway. Signed-off-by: Borislav Petkov <bp@suse.de> Link: http://lkml.kernel.org/r/1360592538-10643-3-git-send-email-bp@alien8.de Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kernel/head_32.S50
1 files changed, 25 insertions, 25 deletions
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index a9c5cc851285..e3725a0f4327 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -307,30 +307,39 @@ default_entry:
307 movl %eax,%cr0 307 movl %eax,%cr0
308 308
309/* 309/*
310 * New page tables may be in 4Mbyte page mode and may 310 * We want to start out with EFLAGS unambiguously cleared. Some BIOSes leave
311 * be using the global pages. 311 * bits like NT set. This would confuse the debugger if this code is traced. So
312 * initialize them properly now before switching to protected mode. That means
313 * DF in particular (even though we have cleared it earlier after copying the
314 * command line) because GCC expects it.
315 */
316 pushl $0
317 popfl
318
319/*
320 * New page tables may be in 4Mbyte page mode and may be using the global pages.
312 * 321 *
313 * NOTE! If we are on a 486 we may have no cr4 at all! 322 * NOTE! If we are on a 486 we may have no cr4 at all! Specifically, cr4 exists
314 * Specifically, cr4 exists if and only if CPUID exists 323 * if and only if CPUID exists and has flags other than the FPU flag set.
315 * and has flags other than the FPU flag set.
316 */ 324 */
325 movl $-1,pa(X86_CPUID) # preset CPUID level
317 movl $X86_EFLAGS_ID,%ecx 326 movl $X86_EFLAGS_ID,%ecx
318 pushl %ecx 327 pushl %ecx
319 popfl 328 popfl # set EFLAGS=ID
320 pushfl
321 popl %eax
322 pushl $0
323 popfl
324 pushfl 329 pushfl
325 popl %edx 330 popl %eax # get EFLAGS
326 xorl %edx,%eax 331 testl $X86_EFLAGS_ID,%eax # did EFLAGS.ID remained set?
327 testl %ecx,%eax 332 jz 6f # hw disallowed setting of ID bit
328 jz 6f # No ID flag = no CPUID = no CR4 333 # which means no CPUID and no CR4
334
335 xorl %eax,%eax
336 cpuid
337 movl %eax,pa(X86_CPUID) # save largest std CPUID function
329 338
330 movl $1,%eax 339 movl $1,%eax
331 cpuid 340 cpuid
332 andl $~1,%edx # Ignore CPUID.FPU 341 andl $~1,%edx # Ignore CPUID.FPU
333 jz 6f # No flags or only CPUID.FPU = no CR4 342 jz 6f # No flags or only CPUID.FPU = no CR4
334 343
335 movl pa(mmu_cr4_features),%eax 344 movl pa(mmu_cr4_features),%eax
336 movl %eax,%cr4 345 movl %eax,%cr4
@@ -378,14 +387,6 @@ default_entry:
378 addl $__PAGE_OFFSET, %esp 387 addl $__PAGE_OFFSET, %esp
379 388
380/* 389/*
381 * Initialize eflags. Some BIOS's leave bits like NT set. This would
382 * confuse the debugger if this code is traced.
383 * XXX - best to initialize before switching to protected mode.
384 */
385 pushl $0
386 popfl
387
388/*
389 * start system 32-bit setup. We need to re-do some of the things done 390 * start system 32-bit setup. We need to re-do some of the things done
390 * in 16-bit mode for the "real" operations. 391 * in 16-bit mode for the "real" operations.
391 */ 392 */
@@ -461,7 +462,6 @@ is486: movl $0x50022,%ecx # set AM, WP, NE and MP
461 xorl %eax,%eax # Clear LDT 462 xorl %eax,%eax # Clear LDT
462 lldt %ax 463 lldt %ax
463 464
464 cld # gcc2 wants the direction flag cleared at all times
465 pushl $0 # fake return address for unwinder 465 pushl $0 # fake return address for unwinder
466 jmp *(initial_code) 466 jmp *(initial_code)
467 467