patch-2.1.75 linux/arch/i386/kernel/head.S
Next file: linux/arch/i386/kernel/i386_ksyms.c
Previous file: linux/arch/i386/kernel/bios32.c
Back to the patch index
Back to the overall index
- Lines: 295
- Date:
Sun Dec 21 17:27:18 1997
- Orig file:
v2.1.74/linux/arch/i386/kernel/head.S
- Orig date:
Tue Dec 2 09:49:39 1997
diff -u --recursive --new-file v2.1.74/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
@@ -1,11 +1,10 @@
/*
- * linux/arch/i386/head.S
+ * linux/arch/i386/head.S -- the 32-bit startup code.
*
* Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-/*
- * head.S contains the 32-bit startup code.
+ *
+ * Enhanced CPU detection and feature setting code by Mike Jagdis
+ * and Martin Mares, November 1997.
*/
.text
@@ -20,6 +19,20 @@
#define CL_OFFSET 0x90022
/*
+ * References to members of the boot_cpu_data structure.
+ */
+
+#define CPU_PARAMS SYMBOL_NAME(boot_cpu_data)
+#define X86 CPU_PARAMS+0
+#define X86_VENDOR CPU_PARAMS+1
+#define X86_MODEL CPU_PARAMS+2
+#define X86_MASK CPU_PARAMS+3
+#define X86_HARD_MATH CPU_PARAMS+6
+#define X86_CPUID CPU_PARAMS+8
+#define X86_CAPABILITY CPU_PARAMS+12
+#define X86_VENDOR_ID CPU_PARAMS+16
+
+/*
* swapper_pg_dir is the main page directory, address 0x00101000
*/
ENTRY(stext)
@@ -45,15 +58,9 @@
* not yet offset 0xC0000000..
*/
#define cr4_bits mmu_cr4_features-0xC0000000
-#ifdef GAS_KNOWS_CR4
movl %cr4,%eax # Turn on 4Mb pages
orl cr4_bits,%eax
movl %eax,%cr4
-#else
- .byte 0x0f,0x20,0xe0
- orl cr4_bits,%eax
- .byte 0x0f,0x22,0xe0
-#endif
#endif
/*
* Setup paging (the tables are already set up, just switch them on)
@@ -135,13 +142,69 @@
checkCPUtype:
#endif
+ movl $-1,X86_CPUID # -1 for no CPUID initially
+
/* 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.
*/
- movl $3, SYMBOL_NAME(x86)
+ /*
+ * A Cyrix preserves flags in cases where other CPUs change
+ * them in undefined ways. We need to know this since we may
+ * need to enable the CPUID instruction at least. (Cyrix chips
+ * prior to M2 have CPUID disabled by default, the Cx486s
+ * didn't have it at all.)
+ */
+ xor %ax,%ax
+ sahf
+ movb $5,%al
+ movb $2,%bl
+ div %bl
+ lahf
+ cmpb $2,%ah
+ jne ncyrix
+
+ /*
+ * It behaves like a Cyrix so put "Cyrix" in the vendor id
+ * field. It may be overwritten later with the real thing
+ * if CPUID works.
+ */
+ movl $0x69727943,X86_VENDOR_ID # low 4 chars
+ movl $0x00000078,X86_VENDOR_ID # next 4 chars
+
+ /*
+ * N.B. The pattern of accesses to 0x22 and 0x23 is *important*
+ * so do not try and "optimise" it! For the same reason we
+ * do all this with interrupts off just to be sure.
+ */
+#define setCx86(reg, val) \
+ movb reg,%al; \
+ outb %al,$0x22; \
+ movb val,%al; \
+ outb %al,$0x23
+
+#define getCx86(reg) \
+ movb reg,%al; \
+ outb %al,$0x22; \
+ inb $0x23,%al
+
+ getCx86($0xc3) # get CCR3
+ movb %al,%cl # Save old value
+ movb %al,%bl
+ andb $0x0f,%bl # Enable all config registers (for CCR4 access)
+ orb $0x10,%bl
+ setCx86($0xc3,%bl)
+
+ getCx86($0xe8) # CCR4 |= CPUID
+ orb $0x80,%al
+ movb %al,%bl
+ setCx86($0xe8,%bl)
+
+ setCx86($0xc3,%cl) # Restore old CCR3
+
+ncyrix: movl $3,X86 # at least 386
pushfl # push EFLAGS
popl %eax # get EFLAGS
movl %eax,%ecx # save original EFLAGS
@@ -153,7 +216,8 @@
xorl %ecx,%eax # change in flags
andl $0x40000,%eax # check if AC bit changed
je is386
- movl $4,SYMBOL_NAME(x86)
+
+ movl $4,X86 # at least 486
movl %ecx,%eax
xorl $0x200000,%eax # check ID flag
pushl %eax
@@ -161,42 +225,74 @@
pushfl # 487SX we can't change it
popl %eax
xorl %ecx,%eax
- andl $0x200000,%eax
- je is486
-isnew: pushl %ecx # restore original EFLAGS
+ pushl %ecx # restore original EFLAGS
popfl
- incl SYMBOL_NAME(have_cpuid) # we have CPUID
- /* get processor type */
- # LINUS WE HAVE A BUG HERE - MUST CHECK WITH
- # CPUID#0 THAT CPUID#1 IS SUPPORTED...
- movl $1, %eax # Use the CPUID instruction to
- .byte 0x0f, 0xa2 # check the processor type
- movb %al, %cl # save reg for future use
- andb $0x0f,%ah # mask processor family
- movb %ah,SYMBOL_NAME(x86)
- andb $0xf0, %eax # mask model
- shrb $4, %al
- movb %al,SYMBOL_NAME(x86_model)
- andb $0x0f, %cl # mask mask revision
- movb %cl,SYMBOL_NAME(x86_mask)
- movl %edx,SYMBOL_NAME(x86_capability)
+ andl $0x200000,%eax
+ je nocpuid
+
/* get vendor info */
- xorl %eax, %eax # call CPUID with 0 -> return vendor ID
- .byte 0x0f, 0xa2 # CPUID
- movl %ebx,SYMBOL_NAME(x86_vendor_id) # lo 4 chars
- movl %edx,SYMBOL_NAME(x86_vendor_id)+4 # next 4 chars
- movl %ecx,SYMBOL_NAME(x86_vendor_id)+8 # last 4 chars
+ xorl %eax,%eax # call CPUID with 0 -> return vendor ID
+ cpuid
+ movl %eax,X86_CPUID # save CPUID level
+ movl %ebx,X86_VENDOR_ID # lo 4 chars
+ movl %edx,X86_VENDOR_ID+4 # next 4 chars
+ movl %ecx,X86_VENDOR_ID+8 # last 4 chars
+
+ orl %eax,%eax # do we have processor info as well?
+ je nocpuid
+
+ movl $1,%eax # Use the CPUID instruction to get CPU type
+ cpuid
+ movb %al,%cl # save reg for future use
+ andb $0x0f,%ah # mask processor family
+ movb %ah,X86
+ andb $0xf0,%al # mask model
+ shrb $4,%al
+ movb %al,X86_MODEL
+ andb $0x0f,%cl # mask mask revision
+ movb %cl,X86_MASK
+ movl %edx,X86_CAPABILITY
+
+nocpuid:
+ /*
+ * Even if we had CPUID Cyrix tries to look compatible with
+ * Intel so we have to go elsewhere for the nitty gritty.
+ */
+ cmpl $0x69727943,X86_VENDOR_ID # "Cyri[x.*]"?
+ jne is486 # maybe ...
+
+ movb $0xfe,X86_MODEL # Generic Cx486?
+ movb $0,X86_MASK
+
+ getCx86($0xc3) # Test for DEVID by writing CCR3
+ movb %al,%cl
+ movb %al,%bl
+ orb $0x80,%bl
+ setCx86($0xc3,%bl)
+ getCx86($0xc0) # dummy to change bus
+ getCx86($0xc3)
+ cmpb %al,%cl
+ je is486 # not writable == no DEVID
+
+ setCx86($0xc3,%cl) # restore CCR3
+
+ getCx86($0xff) # get DEVID in preference to any CPUID
+ movb %al,X86_MASK
+ getCx86($0xfe)
+ movb %al,X86_MODEL
+ andb $0xf0,%al # Check for 6x86(L)
+ cmp $0x30,%al
+ jnz is486
+ getCx86($0xe9) # CCR5: reset SLOP bit, so that the udelay loop
+ andb $0xfd,%al # works well on 6x86(L) CPU's.
+ movb %al,%bl
+ setCx86($0xe9,%bl)
- movl %cr0,%eax # 486+
- andl $0x80000011,%eax # Save PG,PE,ET
- orl $0x50022,%eax # set AM, WP, NE and MP
- jmp 2f
-is486: pushl %ecx # restore original EFLAGS
- popfl
- movl %cr0,%eax # 486
+is486: movl %cr0,%eax # 486 or better
andl $0x80000011,%eax # Save PG,PE,ET
orl $0x50022,%eax # set AM, WP, NE and MP
jmp 2f
+
is386: pushl %ecx # restore original EFLAGS
popfl
movl %cr0,%eax # 386
@@ -208,17 +304,11 @@
movb ready,%al # First CPU if 0
orb %al,%al
jz 4f # First CPU skip this stuff
-#ifdef GAS_KNOWS_CR4
movl %cr4,%eax # Turn on 4Mb pages
orl $16,%eax
movl %eax,%cr4
-#else
- .byte 0x0f,0x20,0xe0
- orl $16,%eax
- .byte 0x0f,0x22,0xe0
-#endif
- movl %cr3, %eax # Intel specification clarification says
- movl %eax, %cr3 # to do this. Maybe it makes a difference.
+ movl %cr3,%eax # Intel specification clarification says
+ movl %eax,%cr3 # to do this. Maybe it makes a difference.
# Who knows ?
#endif
4:
@@ -228,7 +318,7 @@
lgdt gdt_descr
lidt idt_descr
ljmp $(__KERNEL_CS),$1f
-1: movl $(__KERNEL_DS),%eax# reload all the segment registers
+1: movl $(__KERNEL_DS),%eax # reload all the segment registers
mov %ax,%ds # after changing gdt.
mov %ax,%es
mov %ax,%fs
@@ -258,7 +348,7 @@
* We depend on ET to be correct. This checks for 287/387.
*/
check_x87:
- movb $0,SYMBOL_NAME(hard_math)
+ movb $0,X86_HARD_MATH
clts
fninit
fstsw %ax
@@ -269,7 +359,7 @@
movl %eax,%cr0
ret
ALIGN
-1: movb $1,SYMBOL_NAME(hard_math)
+1: movb $1,X86_HARD_MATH
.byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
ret
@@ -366,7 +456,7 @@
.long 0x00102007
.fill 767,4,0
.long 0x00102007
- .fill 127,4,0
+ .fill 255,4,0
/*
* The page tables are initialized to only 4MB here - the final page
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov