linux-old/arch/i386/kernel/head.S
<<
>>
Prefs
   1/*
   2 *  linux/arch/i386/kernel/head.S -- the 32-bit startup code.
   3 *
   4 *  Copyright (C) 1991, 1992  Linus Torvalds
   5 *
   6 *  Enhanced CPU detection and feature setting code by Mike Jagdis
   7 *  and Martin Mares, November 1997.
   8 */
   9
  10.text
  11#include <linux/config.h>
  12#include <linux/threads.h>
  13#include <linux/linkage.h>
  14#include <asm/segment.h>
  15#include <asm/page.h>
  16#include <asm/pgtable.h>
  17#include <asm/desc.h>
  18
  19#define OLD_CL_MAGIC_ADDR       0x90020
  20#define OLD_CL_MAGIC            0xA33F
  21#define OLD_CL_BASE_ADDR        0x90000
  22#define OLD_CL_OFFSET           0x90022
  23#define NEW_CL_POINTER          0x228   /* Relative to real mode data */
  24
  25/*
  26 * References to members of the boot_cpu_data structure.
  27 */
  28
  29#define CPU_PARAMS      SYMBOL_NAME(boot_cpu_data)
  30#define X86             CPU_PARAMS+0
  31#define X86_VENDOR      CPU_PARAMS+1
  32#define X86_MODEL       CPU_PARAMS+2
  33#define X86_MASK        CPU_PARAMS+3
  34#define X86_HARD_MATH   CPU_PARAMS+6
  35#define X86_CPUID       CPU_PARAMS+8
  36#define X86_CAPABILITY  CPU_PARAMS+12
  37#define X86_VENDOR_ID   CPU_PARAMS+28
  38
  39/*
  40 * swapper_pg_dir is the main page directory, address 0x00101000
  41 *
  42 * On entry, %esi points to the real-mode code as a 32-bit pointer.
  43 */
  44startup_32:
  45/*
  46 * Set segments to known values
  47 */
  48        cld
  49        movl $(__KERNEL_DS),%eax
  50        movl %eax,%ds
  51        movl %eax,%es
  52        movl %eax,%fs
  53        movl %eax,%gs
  54#ifdef CONFIG_SMP
  55        orw %bx,%bx
  56        jz 1f
  57
  58/*
  59 *      New page tables may be in 4Mbyte page mode and may
  60 *      be using the global pages. 
  61 *
  62 *      NOTE! If we are on a 486 we may have no cr4 at all!
  63 *      So we do not try to touch it unless we really have
  64 *      some bits in it to set.  This won't work if the BSP
  65 *      implements cr4 but this AP does not -- very unlikely
  66 *      but be warned!  The same applies to the pse feature
  67 *      if not equally supported. --macro
  68 *
  69 *      NOTE! We have to correct for the fact that we're
  70 *      not yet offset PAGE_OFFSET..
  71 */
  72#define cr4_bits mmu_cr4_features-__PAGE_OFFSET
  73        cmpl $0,cr4_bits
  74        je 3f
  75        movl %cr4,%eax          # Turn on paging options (PSE,PAE,..)
  76        orl cr4_bits,%eax
  77        movl %eax,%cr4
  78        jmp 3f
  791:
  80#endif
  81/*
  82 * Initialize page tables
  83 */
  84        movl $pg0-__PAGE_OFFSET,%edi /* initialize page tables */
  85        movl $007,%eax          /* "007" doesn't mean with right to kill, but
  86                                   PRESENT+RW+USER */
  872:      stosl
  88        add $0x1000,%eax
  89        cmp $empty_zero_page-__PAGE_OFFSET,%edi
  90        jne 2b
  91
  92/*
  93 * Enable paging
  94 */
  953:
  96        movl $swapper_pg_dir-__PAGE_OFFSET,%eax
  97        movl %eax,%cr3          /* set the page table pointer.. */
  98        movl %cr0,%eax
  99        orl $0x80000000,%eax
 100        movl %eax,%cr0          /* ..and set paging (PG) bit */
 101        jmp 1f                  /* flush the prefetch-queue */
 1021:
 103        movl $1f,%eax
 104        jmp *%eax               /* make sure eip is relocated */
 1051:
 106        /* Set up the stack pointer */
 107        lss stack_start,%esp
 108
 109#ifdef CONFIG_SMP
 110        orw  %bx,%bx
 111        jz  1f                          /* Initial CPU cleans BSS */
 112        pushl $0
 113        popfl
 114        jmp checkCPUtype
 1151:
 116#endif CONFIG_SMP
 117
 118/*
 119 * Clear BSS first so that there are no surprises...
 120 * No need to cld as DF is already clear from cld above...
 121 */
 122        xorl %eax,%eax
 123        movl $ SYMBOL_NAME(__bss_start),%edi
 124        movl $ SYMBOL_NAME(_end),%ecx
 125        subl %edi,%ecx
 126        rep
 127        stosb
 128
 129/*
 130 * start system 32-bit setup. We need to re-do some of the things done
 131 * in 16-bit mode for the "real" operations.
 132 */
 133        call setup_idt
 134/*
 135 * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
 136 * confuse the debugger if this code is traced.
 137 * XXX - best to initialize before switching to protected mode.
 138 */
 139        pushl $0
 140        popfl
 141/*
 142 * Copy bootup parameters out of the way. First 2kB of
 143 * _empty_zero_page is for boot parameters, second 2kB
 144 * is for the command line.
 145 *
 146 * Note: %esi still has the pointer to the real-mode data.
 147 */
 148        movl $ SYMBOL_NAME(empty_zero_page),%edi
 149        movl $512,%ecx
 150        cld
 151        rep
 152        movsl
 153        xorl %eax,%eax
 154        movl $512,%ecx
 155        rep
 156        stosl
 157        movl SYMBOL_NAME(empty_zero_page)+NEW_CL_POINTER,%esi
 158        andl %esi,%esi
 159        jnz 2f                  # New command line protocol
 160        cmpw $(OLD_CL_MAGIC),OLD_CL_MAGIC_ADDR
 161        jne 1f
 162        movzwl OLD_CL_OFFSET,%esi
 163        addl $(OLD_CL_BASE_ADDR),%esi
 1642:
 165        movl $ SYMBOL_NAME(empty_zero_page)+2048,%edi
 166        movl $512,%ecx
 167        rep
 168        movsl
 1691:
 170checkCPUtype:
 171
 172        movl $-1,X86_CPUID              #  -1 for no CPUID initially
 173
 174/* check if it is 486 or 386. */
 175/*
 176 * XXX - this does a lot of unnecessary setup.  Alignment checks don't
 177 * apply at our cpl of 0 and the stack ought to be aligned already, and
 178 * we don't need to preserve eflags.
 179 */
 180
 181        movb $3,X86             # at least 386
 182        pushfl                  # push EFLAGS
 183        popl %eax               # get EFLAGS
 184        movl %eax,%ecx          # save original EFLAGS
 185        xorl $0x40000,%eax      # flip AC bit in EFLAGS
 186        pushl %eax              # copy to EFLAGS
 187        popfl                   # set EFLAGS
 188        pushfl                  # get new EFLAGS
 189        popl %eax               # put it in eax
 190        xorl %ecx,%eax          # change in flags
 191        andl $0x40000,%eax      # check if AC bit changed
 192        je is386
 193
 194        movb $4,X86             # at least 486
 195        movl %ecx,%eax
 196        xorl $0x200000,%eax     # check ID flag
 197        pushl %eax
 198        popfl                   # if we are on a straight 486DX, SX, or
 199        pushfl                  # 487SX we can't change it
 200        popl %eax
 201        xorl %ecx,%eax
 202        pushl %ecx              # restore original EFLAGS
 203        popfl
 204        andl $0x200000,%eax
 205        je is486
 206
 207        /* get vendor info */
 208        xorl %eax,%eax                  # call CPUID with 0 -> return vendor ID
 209        cpuid
 210        movl %eax,X86_CPUID             # save CPUID level
 211        movl %ebx,X86_VENDOR_ID         # lo 4 chars
 212        movl %edx,X86_VENDOR_ID+4       # next 4 chars
 213        movl %ecx,X86_VENDOR_ID+8       # last 4 chars
 214
 215        orl %eax,%eax                   # do we have processor info as well?
 216        je is486
 217
 218        movl $1,%eax            # Use the CPUID instruction to get CPU type
 219        cpuid
 220        movb %al,%cl            # save reg for future use
 221        andb $0x0f,%ah          # mask processor family
 222        movb %ah,X86
 223        andb $0xf0,%al          # mask model
 224        shrb $4,%al
 225        movb %al,X86_MODEL
 226        andb $0x0f,%cl          # mask mask revision
 227        movb %cl,X86_MASK
 228        movl %edx,X86_CAPABILITY
 229
 230is486:
 231        movl %cr0,%eax          # 486 or better
 232        andl $0x80000011,%eax   # Save PG,PE,ET
 233        orl $0x50022,%eax       # set AM, WP, NE and MP
 234        jmp 2f
 235
 236is386:  pushl %ecx              # restore original EFLAGS
 237        popfl
 238        movl %cr0,%eax          # 386
 239        andl $0x80000011,%eax   # Save PG,PE,ET
 240        orl $2,%eax             # set MP
 2412:      movl %eax,%cr0
 242        call check_x87
 243        incb ready
 244        lgdt gdt_descr
 245        lidt idt_descr
 246        ljmp $(__KERNEL_CS),$1f
 2471:      movl $(__KERNEL_DS),%eax        # reload all the segment registers
 248        movl %eax,%ds           # after changing gdt.
 249        movl %eax,%es
 250        movl %eax,%fs
 251        movl %eax,%gs
 252#ifdef CONFIG_SMP
 253        movl $(__KERNEL_DS), %eax
 254        movl %eax,%ss           # Reload the stack pointer (segment only)
 255#else
 256        lss stack_start,%esp    # Load processor stack
 257#endif
 258        xorl %eax,%eax
 259        lldt %ax
 260        cld                     # gcc2 wants the direction flag cleared at all times
 261#ifdef CONFIG_SMP
 262        movb ready, %cl 
 263        cmpb $1,%cl
 264        je 1f                   # the first CPU calls start_kernel
 265                                # all other CPUs call initialize_secondary
 266        call SYMBOL_NAME(initialize_secondary)
 267        jmp L6
 2681:
 269#endif
 270        call SYMBOL_NAME(start_kernel)
 271L6:
 272        jmp L6                  # main should never return here, but
 273                                # just in case, we know what happens.
 274
 275ready:  .byte 0
 276
 277/*
 278 * We depend on ET to be correct. This checks for 287/387.
 279 */
 280check_x87:
 281        movb $0,X86_HARD_MATH
 282        clts
 283        fninit
 284        fstsw %ax
 285        cmpb $0,%al
 286        je 1f
 287        movl %cr0,%eax          /* no coprocessor: have to set bits */
 288        xorl $4,%eax            /* set EM */
 289        movl %eax,%cr0
 290        ret
 291        ALIGN
 2921:      movb $1,X86_HARD_MATH
 293        .byte 0xDB,0xE4         /* fsetpm for 287, ignored by 387 */
 294        ret
 295
 296/*
 297 *  setup_idt
 298 *
 299 *  sets up a idt with 256 entries pointing to
 300 *  ignore_int, interrupt gates. It doesn't actually load
 301 *  idt - that can be done only after paging has been enabled
 302 *  and the kernel moved to PAGE_OFFSET. Interrupts
 303 *  are enabled elsewhere, when we can be relatively
 304 *  sure everything is ok.
 305 */
 306setup_idt:
 307        lea ignore_int,%edx
 308        movl $(__KERNEL_CS << 16),%eax
 309        movw %dx,%ax            /* selector = 0x0010 = cs */
 310        movw $0x8E00,%dx        /* interrupt gate - dpl=0, present */
 311
 312        lea SYMBOL_NAME(idt_table),%edi
 313        mov $256,%ecx
 314rp_sidt:
 315        movl %eax,(%edi)
 316        movl %edx,4(%edi)
 317        addl $8,%edi
 318        dec %ecx
 319        jne rp_sidt
 320        ret
 321
 322ENTRY(stack_start)
 323        .long SYMBOL_NAME(init_task_union)+8192
 324        .long __KERNEL_DS
 325
 326/* This is the default interrupt "handler" :-) */
 327int_msg:
 328        .asciz "Unknown interrupt\n"
 329        ALIGN
 330ignore_int:
 331        cld
 332        pushl %eax
 333        pushl %ecx
 334        pushl %edx
 335        pushl %es
 336        pushl %ds
 337        movl $(__KERNEL_DS),%eax
 338        movl %eax,%ds
 339        movl %eax,%es
 340        pushl $int_msg
 341        call SYMBOL_NAME(printk)
 342        popl %eax
 343        popl %ds
 344        popl %es
 345        popl %edx
 346        popl %ecx
 347        popl %eax
 348        iret
 349
 350/*
 351 * The interrupt descriptor table has room for 256 idt's,
 352 * the global descriptor table is dependent on the number
 353 * of tasks we can have..
 354 */
 355#define IDT_ENTRIES     256
 356#define GDT_ENTRIES     (__TSS(NR_CPUS))
 357
 358
 359.globl SYMBOL_NAME(idt)
 360.globl SYMBOL_NAME(gdt)
 361
 362        ALIGN
 363        .word 0
 364idt_descr:
 365        .word IDT_ENTRIES*8-1           # idt contains 256 entries
 366SYMBOL_NAME(idt):
 367        .long SYMBOL_NAME(idt_table)
 368
 369        .word 0
 370gdt_descr:
 371        .word GDT_ENTRIES*8-1
 372SYMBOL_NAME(gdt):
 373        .long SYMBOL_NAME(gdt_table)
 374
 375/*
 376 * This is initialized to create an identity-mapping at 0-8M (for bootup
 377 * purposes) and another mapping of the 0-8M area at virtual address
 378 * PAGE_OFFSET.
 379 */
 380.org 0x1000
 381ENTRY(swapper_pg_dir)
 382        .long 0x00102007
 383        .long 0x00103007
 384        .fill BOOT_USER_PGD_PTRS-2,4,0
 385        /* default: 766 entries */
 386        .long 0x00102007
 387        .long 0x00103007
 388        /* default: 254 entries */
 389        .fill BOOT_KERNEL_PGD_PTRS-2,4,0
 390
 391/*
 392 * The page tables are initialized to only 8MB here - the final page
 393 * tables are set up later depending on memory size.
 394 */
 395.org 0x2000
 396ENTRY(pg0)
 397
 398.org 0x3000
 399ENTRY(pg1)
 400
 401/*
 402 * empty_zero_page must immediately follow the page tables ! (The
 403 * initialization loop counts until empty_zero_page)
 404 */
 405
 406.org 0x4000
 407ENTRY(empty_zero_page)
 408
 409.org 0x5000
 410
 411/*
 412 * Real beginning of normal "text" segment
 413 */
 414ENTRY(stext)
 415ENTRY(_stext)
 416
 417/*
 418 * This starts the data section. Note that the above is all
 419 * in the text section because it has alignment requirements
 420 * that we cannot fulfill any other way.
 421 */
 422.data
 423
 424ALIGN
 425/*
 426 * This contains typically 140 quadwords, depending on NR_CPUS.
 427 *
 428 * NOTE! Make sure the gdt descriptor in head.S matches this if you
 429 * change anything.
 430 */
 431ENTRY(gdt_table)
 432        .quad 0x0000000000000000        /* NULL descriptor */
 433        .quad 0x0000000000000000        /* not used */
 434        .quad 0x00cf9a000000ffff        /* 0x10 kernel 4GB code at 0x00000000 */
 435        .quad 0x00cf92000000ffff        /* 0x18 kernel 4GB data at 0x00000000 */
 436        .quad 0x00cffa000000ffff        /* 0x23 user   4GB code at 0x00000000 */
 437        .quad 0x00cff2000000ffff        /* 0x2b user   4GB data at 0x00000000 */
 438        .quad 0x0000000000000000        /* not used */
 439        .quad 0x0000000000000000        /* not used */
 440        /*
 441         * The APM segments have byte granularity and their bases
 442         * and limits are set at run time.
 443         */
 444        .quad 0x0040920000000000        /* 0x40 APM set up for bad BIOS's */
 445        .quad 0x00409a0000000000        /* 0x48 APM CS    code */
 446        .quad 0x00009a0000000000        /* 0x50 APM CS 16 code (16 bit) */
 447        .quad 0x0040920000000000        /* 0x58 APM DS    data */
 448        .fill NR_CPUS*4,8,0             /* space for TSS's and LDT's */
 449
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.