|
|
1.1 root 1: /* 1.1.1.2 ! root 2: * linux/boot/head.s ! 3: * ! 4: * (C) 1991 Linus Torvalds ! 5: */ ! 6: ! 7: /* 1.1 root 8: * head.s contains the 32-bit startup code. 9: * 10: * NOTE!!! Startup happens at absolute address 0x00000000, which is also where 11: * the page directory will exist. The startup code will be overwritten by 12: * the page directory. 13: */ 14: .text 1.1.1.2 ! root 15: .globl _idt,_gdt,_pg_dir,_tmp_floppy_area 1.1 root 16: _pg_dir: 17: startup_32: 18: movl $0x10,%eax 19: mov %ax,%ds 20: mov %ax,%es 21: mov %ax,%fs 22: mov %ax,%gs 23: lss _stack_start,%esp 24: call setup_idt 25: call setup_gdt 26: movl $0x10,%eax # reload all the segment registers 27: mov %ax,%ds # after changing gdt. CS was already 28: mov %ax,%es # reloaded in 'setup_gdt' 29: mov %ax,%fs 30: mov %ax,%gs 31: lss _stack_start,%esp 32: xorl %eax,%eax 33: 1: incl %eax # check that A20 really IS enabled 1.1.1.2 ! root 34: movl %eax,0x000000 # loop forever if it isn't 1.1 root 35: cmpl %eax,0x100000 36: je 1b 1.1.1.2 ! root 37: /* ! 38: * NOTE! 486 should set bit 16, to check for write-protect in supervisor ! 39: * mode. Then it would be unnecessary with the "verify_area()"-calls. ! 40: * 486 users probably want to set the NE (#5) bit also, so as to use ! 41: * int 16 for math errors. ! 42: */ 1.1 root 43: movl %cr0,%eax # check math chip 44: andl $0x80000011,%eax # Save PG,ET,PE 1.1.1.2 ! root 45: /* "orl $0x10020,%eax" here for 486 might be good */ ! 46: orl $2,%eax # set MP 1.1 root 47: testl $0x10,%eax 48: jne 1f # ET is set - 387 is present 1.1.1.2 ! root 49: xorl $6,%eax # else reset MP and set EM 1.1 root 50: 1: movl %eax,%cr0 51: jmp after_page_tables 52: 53: /* 54: * setup_idt 55: * 56: * sets up a idt with 256 entries pointing to 57: * ignore_int, interrupt gates. It then loads 58: * idt. Everything that wants to install itself 59: * in the idt-table may do so themselves. Interrupts 60: * are enabled elsewhere, when we can be relatively 61: * sure everything is ok. This routine will be over- 62: * written by the page tables. 63: */ 64: setup_idt: 65: lea ignore_int,%edx 66: movl $0x00080000,%eax 67: movw %dx,%ax /* selector = 0x0008 = cs */ 68: movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ 69: 70: lea _idt,%edi 71: mov $256,%ecx 72: rp_sidt: 73: movl %eax,(%edi) 74: movl %edx,4(%edi) 75: addl $8,%edi 76: dec %ecx 77: jne rp_sidt 78: lidt idt_descr 79: ret 80: 81: /* 82: * setup_gdt 83: * 84: * This routines sets up a new gdt and loads it. 85: * Only two entries are currently built, the same 86: * ones that were built in init.s. The routine 87: * is VERY complicated at two whole lines, so this 88: * rather long comment is certainly needed :-). 89: * This routine will beoverwritten by the page tables. 90: */ 91: setup_gdt: 92: lgdt gdt_descr 93: ret 94: 1.1.1.2 ! root 95: /* ! 96: * I put the kernel page tables right after the page directory, ! 97: * using 4 of them to span 16 Mb of physical memory. People with ! 98: * more than 16MB will have to expand this. ! 99: */ 1.1 root 100: .org 0x1000 101: pg0: 102: 103: .org 0x2000 104: pg1: 105: 106: .org 0x3000 1.1.1.2 ! root 107: pg2: 1.1 root 108: 109: .org 0x4000 1.1.1.2 ! root 110: pg3: ! 111: ! 112: .org 0x5000 ! 113: /* ! 114: * tmp_floppy_area is used by the floppy-driver when DMA cannot ! 115: * reach to a buffer-block. It needs to be aligned, so that it isn't ! 116: * on a 64kB border. ! 117: */ ! 118: _tmp_floppy_area: ! 119: .fill 1024,1,0 ! 120: 1.1 root 121: after_page_tables: 122: pushl $0 # These are the parameters to main :-) 123: pushl $0 124: pushl $0 125: pushl $L6 # return address for main, if it decides to. 126: pushl $_main 127: jmp setup_paging 128: L6: 129: jmp L6 # main should never return here, but 130: # just in case, we know what happens. 131: 132: /* This is the default interrupt "handler" :-) */ 1.1.1.2 ! root 133: int_msg: ! 134: .asciz "Unknown interrupt\n\r" 1.1 root 135: .align 2 136: ignore_int: 1.1.1.2 ! root 137: pushl %eax ! 138: pushl %ecx ! 139: pushl %edx ! 140: push %ds ! 141: push %es ! 142: push %fs ! 143: movl $0x10,%eax ! 144: mov %ax,%ds ! 145: mov %ax,%es ! 146: mov %ax,%fs ! 147: pushl $int_msg ! 148: call _printk ! 149: popl %eax ! 150: pop %fs ! 151: pop %es ! 152: pop %ds ! 153: popl %edx ! 154: popl %ecx ! 155: popl %eax ! 156: iret 1.1 root 157: 158: 159: /* 160: * Setup_paging 161: * 162: * This routine sets up paging by setting the page bit 163: * in cr0. The page tables are set up, identity-mapping 1.1.1.2 ! root 164: * the first 16MB. The pager assumes that no illegal 1.1 root 165: * addresses are produced (ie >4Mb on a 4Mb machine). 166: * 167: * NOTE! Although all physical memory should be identity 168: * mapped by this routine, only the kernel page functions 169: * use the >1Mb addresses directly. All "normal" functions 170: * use just the lower 1Mb, or the local data space, which 171: * will be mapped to some other place - mm keeps track of 172: * that. 173: * 1.1.1.2 ! root 174: * For those with more memory than 16 Mb - tough luck. I've 1.1 root 175: * not got it, why should you :-) The source is here. Change 176: * it. (Seriously - it shouldn't be too difficult. Mostly 1.1.1.2 ! root 177: * change some constants etc. I left it at 16Mb, as my machine 1.1 root 178: * even cannot be extended past that (ok, but it was cheap :-) 179: * I've tried to show which constants to change by having 1.1.1.2 ! root 180: * some kind of marker at them (search for "16Mb"), but I 1.1 root 181: * won't guarantee that's all :-( ) 182: */ 183: .align 2 184: setup_paging: 1.1.1.2 ! root 185: movl $1024*5,%ecx /* 5 pages - pg_dir+4 page tables */ 1.1 root 186: xorl %eax,%eax 187: xorl %edi,%edi /* pg_dir is at 0x000 */ 188: cld;rep;stosl 189: movl $pg0+7,_pg_dir /* set present bit/user r/w */ 190: movl $pg1+7,_pg_dir+4 /* --------- " " --------- */ 1.1.1.2 ! root 191: movl $pg2+7,_pg_dir+8 /* --------- " " --------- */ ! 192: movl $pg3+7,_pg_dir+12 /* --------- " " --------- */ ! 193: movl $pg3+4092,%edi ! 194: movl $0xfff007,%eax /* 16Mb - 4096 + 7 (r/w user,p) */ 1.1 root 195: std 196: 1: stosl /* fill pages backwards - more efficient :-) */ 197: subl $0x1000,%eax 198: jge 1b 199: xorl %eax,%eax /* pg_dir is at 0x0000 */ 200: movl %eax,%cr3 /* cr3 - page directory start */ 201: movl %cr0,%eax 202: orl $0x80000000,%eax 203: movl %eax,%cr0 /* set paging (PG) bit */ 204: ret /* this also flushes prefetch-queue */ 205: 206: .align 2 207: .word 0 208: idt_descr: 209: .word 256*8-1 # idt contains 256 entries 210: .long _idt 211: .align 2 212: .word 0 213: gdt_descr: 214: .word 256*8-1 # so does gdt (not that that's any 215: .long _gdt # magic number, but it works for me :^) 216: 217: .align 3 218: _idt: .fill 256,8,0 # idt is uninitialized 219: 220: _gdt: .quad 0x0000000000000000 /* NULL descriptor */ 1.1.1.2 ! root 221: .quad 0x00c09a0000000fff /* 16Mb */ ! 222: .quad 0x00c0920000000fff /* 16Mb */ 1.1 root 223: .quad 0x0000000000000000 /* TEMPORARY - don't use */ 224: .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.