Annotation of linux/boot/head.S, revision 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.