fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / i386 / kernel / head.S
index ea1ef3a..edef508 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 .text
-#include <linux/config.h>
 #include <linux/threads.h>
 #include <linux/linkage.h>
 #include <asm/segment.h>
@@ -17,7 +16,7 @@
 #include <asm/desc.h>
 #include <asm/cache.h>
 #include <asm/thread_info.h>
-#include <asm/asm_offsets.h>
+#include <asm/asm-offsets.h>
 #include <asm/setup.h>
 
 /*
  */
 ENTRY(startup_32)
 
+#ifdef CONFIG_PARAVIRT
+        movl %cs, %eax
+        testl $0x3, %eax
+        jnz startup_paravirt
+#endif
+
 /*
  * Set segments to known values.
  */
@@ -77,6 +82,32 @@ ENTRY(startup_32)
        subl %edi,%ecx
        shrl $2,%ecx
        rep ; stosl
+/*
+ * Copy bootup parameters out of the way.
+ * Note: %esi still has the pointer to the real-mode data.
+ * With the kexec as boot loader, parameter segment might be loaded beyond
+ * kernel image and might not even be addressable by early boot page tables.
+ * (kexec on panic case). Hence copy out the parameters before initializing
+ * page tables.
+ */
+       movl $(boot_params - __PAGE_OFFSET),%edi
+       movl $(PARAM_SIZE/4),%ecx
+       cld
+       rep
+       movsl
+       movl boot_params - __PAGE_OFFSET + NEW_CL_POINTER,%esi
+       andl %esi,%esi
+       jnz 2f                  # New command line protocol
+       cmpw $(OLD_CL_MAGIC),OLD_CL_MAGIC_ADDR
+       jne 1f
+       movzwl OLD_CL_OFFSET,%esi
+       addl $(OLD_CL_BASE_ADDR),%esi
+2:
+       movl $(saved_command_line - __PAGE_OFFSET),%edi
+       movl $(COMMAND_LINE_SIZE/4),%ecx
+       rep
+       movsl
+1:
 
 /*
  * Initialize page tables.  This creates a PDE and a set of page
@@ -214,28 +245,6 @@ ENTRY(startup_32_smp)
  */
        call setup_idt
 
-/*
- * Copy bootup parameters out of the way.
- * Note: %esi still has the pointer to the real-mode data.
- */
-       movl $boot_params,%edi
-       movl $(PARAM_SIZE/4),%ecx
-       cld
-       rep
-       movsl
-       movl boot_params+NEW_CL_POINTER,%esi
-       andl %esi,%esi
-       jnz 2f                  # New command line protocol
-       cmpw $(OLD_CL_MAGIC),OLD_CL_MAGIC_ADDR
-       jne 1f
-       movzwl OLD_CL_OFFSET,%esi
-       addl $(OLD_CL_BASE_ADDR),%esi
-2:
-       movl $saved_command_line,%edi
-       movl $(COMMAND_LINE_SIZE/4),%ecx
-       rep
-       movsl
-1:
 checkCPUtype:
 
        movl $-1,X86_CPUID              #  -1 for no CPUID initially
@@ -299,7 +308,7 @@ is386:      movl $2,%ecx            # set MP
        movl %eax,%cr0
 
        call check_x87
-       incb ready
+       call setup_pda
        lgdt cpu_gdt_descr
        lidt idt_descr
        ljmp $(__KERNEL_CS),$1f
@@ -310,24 +319,22 @@ is386:    movl $2,%ecx            # set MP
        movl %eax,%ds
        movl %eax,%es
 
-       xorl %eax,%eax                  # Clear FS/GS and LDT
+       xorl %eax,%eax                  # Clear FS and LDT
        movl %eax,%fs
-       movl %eax,%gs
        lldt %ax
+
+       movl $(__KERNEL_PDA),%eax
+       mov  %eax,%gs
+
        cld                     # gcc2 wants the direction flag cleared at all times
+       pushl $0                # fake return address for unwinder
 #ifdef CONFIG_SMP
-       movb ready, %cl 
-       cmpb $1,%cl
-       je 1f                   # the first CPU calls start_kernel
-                               # all other CPUs call initialize_secondary
-       call initialize_secondary
-       jmp L6
-1:
+       movb ready, %cl
+       movb $1, ready
+       cmpb $0,%cl             # the first CPU calls start_kernel
+       jne initialize_secondary # all other CPUs call initialize_secondary
 #endif /* CONFIG_SMP */
-       call start_kernel
-L6:
-       jmp L6                  # main should never return here, but
-                               # just in case, we know what happens.
+       jmp start_kernel
 
 /*
  * We depend on ET to be correct. This checks for 287/387.
@@ -348,6 +355,23 @@ check_x87:
        .byte 0xDB,0xE4         /* fsetpm for 287, ignored by 387 */
        ret
 
+/*
+ * Point the GDT at this CPU's PDA.  On boot this will be
+ * cpu_gdt_table and boot_pda; for secondary CPUs, these will be
+ * that CPU's GDT and PDA.
+ */
+setup_pda:
+       /* get the PDA pointer */
+       movl start_pda, %eax
+
+       /* slot the PDA address into the GDT */
+       mov cpu_gdt_descr+2, %ecx
+       mov %ax, (__KERNEL_PDA+0+2)(%ecx)               /* base & 0x0000ffff */
+       shr $16, %eax
+       mov %al, (__KERNEL_PDA+4+0)(%ecx)               /* base & 0x00ff0000 */
+       mov %ah, (__KERNEL_PDA+4+3)(%ecx)               /* base & 0xff000000 */
+       ret
+
 /*
  *  setup_idt
  *
@@ -374,12 +398,70 @@ rp_sidt:
        addl $8,%edi
        dec %ecx
        jne rp_sidt
+
+.macro set_early_handler handler,trapno
+       lea \handler,%edx
+       movl $(__KERNEL_CS << 16),%eax
+       movw %dx,%ax
+       movw $0x8E00,%dx        /* interrupt gate - dpl=0, present */
+       lea idt_table,%edi
+       movl %eax,8*\trapno(%edi)
+       movl %edx,8*\trapno+4(%edi)
+.endm
+
+       set_early_handler handler=early_divide_err,trapno=0
+       set_early_handler handler=early_illegal_opcode,trapno=6
+       set_early_handler handler=early_protection_fault,trapno=13
+       set_early_handler handler=early_page_fault,trapno=14
+
        ret
 
+early_divide_err:
+       xor %edx,%edx
+       pushl $0        /* fake errcode */
+       jmp early_fault
+
+early_illegal_opcode:
+       movl $6,%edx
+       pushl $0        /* fake errcode */
+       jmp early_fault
+
+early_protection_fault:
+       movl $13,%edx
+       jmp early_fault
+
+early_page_fault:
+       movl $14,%edx
+       jmp early_fault
+
+early_fault:
+       cld
+#ifdef CONFIG_PRINTK
+       movl $(__KERNEL_DS),%eax
+       movl %eax,%ds
+       movl %eax,%es
+       cmpl $2,early_recursion_flag
+       je hlt_loop
+       incl early_recursion_flag
+       movl %cr2,%eax
+       pushl %eax
+       pushl %edx              /* trapno */
+       pushl $fault_msg
+#ifdef CONFIG_EARLY_PRINTK
+       call early_printk
+#else
+       call printk
+#endif
+#endif
+hlt_loop:
+       hlt
+       jmp hlt_loop
+
 /* This is the default interrupt "handler" :-) */
        ALIGN
 ignore_int:
        cld
+#ifdef CONFIG_PRINTK
        pushl %eax
        pushl %ecx
        pushl %edx
@@ -388,20 +470,55 @@ ignore_int:
        movl $(__KERNEL_DS),%eax
        movl %eax,%ds
        movl %eax,%es
+       cmpl $2,early_recursion_flag
+       je hlt_loop
+       incl early_recursion_flag
        pushl 16(%esp)
        pushl 24(%esp)
        pushl 32(%esp)
        pushl 40(%esp)
        pushl $int_msg
+#ifdef CONFIG_EARLY_PRINTK
+       call early_printk
+#else
        call printk
+#endif
        addl $(5*4),%esp
        popl %ds
        popl %es
        popl %edx
        popl %ecx
        popl %eax
+#endif
        iret
 
+#ifdef CONFIG_PARAVIRT
+startup_paravirt:
+       cld
+       movl $(init_thread_union+THREAD_SIZE),%esp
+
+       /* We take pains to preserve all the regs. */
+       pushl   %edx
+       pushl   %ecx
+       pushl   %eax
+
+       /* paravirt.o is last in link, and that probe fn never returns */
+       pushl   $__start_paravirtprobe
+1:
+       movl    0(%esp), %eax
+       pushl   (%eax)
+       movl    8(%esp), %eax
+       call    *(%esp)
+       popl    %eax
+
+       movl    4(%esp), %eax
+       movl    8(%esp), %ecx
+       movl    12(%esp), %edx
+
+       addl    $4, (%esp)
+       jmp     1b
+#endif
+
 /*
  * Real beginning of normal "text" segment
  */
@@ -421,6 +538,8 @@ ENTRY(empty_zero_page)
  * This starts the data section.
  */
 .data
+ENTRY(start_pda)
+       .long boot_pda
 
 ENTRY(stack_start)
        .long init_thread_union+THREAD_SIZE
@@ -428,9 +547,16 @@ ENTRY(stack_start)
 
 ready: .byte 0
 
+early_recursion_flag:
+       .long 0
+
 int_msg:
        .asciz "Unknown interrupt or fault at EIP %p %p %p\n"
 
+fault_msg:
+       .ascii "Int %d: CR2 %p  err %p  EIP %p  CS %p  flags %p\n"
+       .asciz "Stack: %p %p %p %p %p %p %p %p\n"
+
 /*
  * The IDT and GDT 'descriptors' are a strange 48-bit object
  * only used by the lidt and lgdt instructions. They are not
@@ -440,7 +566,6 @@ int_msg:
 
 .globl boot_gdt_descr
 .globl idt_descr
-.globl cpu_gdt_descr
 
        ALIGN
 # early boot GDT descriptor (must use 1:1 address mapping)
@@ -456,12 +581,10 @@ idt_descr:
 
 # boot GDT descriptor (later on used by CPU#0):
        .word 0                         # 32 bit align gdt_desc.address
-cpu_gdt_descr:
+ENTRY(cpu_gdt_descr)
        .word GDT_ENTRIES*8-1
        .long cpu_gdt_table
 
-       .fill NR_CPUS-1,8,0             # space for the other GDT descriptors
-
 /*
  * The boot_gdt_table must mirror the equivalent in setup.S and is
  * used only for booting.
@@ -475,7 +598,7 @@ ENTRY(boot_gdt_table)
 /*
  * The Global Descriptor Table contains 28 quadwords, per-CPU.
  */
-       .align PAGE_SIZE_asm
+       .align L1_CACHE_BYTES
 ENTRY(cpu_gdt_table)
        .quad 0x0000000000000000        /* NULL descriptor */
        .quad 0x0000000000000000        /* 0x0b reserved */
@@ -498,22 +621,27 @@ ENTRY(cpu_gdt_table)
        .quad 0x0000000000000000        /* 0x80 TSS descriptor */
        .quad 0x0000000000000000        /* 0x88 LDT descriptor */
 
-       /* Segments used for calling PnP BIOS */
-       .quad 0x00c09a0000000000        /* 0x90 32-bit code */
-       .quad 0x00809a0000000000        /* 0x98 16-bit code */
-       .quad 0x0080920000000000        /* 0xa0 16-bit data */
-       .quad 0x0080920000000000        /* 0xa8 16-bit data */
-       .quad 0x0080920000000000        /* 0xb0 16-bit data */
+       /*
+        * Segments used for calling PnP BIOS have byte granularity.
+        * They code segments and data segments have fixed 64k limits,
+        * the transfer segment sizes are set at run time.
+        */
+       .quad 0x00409a000000ffff        /* 0x90 32-bit code */
+       .quad 0x00009a000000ffff        /* 0x98 16-bit code */
+       .quad 0x000092000000ffff        /* 0xa0 16-bit data */
+       .quad 0x0000920000000000        /* 0xa8 16-bit data */
+       .quad 0x0000920000000000        /* 0xb0 16-bit data */
+
        /*
         * The APM segments have byte granularity and their bases
-        * and limits are set at run time.
+        * are set at run time.  All have 64k limits.
         */
-       .quad 0x00409a0000000000        /* 0xb8 APM CS    code */
-       .quad 0x00009a0000000000        /* 0xc0 APM CS 16 code (16 bit) */
-       .quad 0x0040920000000000        /* 0xc8 APM DS    data */
+       .quad 0x00409a000000ffff        /* 0xb8 APM CS    code */
+       .quad 0x00009a000000ffff        /* 0xc0 APM CS 16 code (16 bit) */
+       .quad 0x004092000000ffff        /* 0xc8 APM DS    data */
 
-       .quad 0x0000000000000000        /* 0xd0 - unused */
-       .quad 0x0000000000000000        /* 0xd8 - unused */
+       .quad 0x00c0920000000000        /* 0xd0 - ESPFIX SS */
+       .quad 0x00cf92000000ffff        /* 0xd8 - PDA */
        .quad 0x0000000000000000        /* 0xe0 - unused */
        .quad 0x0000000000000000        /* 0xe8 - unused */
        .quad 0x0000000000000000        /* 0xf0 - unused */