home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / boot / head.S < prev    next >
Encoding:
Text File  |  1994-02-03  |  8.4 KB  |  355 lines

  1. /*
  2.  *  linux/boot/head.S
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  */
  6.  
  7. /*
  8.  *  head.S contains the 32-bit startup code.
  9.  */
  10.  
  11. .text
  12. .globl _idt,_gdt,
  13. .globl _swapper_pg_dir,_pg0
  14. .globl _empty_bad_page
  15. .globl _empty_bad_page_table
  16. .globl _empty_zero_page
  17. .globl _tmp_floppy_area,_floppy_track_buffer
  18.  
  19. #include <linux/tasks.h>
  20. #include <linux/segment.h>
  21.  
  22. #define CL_MAGIC_ADDR    0x90020
  23. #define CL_MAGIC    0xA33F
  24. #define CL_BASE_ADDR    0x90000
  25. #define CL_OFFSET    0x90022
  26.  
  27. /*
  28.  * swapper_pg_dir is the main page directory, address 0x00001000 (or at
  29.  * address 0x00101000 for a compressed boot).
  30.  */
  31. startup_32:
  32.     cld
  33.     movl $(KERNEL_DS),%eax
  34.     mov %ax,%ds
  35.     mov %ax,%es
  36.     mov %ax,%fs
  37.     mov %ax,%gs
  38.     lss _stack_start,%esp
  39. /*
  40.  * Clear BSS first so that there are no surprises...
  41.  */
  42.     xorl %eax,%eax
  43.     movl $__edata,%edi
  44.     movl $__end,%ecx
  45.     subl %edi,%ecx
  46.     cld
  47.     rep
  48.     stosb
  49. /*
  50.  * start system 32-bit setup. We need to re-do some of the things done
  51.  * in 16-bit mode for the "real" operations.
  52.  */
  53.     call setup_idt
  54.     xorl %eax,%eax
  55. 1:    incl %eax        # check that A20 really IS enabled
  56.     movl %eax,0x000000    # loop forever if it isn't
  57.     cmpl %eax,0x100000
  58.     je 1b
  59. /*
  60.  * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
  61.  * confuse the debugger if this code is traced.
  62.  * XXX - best to initialize before switching to protected mode.
  63.  */
  64.     pushl $0
  65.     popfl
  66. /*
  67.  * Copy bootup parameters out of the way. First 2kB of
  68.  * _empty_zero_page is for boot parameters, second 2kB
  69.  * is for the command line.
  70.  */
  71.     movl $0x90000,%esi
  72.     movl $_empty_zero_page,%edi
  73.     movl $512,%ecx
  74.     cld
  75.     rep
  76.     movsl
  77.     xorl %eax,%eax
  78.     movl $512,%ecx
  79.     rep
  80.     stosl
  81.     cmpw $(CL_MAGIC),CL_MAGIC_ADDR
  82.     jne 1f
  83.     movl $_empty_zero_page+2048,%edi
  84.     movzwl CL_OFFSET,%esi
  85.     addl $(CL_BASE_ADDR),%esi
  86.     movl $2048,%ecx
  87.     rep
  88.     movsb
  89. 1:
  90. /* check if it is 486 or 386. */
  91. /*
  92.  * XXX - this does a lot of unnecessary setup.  Alignment checks don't
  93.  * apply at our cpl of 0 and the stack ought to be aligned already, and
  94.  * we don't need to preserve eflags.
  95.  */
  96.     movl %esp,%edi        # save stack pointer
  97.     andl $0xfffffffc,%esp    # align stack to avoid AC fault
  98.     movl $3,_x86
  99.     pushfl            # push EFLAGS
  100.     popl %eax        # get EFLAGS
  101.     movl %eax,%ecx        # save original EFLAGS
  102.     xorl $0x40000,%eax    # flip AC bit in EFLAGS
  103.     pushl %eax        # copy to EFLAGS
  104.     popfl            # set EFLAGS
  105.     pushfl            # get new EFLAGS
  106.     popl %eax        # put it in eax
  107.     xorl %ecx,%eax        # change in flags
  108.     andl $0x40000,%eax    # check if AC bit changed
  109.     je is386
  110.     movl $4,_x86
  111.     movl %ecx,%eax
  112.     xorl $0x200000,%eax    # check ID flag
  113.     pushl %eax
  114.     popfl            # if we are on a straight 486DX, SX, or
  115.     pushfl            # 487SX we can't change it
  116.     popl %eax
  117.     xorl %ecx,%eax
  118.     andl $0x200000,%eax
  119.     je is486
  120. isnew:    pushl %ecx        # restore original EFLAGS
  121.     popfl
  122.     movl $1, %eax        # Use the CPUID instruction to 
  123.     .byte 0x0f, 0xa2    # check the processor type
  124.     andl $0xf00, %eax    # Set _x86 with the family
  125.     shrl $8, %eax        # returned.    
  126.     movl %eax, _x86
  127.     movl %edi,%esp        # restore esp
  128.     movl %cr0,%eax        # 486+
  129.     andl $0x80000011,%eax    # Save PG,PE,ET
  130.     orl $0x50022,%eax    # set AM, WP, NE and MP
  131.     jmp 2f
  132. is486:    pushl %ecx        # restore original EFLAGS
  133.     popfl
  134.     movl %edi,%esp        # restore esp
  135.     movl %cr0,%eax        # 486
  136.     andl $0x80000011,%eax    # Save PG,PE,ET
  137.     orl $0x50022,%eax    # set AM, WP, NE and MP
  138.     jmp 2f
  139. is386:    pushl %ecx        # restore original EFLAGS
  140.     popfl
  141.     movl %edi,%esp        # restore esp
  142.     movl %cr0,%eax        # 386
  143.     andl $0x80000011,%eax    # Save PG,PE,ET
  144.     orl $2,%eax        # set MP
  145. 2:    movl %eax,%cr0
  146.     call check_x87
  147.     call setup_paging
  148.     lgdt gdt_descr
  149.     lidt idt_descr
  150.     ljmp $(KERNEL_CS),$1f
  151. 1:    movl $(KERNEL_DS),%eax    # reload all the segment registers
  152.     mov %ax,%ds        # after changing gdt.
  153.     mov %ax,%es
  154.     mov %ax,%fs
  155.     mov %ax,%gs
  156.     lss _stack_start,%esp
  157.     xorl %eax,%eax
  158.     lldt %ax
  159.     pushl %eax        # These are the parameters to main :-)
  160.     pushl %eax
  161.     pushl %eax
  162.     cld            # gcc2 wants the direction flag cleared at all times
  163.     call _start_kernel
  164. L6:
  165.     jmp L6            # main should never return here, but
  166.                 # just in case, we know what happens.
  167.  
  168. /*
  169.  * We depend on ET to be correct. This checks for 287/387.
  170.  */
  171. check_x87:
  172.     movl $0,_hard_math
  173.     clts
  174.     fninit
  175.     fstsw %ax
  176.     cmpb $0,%al
  177.     je 1f
  178.     movl %cr0,%eax        /* no coprocessor: have to set bits */
  179.     xorl $4,%eax        /* set EM */
  180.     movl %eax,%cr0
  181.     ret
  182. .align 2
  183. 1:    movl $1,_hard_math
  184.     .byte 0xDB,0xE4        /* fsetpm for 287, ignored by 387 */
  185.     ret
  186.  
  187. /*
  188.  *  setup_idt
  189.  *
  190.  *  sets up a idt with 256 entries pointing to
  191.  *  ignore_int, interrupt gates. It doesn't actually load
  192.  *  idt - that can be done only after paging has been enabled
  193.  *  and the kernel moved to 0xC0000000. Interrupts
  194.  *  are enabled elsewhere, when we can be relatively
  195.  *  sure everything is ok.
  196.  */
  197. setup_idt:
  198.     lea ignore_int,%edx
  199.     movl $(KERNEL_CS << 16),%eax
  200.     movw %dx,%ax        /* selector = 0x0010 = cs */
  201.     movw $0x8E00,%dx    /* interrupt gate - dpl=0, present */
  202.  
  203.     lea _idt,%edi
  204.     mov $256,%ecx
  205. rp_sidt:
  206.     movl %eax,(%edi)
  207.     movl %edx,4(%edi)
  208.     addl $8,%edi
  209.     dec %ecx
  210.     jne rp_sidt
  211.     ret
  212.  
  213.  
  214. /*
  215.  * Setup_paging
  216.  *
  217.  * This routine sets up paging by setting the page bit
  218.  * in cr0. The page tables are set up, identity-mapping
  219.  * the first 4MB.  The rest are initialized later.
  220.  *
  221.  * (ref: added support for up to 32mb, 17Apr92)  -- Rik Faith
  222.  * (ref: update, 25Sept92)  -- croutons@crunchy.uucp 
  223.  * (ref: 92.10.11 - Linus Torvalds. Corrected 16M limit - no upper memory limit)
  224.  */
  225. .align 2
  226. setup_paging:
  227.     movl $1024*2,%ecx        /* 2 pages - swapper_pg_dir+1 page table */
  228.     xorl %eax,%eax
  229.     movl $_swapper_pg_dir,%edi    /* swapper_pg_dir is at 0x1000 */
  230.     cld;rep;stosl
  231. /* Identity-map the kernel in low 4MB memory for ease of transition */
  232.     movl $_pg0+7,_swapper_pg_dir        /* set present bit/user r/w */
  233. /* But the real place is at 0xC0000000 */
  234.     movl $_pg0+7,_swapper_pg_dir+3072    /* set present bit/user r/w */
  235.     movl $_pg0+4092,%edi
  236.     movl $0x03ff007,%eax        /*  4Mb - 4096 + 7 (r/w user,p) */
  237.     std
  238. 1:    stosl            /* fill the page backwards - more efficient :-) */
  239.     subl $0x1000,%eax
  240.     jge 1b
  241.     cld
  242.     movl $_swapper_pg_dir,%eax
  243.     movl %eax,%cr3            /* cr3 - page directory start */
  244.     movl %cr0,%eax
  245.     orl $0x80000000,%eax
  246.     movl %eax,%cr0        /* set paging (PG) bit */
  247.     ret            /* this also flushes the prefetch-queue */
  248.  
  249. /*
  250.  * page 0 is made non-existent, so that kernel NULL pointer references get
  251.  * caught. Thus the swapper page directory has been moved to 0x1000
  252.  *
  253.  * XXX Actually, the swapper page directory is at 0x1000 plus 1 megabyte,
  254.  * with the introduction of the compressed boot code.  Theoretically,
  255.  * the original design of overlaying the startup code with the swapper
  256.  * page directory is still possible --- it would reduce the size of the kernel
  257.  * by 2-3k.  This would be a good thing to do at some point.....
  258.  */
  259. .org 0x1000
  260. _swapper_pg_dir:
  261. /*
  262.  * The page tables are initialized to only 4MB here - the final page
  263.  * tables are set up later depending on memory size.
  264.  */
  265. .org 0x2000
  266. _pg0:
  267.  
  268. .org 0x3000
  269. _empty_bad_page:
  270.  
  271. .org 0x4000
  272. _empty_bad_page_table:
  273.  
  274. .org 0x5000
  275. _empty_zero_page:
  276.  
  277. .org 0x6000
  278. /*
  279.  * tmp_floppy_area is used by the floppy-driver when DMA cannot
  280.  * reach to a buffer-block. It needs to be aligned, so that it isn't
  281.  * on a 64kB border.
  282.  */
  283. _tmp_floppy_area:
  284.     .fill 1024,1,0
  285. /*
  286.  * floppy_track_buffer is used to buffer one track of floppy data: it
  287.  * has to be separate from the tmp_floppy area, as otherwise a single-
  288.  * sector read/write can mess it up. It can contain one full track of
  289.  * data (18*2*512 bytes).
  290.  */
  291. _floppy_track_buffer:
  292.     .fill 512*2*18,1,0
  293.  
  294. /* This is the default interrupt "handler" :-) */
  295. int_msg:
  296.     .asciz "Unknown interrupt\n"
  297. .align 2
  298. ignore_int:
  299.     cld
  300.     pushl %eax
  301.     pushl %ecx
  302.     pushl %edx
  303.     push %ds
  304.     push %es
  305.     push %fs
  306.     movl $(KERNEL_DS),%eax
  307.     mov %ax,%ds
  308.     mov %ax,%es
  309.     mov %ax,%fs
  310.     pushl $int_msg
  311.     call _printk
  312.     popl %eax
  313.     pop %fs
  314.     pop %es
  315.     pop %ds
  316.     popl %edx
  317.     popl %ecx
  318.     popl %eax
  319.     iret
  320.  
  321. /*
  322.  * The interrupt descriptor table has room for 256 idt's
  323.  */
  324. .align 4
  325. .word 0
  326. idt_descr:
  327.     .word 256*8-1        # idt contains 256 entries
  328.     .long 0xc0000000+_idt
  329.  
  330. .align 4
  331. _idt:
  332.     .fill 256,8,0        # idt is uninitialized
  333.  
  334. .align 4
  335. .word 0
  336. gdt_descr:
  337.     .word (8+2*NR_TASKS)*8-1
  338.     .long 0xc0000000+_gdt
  339.  
  340. /*
  341.  * This gdt setup gives the kernel a 1GB address space at virtual
  342.  * address 0xC0000000 - space enough for expansion, I hope.
  343.  */
  344. .align 4
  345. _gdt:
  346.     .quad 0x0000000000000000    /* NULL descriptor */
  347.     .quad 0x0000000000000000    /* not used */
  348.     .quad 0xc0c39a000000ffff    /* 0x10 kernel 1GB code at 0xC0000000 */
  349.     .quad 0xc0c392000000ffff    /* 0x18 kernel 1GB data at 0xC0000000 */
  350.     .quad 0x00cbfa000000ffff    /* 0x23 user   3GB code at 0x00000000 */
  351.     .quad 0x00cbf2000000ffff    /* 0x2b user   3GB data at 0x00000000 */
  352.     .quad 0x0000000000000000    /* not used */
  353.     .quad 0x0000000000000000    /* not used */
  354.     .fill 2*NR_TASKS,8,0        /* space for LDT's and TSS's etc */
  355.