Merge branch 'x86/microcode' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
[~shefty/rdma-dev.git] / arch / x86 / kernel / head_32.S
index 2f70530..73afd11 100644 (file)
@@ -311,37 +311,52 @@ ENTRY(startup_32_smp)
 
 
 default_entry:
+#define CR0_STATE      (X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | \
+                        X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | \
+                        X86_CR0_PG)
+       movl $(CR0_STATE & ~X86_CR0_PG),%eax
+       movl %eax,%cr0
+
+/*
+ * We want to start out with EFLAGS unambiguously cleared. Some BIOSes leave
+ * bits like NT set. This would confuse the debugger if this code is traced. So
+ * initialize them properly now before switching to protected mode. That means
+ * DF in particular (even though we have cleared it earlier after copying the
+ * command line) because GCC expects it.
+ */
+       pushl $0
+       popfl
+
 /*
- *     New page tables may be in 4Mbyte page mode and may
- *     be using the global pages. 
+ * New page tables may be in 4Mbyte page mode and may be using the global pages.
  *
- *     NOTE! If we are on a 486 we may have no cr4 at all!
- *     Specifically, cr4 exists if and only if CPUID exists
- *     and has flags other than the FPU flag set.
+ * NOTE! If we are on a 486 we may have no cr4 at all! Specifically, cr4 exists
+ * if and only if CPUID exists and has flags other than the FPU flag set.
  */
+       movl $-1,pa(X86_CPUID)          # preset CPUID level
        movl $X86_EFLAGS_ID,%ecx
        pushl %ecx
-       popfl
+       popfl                           # set EFLAGS=ID
        pushfl
-       popl %eax
-       pushl $0
-       popfl
-       pushfl
-       popl %edx
-       xorl %edx,%eax
-       testl %ecx,%eax
-       jz 6f                   # No ID flag = no CPUID = no CR4
+       popl %eax                       # get EFLAGS
+       testl $X86_EFLAGS_ID,%eax       # did EFLAGS.ID remained set?
+       jz enable_paging                # hw disallowed setting of ID bit
+                                       # which means no CPUID and no CR4
+
+       xorl %eax,%eax
+       cpuid
+       movl %eax,pa(X86_CPUID)         # save largest std CPUID function
 
        movl $1,%eax
        cpuid
-       andl $~1,%edx           # Ignore CPUID.FPU
-       jz 6f                   # No flags or only CPUID.FPU = no CR4
+       andl $~1,%edx                   # Ignore CPUID.FPU
+       jz enable_paging                # No flags or only CPUID.FPU = no CR4
 
        movl pa(mmu_cr4_features),%eax
        movl %eax,%cr4
 
        testb $X86_CR4_PAE, %al         # check if PAE is enabled
-       jz 6f
+       jz enable_paging
 
        /* Check if extended functions are implemented */
        movl $0x80000000, %eax
@@ -349,7 +364,7 @@ default_entry:
        /* Value must be in the range 0x80000001 to 0x8000ffff */
        subl $0x80000001, %eax
        cmpl $(0x8000ffff-0x80000001), %eax
-       ja 6f
+       ja enable_paging
 
        /* Clear bogus XD_DISABLE bits */
        call verify_cpu
@@ -358,7 +373,7 @@ default_entry:
        cpuid
        /* Execute Disable bit supported? */
        btl $(X86_FEATURE_NX & 31), %edx
-       jnc 6f
+       jnc enable_paging
 
        /* Setup EFER (Extended Feature Enable Register) */
        movl $MSR_EFER, %ecx
@@ -368,29 +383,20 @@ default_entry:
        /* Make changes effective */
        wrmsr
 
-6:
+enable_paging:
 
 /*
  * Enable paging
  */
        movl $pa(initial_page_table), %eax
        movl %eax,%cr3          /* set the page table pointer.. */
-       movl %cr0,%eax
-       orl  $X86_CR0_PG,%eax
+       movl $CR0_STATE,%eax
        movl %eax,%cr0          /* ..and set paging (PG) bit */
        ljmp $__BOOT_CS,$1f     /* Clear prefetch and normalize %eip */
 1:
        /* Shift the stack pointer to a virtual address */
        addl $__PAGE_OFFSET, %esp
 
-/*
- * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
- * confuse the debugger if this code is traced.
- * XXX - best to initialize before switching to protected mode.
- */
-       pushl $0
-       popfl
-
 /*
  * start system 32-bit setup. We need to re-do some of the things done
  * in 16-bit mode for the "real" operations.
@@ -400,31 +406,11 @@ default_entry:
        jz 1f                           # Did we do this already?
        call *%eax
 1:
-       
-/* check if it is 486 or 386. */
+
 /*
- * XXX - this does a lot of unnecessary setup.  Alignment checks don't
- * apply at our cpl of 0 and the stack ought to be aligned already, and
- * we don't need to preserve eflags.
+ * Check if it is 486
  */
-       movl $-1,X86_CPUID      # -1 for no CPUID initially
-       movb $3,X86             # at least 386
-       pushfl                  # push EFLAGS
-       popl %eax               # get EFLAGS
-       movl %eax,%ecx          # save original EFLAGS
-       xorl $0x240000,%eax     # flip AC and ID bits in EFLAGS
-       pushl %eax              # copy to EFLAGS
-       popfl                   # set EFLAGS
-       pushfl                  # get new EFLAGS
-       popl %eax               # put it in eax
-       xorl %ecx,%eax          # change in flags
-       pushl %ecx              # restore original EFLAGS
-       popfl
-       testl $0x40000,%eax     # check if AC bit changed
-       je is386
-
-       movb $4,X86             # at least 486
-       testl $0x200000,%eax    # check if ID bit changed
+       cmpl $-1,X86_CPUID
        je is486
 
        /* get vendor info */
@@ -450,11 +436,10 @@ default_entry:
        movb %cl,X86_MASK
        movl %edx,X86_CAPABILITY
 
-is486: movl $0x50022,%ecx      # set AM, WP, NE and MP
-       jmp 2f
-
-is386: movl $2,%ecx            # set MP
-2:     movl %cr0,%eax
+is486:
+       movb $4,X86
+       movl $0x50022,%ecx      # set AM, WP, NE and MP
+       movl %cr0,%eax
        andl $0x80000011,%eax   # Save PG,PE,ET
        orl %ecx,%eax
        movl %eax,%cr0
@@ -479,7 +464,6 @@ is386:      movl $2,%ecx            # set MP
        xorl %eax,%eax                  # Clear LDT
        lldt %ax
 
-       cld                     # gcc2 wants the direction flag cleared at all times
        pushl $0                # fake return address for unwinder
        jmp *(initial_code)