Linux/boot/head.S 冷不防 2022-09-19 12:12 105阅读 0赞 Linux/boot/head.S 1 /\* 2\*linux/boot/head.S 3\* 4\*Copyright (C) 1991, 1992Linus Torvalds 5\*/ 6 7 /\* 8\*head.S contains the 32-bit startup code. 9\*/ 10 11 .text 12 .globl \_idt,\_gdt, 13 .globl \_swapper\_pg\_dir,\_pg0 14 .globl \_empty\_bad\_page 15 .globl \_empty\_bad\_page\_table 16 .globl \_empty\_zero\_page 17 .globl \_tmp\_floppy\_area,\_floppy\_track\_buffer 18 19 \#include <linux/tasks.h> 20 \#include <linux/segment.h> 21 22 \#define CL\_MAGIC\_ADDR0x90020 23 \#define CL\_MAGIC0xA 33F 24 \#define CL\_BASE\_ADDR0x90000 25 \#define CL\_OFFSET0x90022 26 27 /\* 28\* swapper\_pg\_dir is the main page directory, address 0x00001000 (or at 29\* address 0x00101000 for a compressed boot). 30\*/ 31 startup\_32: 32cld 33movl $(KERNEL\_DS),%eax 34mov %ax,%ds 35mov %ax,%es 36mov %ax,%fs 37mov %ax,%gs 38lss \_stack\_start,%esp 39 /\* 40\* Clear BSS first so that there are no surprises... 41\*/ 42xorl %eax,%eax 43movl $\_\_edata,%edi 44movl $\_\_end,%ecx 45subl %edi,%ecx 46cld 47rep 48stosb 49 /\* 50\* start system 32-bit setup. We need to re-do some of the things done 51\* in 16-bit mode for the "real" operations. 52\*/ 53call setup\_idt 54xorl %eax,%eax 55 1:incl %eax\# check that A20 really IS enabled 56movl %eax,0x000000\# loop forever if it isn't 57cmpl %eax,0x100000 58 je 1b 59 /\* 60\* Initialize eflags.Some BIOS's leave bits like NT set.This would 61\* confuse the debugger if this code is traced. 62\* XXX - best to initialize before switching to protected mode. 63\*/ 64pushl $0 65popfl 66 /\* 67\* Copy bootup parameters out of the way. First 2kB of 68\* \_empty\_zero\_page is for boot parameters, second 2kB 69\* is for the command line. 70\*/ 71movl $0x90000,%esi 72movl $\_empty\_zero\_page,%edi 73movl $512,%ecx 74cld 75rep 76movsl 77xorl %eax,%eax 78movl $512,%ecx 79rep 80stosl 81cmpw $(CL\_MAGIC),CL\_MAGIC\_ADDR 82jne 1f 83movl $\_empty\_zero\_page+2048,%edi 84movzwl CL\_OFFSET,%esi 85addl $(CL\_BASE\_ADDR),%esi 86movl $2048,%ecx 87rep 88movsb 89 1: 90 /\* check if it is 486 or 386. \*/ 91 /\* 92\* XXX - this does a lot of unnecessary setup.Alignment checks don't 93\* apply at our cpl of 0 and the stack ought to be aligned already, and 94\* we don't need to preserve eflags. 95\*/ 96movl %esp,%edi\# save stack pointer 97andl $0xfffffffc,%esp\# align stack to avoid AC fault 98movl $3,\_x86 99pushfl\# push EFLAGS 100popl %eax\# get EFLAGS 101movl %eax,%ecx\# save original EFLAGS 102xorl $0x40000,%eax\# flip AC bit in EFLAGS 103pushl %eax\# copy to EFLAGS 104popfl\# set EFLAGS 105pushfl\# get new EFLAGS 106popl %eax\# put it in eax 107xorl %ecx,%eax\# change in flags 108andl $0x40000,%eax\# check if AC bit changed 109je is386 110movl $4,\_x86 111movl %ecx,%eax 112xorl $0x200000,%eax\# check ID flag 113pushl %eax 114popfl\# if we are on a straight 486DX, SX, or 115pushfl\# 487SX we can't change it 116popl %eax 117xorl %ecx,%eax 118andl $0x200000,%eax 119je is486 120 isnew:pushl %ecx\# restore original EFLAGS 121popfl 122movl $1, %eax\# Use the CPUID instruction to 123.byte 0x 0f , 0xa2\# check the processor type 124andl $0xf00, %eax\# Set \_x86 with the family 125shrl $8, %eax\# returned. 126movl %eax, \_x86 127movl %edi,%esp\# restore esp 128movl %cr0,%eax\# 486+ 129andl $0x80000011,%eax\# Save PG,PE,ET 130orl $0x50022,%eax\# set AM, WP, NE and MP 131jmp 2f 132 is486:pushl %ecx\# restore original EFLAGS 133popfl 134movl %edi,%esp\# restore esp 135movl %cr0,%eax\# 486 136andl $0x80000011,%eax\# Save PG,PE,ET 137orl $0x50022,%eax\# set AM, WP, NE and MP 138jmp 2f 139 is386:pushl %ecx\# restore original EFLAGS 140popfl 141movl %edi,%esp\# restore esp 142movl %cr0,%eax\# 386 143andl $0x80000011,%eax\# Save PG,PE,ET 144orl $2,%eax\# set MP 145 2:movl %eax,%cr0 146call check\_x87 147call setup\_paging 148lgdt gdt\_descr 149lidt idt\_descr 150ljmp $(KERNEL\_CS),$ 1f 151 1:movl $(KERNEL\_DS),%eax\# reload all the segment registers 152mov %ax,%ds\# after changing gdt. 153mov %ax,%es 154mov %ax,%fs 155mov %ax,%gs 156lss \_stack\_start,%esp 157xorl %eax,%eax 158lldt %ax 159pushl %eax\# These are the parameters to main :-) 160pushl %eax 161pushl %eax 162cld\# gcc2 wants the direction flag cleared at all times 163call \_start\_kernel 164 L6: 165jmp L6\# main should never return here, but 166\# just in case, we know what happens. 167 168 /\* 169\* We depend on ET to be correct. This checks for 287/387. 170\*/ 171 check\_x87: 172movl $0,\_hard\_math 173clts 174fninit 175fstsw %ax 176cmpb $0,%al 177je 1f 178movl %cr0,%eax/\* no coprocessor: have to set bits \*/ 179xorl $4,%eax/\* set EM \*/ 180movl %eax,%cr0 181ret 182 .align 2 183 1:movl $1,\_hard\_math 184.byte 0xDB,0xE4/\* fsetpm for 287, ignored by 387 \*/ 185ret 186 187 /\* 188\*setup\_idt 189\* 190\*sets up a idt with 256 entries pointing to 191\*ignore\_int, interrupt gates. It doesn't actually load 192\*idt - that can be done only after paging has been enabled 193\*and the kernel moved to 0xC0000000. Interrupts 194\*are enabled elsewhere, when we can be relatively 195\*sure everything is ok. 196\*/ 197 setup\_idt: 198lea ignore\_int,%edx 199movl $(KERNEL\_CS << 16),%eax 200movw %dx,%ax/\* selector = 0x0010 = cs \*/ 201movw $0x8E00,%dx/\* interrupt gate - dpl=0, present \*/ 202 203lea \_idt,%edi 204mov $256,%ecx 205 rp\_sidt: 206movl %eax,(%edi) 207movl %edx,4(%edi) 208addl $8,%edi 209dec %ecx 210jne rp\_sidt 211ret 212 213 214 /\* 215\* Setup\_paging 216\* 217\* This routine sets up paging by setting the page bit 218\* in cr0. The page tables are set up, identity-mapping 219\* the first 4MB.The rest are initialized later. 220\* 221\* (ref: added support for up to 32mb, 17Apr92)\-- Rik Faith 222\* (ref: update, 25Sept92)\-- croutons@crunchy.uucp 223\* (ref: 92.10.11 - Linus Torvalds. Corrected 16M limit - no upper memory limit) 224\*/ 225 .align 2 226 setup\_paging: 227movl $1024\*2,%ecx/\* 2 pages - swapper\_pg\_dir+1 page table \*/ 228xorl %eax,%eax 229movl $\_swapper\_pg\_dir,%edi/\* swapper\_pg\_dir is at 0x1000 \*/ 230cld;rep;stosl 231 /\* Identity-map the kernel in low 4MB memory for ease of transition \*/ 232movl $\_pg0+7,\_swapper\_pg\_dir/\* set present bit/user r/w \*/ 233 /\* But the real place is at 0xC0000000 \*/ 234movl $\_pg0+7,\_swapper\_pg\_dir+3072/\* set present bit/user r/w \*/ 235movl $\_pg0+4092,%edi 236movl $0x03ff007,%eax/\*4Mb - 4096 + 7 (r/w user,p) \*/ 237std 238 1:stosl/\* fill the page backwards - more efficient :-) \*/ 239subl $0x1000,%eax 240jge 1b 241cld 242movl $\_swapper\_pg\_dir,%eax 243movl %eax,%cr3/\* cr3 - page directory start \*/ 244movl %cr0,%eax 245orl $0x80000000,%eax 246movl %eax,%cr0/\* set paging (PG) bit \*/ 247ret/\* this also flushes the prefetch-queue \*/ 248 249 /\* 250\* page 0 is made non-existent, so that kernel NULL pointer references get 251\* caught. Thus the swapper page directory has been moved to 0x1000 252\* 253\* XXX Actually, the swapper page directory is at 0x1000 plus 1 megabyte, 254\* with the introduction of the compressed boot code.Theoretically, 255\* the original design of overlaying the startup code with the swapper 256\* page directory is still possible --- it would reduce the size of the kernel 257\* by 2-3k.This would be a good thing to do at some point..... 258\*/ 259 .org 0x1000 260 \_swapper\_pg\_dir: 261 /\* 262\* The page tables are initialized to only 4MB here - the final page 263\* tables are set up later depending on memory size. 264\*/ 265 .org 0x2000 266 \_pg0: 267 268 .org 0x3000 269 \_empty\_bad\_page: 270 271 .org 0x4000 272 \_empty\_bad\_page\_table: 273 274 .org 0x5000 275 \_empty\_zero\_page: 276 277 .org 0x6000 278 /\* 279\* tmp\_floppy\_area is used by the floppy-driver when DMA cannot 280\* reach to a buffer-block. It needs to be aligned, so that it isn't 281\* on a 64kB border. 282\*/ 283 \_tmp\_floppy\_area: 284.fill 1024,1,0 285 /\* 286\* floppy\_track\_buffer is used to buffer one track of floppy data: it 287\* has to be separate from the tmp\_floppy area, as otherwise a single- 288\* sector read/write can mess it up. It can contain one full track of 289\* data (18\*2\*512 bytes). 290\*/ 291 \_floppy\_track\_buffer: 292.fill 512\*2\*18,1,0 293 294 /\* This is the default interrupt "handler" :-) \*/ 295 int\_msg: 296.asciz "Unknown interrupt/n" 297 .align 2 298 ignore\_int: 299cld 300pushl %eax 301pushl %ecx 302pushl %edx 303push %ds 304push %es 305push %fs 306movl $(KERNEL\_DS),%eax 307mov %ax,%ds 308mov %ax,%es 309mov %ax,%fs 310pushl $int\_msg 311call \_printk 312popl %eax 313pop %fs 314pop %es 315pop %ds 316popl %edx 317popl %ecx 318popl %eax 319iret 320 321 /\* 322\* The interrupt descriptor table has room for 256 idt's 323\*/ 324 .align 4 325 .word 0 326 idt\_descr: 327.word 256\*8-1\# idt contains 256 entries 328.long 0xc0000000+\_idt 329 330 .align 4 331 \_idt: 332.fill 256,8,0\# idt is uninitialized 333 334 .align 4 335 .word 0 336 gdt\_descr: 337.word (8+2\*NR\_TASKS)\*8-1 338.long 0xc0000000+\_gdt 339 340 /\* 341\* This gdt setup gives the kernel a 1GB address space at virtual 342\* address 0xC0000000 - space enough for expansion, I hope. 343\*/ 344 .align 4 345 \_gdt: 346.quad 0x0000000000000000/\* NULL descriptor \*/ 347.quad 0x0000000000000000/\* not used \*/ 348.quad 0xc 0c 39a 000000ffff/\* 0x10 kernel 1GB code at 0xC0000000 \*/ 349.quad 0xc 0c 392000000ffff/\* 0x18 kernel 1GB data at 0xC0000000 \*/ 350.quad 0x00cbfa000000ffff/\* 0x23 user3GB code at 0x00000000 \*/ 351.quad 0x00cbf2000000ffff/\* 0x2b user3GB data at 0x00000000 \*/ 352.quad 0x0000000000000000/\* not used \*/ 353.quad 0x0000000000000000/\* not used \*/ 354.fill 2\*NR\_TASKS,8,0/\* space for LDT's and TSS's etc \*/
还没有评论,来说两句吧...