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