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