|
|
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 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.