Annotation of linux/boot/head.S, revision 1.1.1.1

1.1       root        1: /*
                      2:  *  linux/boot/head.s
                      3:  *
                      4:  *  Copyright (C) 1991, 1992  Linus Torvalds
                      5:  */
                      6: 
                      7: #if (MAX_MEGABYTES != 16) && (MAX_MEGABYTES != 32)
                      8: #error "MAX_MEGABYTES must be 16 or 32"
                      9: #endif
                     10: 
                     11: /*
                     12:  *  head.s contains the 32-bit startup code.
                     13:  *
                     14:  * NOTE!!! Startup happens at absolute address 0x00000000, which is also where
                     15:  * the page directory will exist. The startup code will be overwritten by
                     16:  * the page directory.
                     17:  */
                     18: .text
                     19: .globl _idt,_gdt,_swapper_pg_dir,_tmp_floppy_area,_floppy_track_buffer
                     20: /*
                     21:  * swapper_pg_dir is the main page directory, address 0x00000000
                     22:  */
                     23: _swapper_pg_dir:
                     24: startup_32:
                     25:        cld
                     26:        movl $0x10,%eax
                     27:        mov %ax,%ds
                     28:        mov %ax,%es
                     29:        mov %ax,%fs
                     30:        mov %ax,%gs
                     31:        lss _stack_start,%esp
                     32:        call setup_idt
                     33:        xorl %eax,%eax
                     34: 1:     incl %eax               # check that A20 really IS enabled
                     35:        movl %eax,0x000000      # loop forever if it isn't
                     36:        cmpl %eax,0x100000
                     37:        je 1b
                     38: /* check if it is 486 or 386. */
                     39:        movl %esp,%edi          # save stack pointer
                     40:        andl $0xfffffffc,%esp   # align stack to avoid AC fault
                     41:        pushfl                  # push EFLAGS
                     42:        popl %eax               # get EFLAGS
                     43:        movl %eax,%ecx          # save original EFLAGS
                     44:        xorl $0x40000,%eax      # flip AC bit in EFLAGS
                     45:        pushl %eax              # copy to EFLAGS
                     46:        popfl                   # set EFLAGS
                     47:        pushfl                  # get new EFLAGS
                     48:        popl %eax               # put it in eax
                     49:        xorl %ecx,%eax          # check if AC bit is changed. zero is 486.
                     50:        jz 1f                   # 486
                     51:        pushl %ecx              # restore original EFLAGS
                     52:        popfl
                     53:        movl %edi,%esp          # restore esp
                     54:        movl %cr0,%eax          # 386
                     55:        andl $0x80000011,%eax   # Save PG,PE,ET
                     56:        orl $2,%eax             # set MP
                     57:        jmp 2f  
                     58: /*
                     59:  * NOTE! 486 should set bit 16, to check for write-protect in supervisor
                     60:  * mode. Then it would be unnecessary with the "verify_area()"-calls.
                     61:  * 486 users probably want to set the NE (#5) bit also, so as to use
                     62:  * int 16 for math errors.
                     63:  */
                     64: 1:     pushl %ecx              # restore original EFLAGS
                     65:        popfl
                     66:        movl %edi,%esp          # restore esp
                     67:        movl %cr0,%eax          # 486
                     68:        andl $0x80000011,%eax   # Save PG,PE,ET
                     69:        orl $0x10022,%eax       # set NE and MP
                     70: 2:     movl %eax,%cr0
                     71:        call check_x87
                     72:        jmp after_page_tables
                     73: 
                     74: /*
                     75:  * We depend on ET to be correct. This checks for 287/387.
                     76:  */
                     77: check_x87:
                     78:        fninit
                     79:        fstsw %ax
                     80:        cmpb $0,%al
                     81:        je 1f
                     82:        movl %cr0,%eax          /* no coprocessor: have to set bits */
                     83:        xorl $6,%eax            /* reset MP, set EM */
                     84:        movl %eax,%cr0
                     85:        ret
                     86: .align 2
                     87: 1:     .byte 0xDB,0xE4         /* fsetpm for 287, ignored by 387 */
                     88:        ret
                     89: 
                     90: /*
                     91:  *  setup_idt
                     92:  *
                     93:  *  sets up a idt with 256 entries pointing to
                     94:  *  ignore_int, interrupt gates. It doesn't actually load
                     95:  *  idt - that can be done only after paging has been enabled
                     96:  *  and the kernel moved to 0xC0000000. Interrupts
                     97:  *  are enabled elsewhere, when we can be relatively
                     98:  *  sure everything is ok. This routine will be over-
                     99:  *  written by the page tables.
                    100:  */
                    101: setup_idt:
                    102:        lea ignore_int,%edx
                    103:        movl $0x00080000,%eax
                    104:        movw %dx,%ax            /* selector = 0x0008 = cs */
                    105:        movw $0x8E00,%dx        /* interrupt gate - dpl=0, present */
                    106: 
                    107:        lea _idt,%edi
                    108:        mov $256,%ecx
                    109: rp_sidt:
                    110:        movl %eax,(%edi)
                    111:        movl %edx,4(%edi)
                    112:        addl $8,%edi
                    113:        dec %ecx
                    114:        jne rp_sidt
                    115:        ret
                    116: 
                    117: /*
                    118:  * I put the kernel page tables right after the page directory,
                    119:  * using 4 of them to span 16 Mb of physical memory. People with
                    120:  * more than 16MB will have to expand this.
                    121:  * When MAX_MEGABYTES == 32, this is set up for a maximum of 32 MB
                    122:  * (ref: 17Apr92)  (redone for 0.97 kernel changes, 1Aug92, ref)
                    123:  */
                    124: .org 0x1000
                    125: pg0:
                    126: 
                    127: .org 0x2000
                    128: pg1:
                    129: 
                    130: .org 0x3000
                    131: pg2:
                    132: 
                    133: .org 0x4000
                    134: pg3:
                    135: 
                    136: .org 0x5000
                    137: #if MAX_MEGABYTES == 32
                    138: pg4:
                    139: 
                    140: .org 0x6000
                    141: pg5:
                    142: 
                    143: .org 0x7000
                    144: pg6:
                    145: 
                    146: .org 0x8000
                    147: pg7:
                    148: 
                    149: .org 0x9000
                    150: #endif
                    151: /*
                    152:  * empty_bad_page is a bogus page that will be used when out of memory,
                    153:  * so that a process isn't accidentally killed due to a page fault when
                    154:  * it is running in kernel mode..
                    155:  */
                    156: .globl _empty_bad_page
                    157: _empty_bad_page:
                    158: 
                    159: #if MAX_MEGABYTES == 32
                    160: .org 0xa000
                    161: #else
                    162: .org 0x6000
                    163: #endif
                    164: /*
                    165:  * empty_bad_page_table is similar to the above, but is used when the
                    166:  * system needs a bogus page-table
                    167:  */
                    168: .globl _empty_bad_page_table
                    169: _empty_bad_page_table:
                    170: 
                    171: #if MAX_MEGABYTES == 32
                    172: .org 0xb000
                    173: #else
                    174: .org 0x7000
                    175: #endif
                    176: /*
                    177:  * tmp_floppy_area is used by the floppy-driver when DMA cannot
                    178:  * reach to a buffer-block. It needs to be aligned, so that it isn't
                    179:  * on a 64kB border.
                    180:  */
                    181: _tmp_floppy_area:
                    182:        .fill 1024,1,0
                    183: /*
                    184:  * floppy_track_buffer is used to buffer one track of floppy data: it
                    185:  * has to be separate from the tmp_floppy area, as otherwise a single-
                    186:  * sector read/write can mess it up. It can contain one full track of
                    187:  * data (18*2*512 bytes).
                    188:  */
                    189: _floppy_track_buffer:
                    190:        .fill 512*2*18,1,0
                    191: 
                    192: after_page_tables:
                    193:        call setup_paging
                    194:        lgdt gdt_descr
                    195:        lidt idt_descr
                    196:        ljmp $0x08,$1f
                    197: 1:     movl $0x10,%eax         # reload all the segment registers
                    198:        mov %ax,%ds             # after changing gdt.
                    199:        mov %ax,%es
                    200:        mov %ax,%fs
                    201:        mov %ax,%gs
                    202:        lss _stack_start,%esp
                    203:        pushl $0                # These are the parameters to main :-)
                    204:        pushl $0
                    205:        pushl $0
                    206:        cld                     # gcc2 wants the direction flag cleared at all times
                    207:        call _start_kernel
                    208: L6:
                    209:        jmp L6                  # main should never return here, but
                    210:                                # just in case, we know what happens.
                    211: 
                    212: /* This is the default interrupt "handler" :-) */
                    213: int_msg:
                    214:        .asciz "Unknown interrupt\n\r"
                    215: .align 2
                    216: ignore_int:
                    217:        cld
                    218:        pushl %eax
                    219:        pushl %ecx
                    220:        pushl %edx
                    221:        push %ds
                    222:        push %es
                    223:        push %fs
                    224:        movl $0x10,%eax
                    225:        mov %ax,%ds
                    226:        mov %ax,%es
                    227:        mov %ax,%fs
                    228:        pushl $int_msg
                    229:        call _printk
                    230:        popl %eax
                    231:        pop %fs
                    232:        pop %es
                    233:        pop %ds
                    234:        popl %edx
                    235:        popl %ecx
                    236:        popl %eax
                    237:        iret
                    238: 
                    239: 
                    240: /*
                    241:  * Setup_paging
                    242:  *
                    243:  * This routine sets up paging by setting the page bit
                    244:  * in cr0. The page tables are set up, identity-mapping
                    245:  * the first 16MB. The pager assumes that no illegal
                    246:  * addresses are produced (ie >4Mb on a 4Mb machine).
                    247:  *
                    248:  * NOTE! Although all physical memory should be identity
                    249:  * mapped by this routine, only the kernel page functions
                    250:  * use the >1Mb addresses directly. All "normal" functions
                    251:  * use just the lower 1Mb, or the local data space, which
                    252:  * will be mapped to some other place - mm keeps track of
                    253:  * that.
                    254:  *
                    255:  * For those with more memory than 16 Mb - tough luck. I've
                    256:  * not got it, why should you :-) The source is here. Change
                    257:  * it. (Seriously - it shouldn't be too difficult. Mostly
                    258:  * change some constants etc. I left it at 16Mb, as my machine
                    259:  * even cannot be extended past that (ok, but it was cheap :-)
                    260:  * I've tried to show which constants to change by having
                    261:  * some kind of marker at them (search for "16Mb"), but I
                    262:  * won't guarantee that's all :-( )
                    263:  *
                    264:  * (ref: added support for up to 32mb, 17Apr92)  -- Rik Faith
                    265:  * (ref: update, 25Sept92)  -- [email protected] 
                    266:  */
                    267: .align 2
                    268: setup_paging:
                    269: #if MAXMEGABYTES == 32
                    270:        movl $1024*9,%ecx               /* 9 pages - swapper_pg_dir+8 page tables */
                    271: #else 
                    272:        movl $1024*5,%ecx               /* 5 pages - swapper_pg_dir+4 page tables */
                    273: #endif
                    274:        xorl %eax,%eax
                    275:        xorl %edi,%edi                  /* swapper_pg_dir is at 0x000 */
                    276:        cld;rep;stosl
                    277: /* Identity-map the kernel in low 4MB memory for ease of transition */
                    278:        movl $pg0+7,_swapper_pg_dir             /* set present bit/user r/w */
                    279: /* But the real place is at 0xC0000000 */
                    280:        movl $pg0+7,_swapper_pg_dir+3072        /* set present bit/user r/w */
                    281:        movl $pg1+7,_swapper_pg_dir+3076        /*  --------- " " --------- */
                    282:        movl $pg2+7,_swapper_pg_dir+3080        /*  --------- " " --------- */
                    283:        movl $pg3+7,_swapper_pg_dir+3084        /*  --------- " " --------- */
                    284: #if MAX_MEGABYTES == 32
                    285:        movl $pg4+7,_swapper_pg_dir+3088        /*  --------- " " --------- */
                    286:        movl $pg5+7,_swapper_pg_dir+3092        /*  --------- " " --------- */
                    287:        movl $pg6+7,_swapper_pg_dir+3096        /*  --------- " " --------- */
                    288:        movl $pg7+7,_swapper_pg_dir+3100        /*  --------- " " --------- */
                    289: 
                    290:        movl $pg7+4092,%edi
                    291:        movl $0x1fff007,%eax            /*  32Mb - 4096 + 7 (r/w user,p) */
                    292: #else 
                    293:        movl $pg3+4092,%edi
                    294:        movl $0x0fff007,%eax            /*  16Mb - 4096 + 7 (r/w user,p) */
                    295: #endif
                    296:        std
                    297: 1:     stosl                   /* fill pages backwards - more efficient :-) */
                    298:        subl $0x1000,%eax
                    299:        jge 1b
                    300:        cld
                    301:        xorl %eax,%eax          /* swapper_pg_dir is at 0x0000 */
                    302:        movl %eax,%cr3          /* cr3 - page directory start */
                    303:        movl %cr0,%eax
                    304:        orl $0x80000000,%eax
                    305:        movl %eax,%cr0          /* set paging (PG) bit */
                    306:        ret                     /* this also flushes prefetch-queue */
                    307: 
                    308: /*
                    309:  * The interrupt descriptor table has room for 256 idt's
                    310:  */
                    311: .align 4
                    312: .word 0
                    313: idt_descr:
                    314:        .word 256*8-1           # idt contains 256 entries
                    315:        .long 0xc0000000+_idt
                    316: 
                    317: .align 4
                    318: _idt:
                    319:        .fill 256,8,0           # idt is uninitialized
                    320: 
                    321: /*
                    322:  * The real GDT is also 256 entries long - no real reason
                    323:  */
                    324: .align 4
                    325: .word 0
                    326: gdt_descr:
                    327:        .word 256*8-1
                    328:        .long 0xc0000000+_gdt
                    329: 
                    330: /*
                    331:  * This gdt setup gives the kernel a 1GB address space at virtual
                    332:  * address 0xC0000000 - space enough for expansion, I hope.
                    333:  */
                    334: .align 4
                    335: _gdt:
                    336:        .quad 0x0000000000000000        /* NULL descriptor */
                    337:        .quad 0xc0c39a000000ffff        /* 1GB at 0xC0000000 */
                    338:        .quad 0xc0c392000000ffff        /* 1GB */
                    339:        .quad 0x0000000000000000        /* TEMPORARY - don't use */
                    340:        .fill 252,8,0                   /* space for LDT's and TSS's etc */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.