home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / arch / i386 / kernel / head.S < prev    next >
Encoding:
Text File  |  1995-01-02  |  8.6 KB  |  363 lines

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