1 /* 2 * linux/arch/i386/head.S -- the 32-bit startup code. 3 * 4 * Copyright (C) 1991, 1992 Linus Torvalds 5 * 6 * Enhanced CPU detection and feature setting code by Mike Jagdis 7 * and Martin Mares, November 1997. 8 */ 9 10 .text 11 #include <linux/config.h> 12 #include <linux/threads.h> 13 #include <linux/linkage.h> 14 #include <asm/segment.h> 15 #include <asm/page.h> 16 #include <asm/pgtable.h> 17 #include <asm/desc.h> 18 19 #define OLD_CL_MAGIC_ADDR 0x90020 20 #define OLD_CL_MAGIC 0xA33F 21 #define OLD_CL_BASE_ADDR 0x90000 22 #define OLD_CL_OFFSET 0x90022 23 #define NEW_CL_POINTER 0x228 /* Relative to real mode data */ 24 25 /* 26 * References to members of the boot_cpu_data structure. 27 */ 28 29 #define CPU_PARAMS SYMBOL_NAME(boot_cpu_data) 30 #define X86 CPU_PARAMS+0 31 #define X86_VENDOR CPU_PARAMS+1 32 #define X86_MODEL CPU_PARAMS+2 33 #define X86_MASK CPU_PARAMS+3 34 #define X86_HARD_MATH CPU_PARAMS+6 35 #define X86_CPUID CPU_PARAMS+8 36 #define X86_CAPABILITY CPU_PARAMS+12 37 #define X86_VENDOR_ID CPU_PARAMS+28 38 39 /* 40 * swapper_pg_dir is the main page directory, address 0x00101000 41 * 42 * On entry, %esi points to the real-mode code as a 32-bit pointer. 43 */ 44 startup_32: 45 /* 46 * Set segments to known values 47 */ 48 cld 49 movl $(__KERNEL_DS),%eax 50 movl %eax,%ds 51 movl %eax,%es 52 movl %eax,%fs 53 movl %eax,%gs 54 #ifdef CONFIG_SMP 55 orw %bx,%bx 56 jz 1f 57 58 /* 59 * New page tables may be in 4Mbyte page mode and may 60 * be using the global pages. 61 * 62 * NOTE! If we are on a 486 we may have no cr4 at all! 63 * So we do not try to touch it unless we really have 64 * some bits in it to set. This won't work if the BSP 65 * implements cr4 but this AP does not -- very unlikely 66 * but be warned! The same applies to the pse feature 67 * if not equally supported. --macro 68 * 69 * NOTE! We have to correct for the fact that we're 70 * not yet offset PAGE_OFFSET.. 71 */ 72 #define cr4_bits mmu_cr4_features-__PAGE_OFFSET 73 cmpl $0,cr4_bits 74 je 3f 75 movl %cr4,%eax # Turn on paging options (PSE,PAE,..) 76 orl cr4_bits,%eax 77 movl %eax,%cr4 78 jmp 3f 79 1: 80 #endif 81 /* 82 * Initialize page tables 83 */ 84 movl $pg0-__PAGE_OFFSET,%edi /* initialize page tables */ 85 movl $007,%eax /* "007" doesn't mean with right to kill, but 86 PRESENT+RW+USER */ 87 2: stosl 88 add $0x1000,%eax 89 cmp $empty_zero_page-__PAGE_OFFSET,%edi 90 jne 2b 91 92 /* 93 * Enable paging 94 */ 95 3: 96 movl $swapper_pg_dir-__PAGE_OFFSET,%eax 97 movl %eax,%cr3 /* set the page table pointer.. */ 98 movl %cr0,%eax 99 orl $0x80000000,%eax 100 movl %eax,%cr0 /* ..and set paging (PG) bit */ 101 jmp 1f /* flush the prefetch-queue */ 102 1: 103 movl $1f,%eax 104 jmp *%eax /* make sure eip is relocated */ 105 1: 106 /* Set up the stack pointer */ 107 lss stack_start,%esp 108 109 #ifdef CONFIG_SMP 110 orw %bx,%bx 111 jz 1f /* Initial CPU cleans BSS */ 112 pushl $0 113 popfl 114 jmp checkCPUtype 115 1: 116 #endif CONFIG_SMP 117 118 /* 119 * Clear BSS first so that there are no surprises... 120 * No need to cld as DF is already clear from cld above... 121 */ 122 xorl %eax,%eax 123 movl $ SYMBOL_NAME(__bss_start),%edi 124 movl $ SYMBOL_NAME(_end),%ecx 125 subl %edi,%ecx 126 rep 127 stosb 128 129 /* 130 * start system 32-bit setup. We need to re-do some of the things done 131 * in 16-bit mode for the "real" operations. 132 */ 133 call setup_idt 134 /* 135 * Initialize eflags. Some BIOS's leave bits like NT set. This would 136 * confuse the debugger if this code is traced. 137 * XXX - best to initialize before switching to protected mode. 138 */ 139 pushl $0 140 popfl 141 /* 142 * Copy bootup parameters out of the way. First 2kB of 143 * _empty_zero_page is for boot parameters, second 2kB 144 * is for the command line. 145 * 146 * Note: %esi still has the pointer to the real-mode data. 147 */ 148 movl $ SYMBOL_NAME(empty_zero_page),%edi 149 movl $512,%ecx 150 cld 151 rep 152 movsl 153 xorl %eax,%eax 154 movl $512,%ecx 155 rep 156 stosl 157 movl SYMBOL_NAME(empty_zero_page)+NEW_CL_POINTER,%esi 158 andl %esi,%esi 159 jnz 2f # New command line protocol 160 cmpw $(OLD_CL_MAGIC),OLD_CL_MAGIC_ADDR 161 jne 1f 162 movzwl OLD_CL_OFFSET,%esi 163 addl $(OLD_CL_BASE_ADDR),%esi 164 2: 165 movl $ SYMBOL_NAME(empty_zero_page)+2048,%edi 166 movl $512,%ecx 167 rep 168 movsl 169 1: 170 checkCPUtype: 171 172 movl $-1,X86_CPUID # -1 for no CPUID initially 173 174 /* check if it is 486 or 386. */ 175 /* 176 * XXX - this does a lot of unnecessary setup. Alignment checks don't 177 * apply at our cpl of 0 and the stack ought to be aligned already, and 178 * we don't need to preserve eflags. 179 */ 180 181 movb $3,X86 # at least 386 182 pushfl # push EFLAGS 183 popl %eax # get EFLAGS 184 movl %eax,%ecx # save original EFLAGS 185 xorl $0x40000,%eax # flip AC bit in EFLAGS 186 pushl %eax # copy to EFLAGS 187 popfl # set EFLAGS 188 pushfl # get new EFLAGS 189 popl %eax # put it in eax 190 xorl %ecx,%eax # change in flags 191 andl $0x40000,%eax # check if AC bit changed 192 je is386 193 194 movb $4,X86 # at least 486 195 movl %ecx,%eax 196 xorl $0x200000,%eax # check ID flag 197 pushl %eax 198 popfl # if we are on a straight 486DX, SX, or 199 pushfl # 487SX we can't change it 200 popl %eax 201 xorl %ecx,%eax 202 pushl %ecx # restore original EFLAGS 203 popfl 204 andl $0x200000,%eax 205 je is486 206 207 /* get vendor info */ 208 xorl %eax,%eax # call CPUID with 0 -> return vendor ID 209 cpuid 210 movl %eax,X86_CPUID # save CPUID level 211 movl %ebx,X86_VENDOR_ID # lo 4 chars 212 movl %edx,X86_VENDOR_ID+4 # next 4 chars 213 movl %ecx,X86_VENDOR_ID+8 # last 4 chars 214 215 orl %eax,%eax # do we have processor info as well? 216 je is486 217 218 movl $1,%eax # Use the CPUID instruction to get CPU type 219 cpuid 220 movb %al,%cl # save reg for future use 221 andb $0x0f,%ah # mask processor family 222 movb %ah,X86 223 andb $0xf0,%al # mask model 224 shrb $4,%al 225 movb %al,X86_MODEL 226 andb $0x0f,%cl # mask mask revision 227 movb %cl,X86_MASK 228 movl %edx,X86_CAPABILITY 229 230 is486: 231 movl %cr0,%eax # 486 or better 232 andl $0x80000011,%eax # Save PG,PE,ET 233 orl $0x50022,%eax # set AM, WP, NE and MP 234 jmp 2f 235 236 is386: pushl %ecx # restore original EFLAGS 237 popfl 238 movl %cr0,%eax # 386 239 andl $0x80000011,%eax # Save PG,PE,ET 240 orl $2,%eax # set MP 241 2: movl %eax,%cr0 242 call check_x87 243 incb ready 244 lgdt gdt_descr 245 lidt idt_descr 246 ljmp $(__KERNEL_CS),$1f 247 1: movl $(__KERNEL_DS),%eax # reload all the segment registers 248 movl %eax,%ds # after changing gdt. 249 movl %eax,%es 250 movl %eax,%fs 251 movl %eax,%gs 252 #ifdef CONFIG_SMP 253 movl $(__KERNEL_DS), %eax 254 movl %eax,%ss # Reload the stack pointer (segment only) 255 #else 256 lss stack_start,%esp # Load processor stack 257 #endif 258 xorl %eax,%eax 259 lldt %ax 260 cld # gcc2 wants the direction flag cleared at all times 261 #ifdef CONFIG_SMP 262 movb ready, %cl 263 cmpb $1,%cl 264 je 1f # the first CPU calls start_kernel 265 # all other CPUs call initialize_secondary 266 call SYMBOL_NAME(initialize_secondary) 267 jmp L6 268 1: 269 #endif 270 call SYMBOL_NAME(start_kernel) 271 L6: 272 jmp L6 # main should never return here, but 273 # just in case, we know what happens. 274 275 ready: .byte 0 276 277 /* 278 * We depend on ET to be correct. This checks for 287/387. 279 */ 280 check_x87: 281 movb $0,X86_HARD_MATH 282 clts 283 fninit 284 fstsw %ax 285 cmpb $0,%al 286 je 1f 287 movl %cr0,%eax /* no coprocessor: have to set bits */ 288 xorl $4,%eax /* set EM */ 289 movl %eax,%cr0 290 ret 291 ALIGN 292 1: movb $1,X86_HARD_MATH 293 .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ 294 ret 295 296 /* 297 * setup_idt 298 * 299 * sets up a idt with 256 entries pointing to 300 * ignore_int, interrupt gates. It doesn't actually load 301 * idt - that can be done only after paging has been enabled 302 * and the kernel moved to PAGE_OFFSET. Interrupts 303 * are enabled elsewhere, when we can be relatively 304 * sure everything is ok. 305 */ 306 setup_idt: 307 lea ignore_int,%edx 308 movl $(__KERNEL_CS << 16),%eax 309 movw %dx,%ax /* selector = 0x0010 = cs */ 310 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ 311 312 lea SYMBOL_NAME(idt_table),%edi 313 mov $256,%ecx 314 rp_sidt: 315 movl %eax,(%edi) 316 movl %edx,4(%edi) 317 addl $8,%edi 318 dec %ecx 319 jne rp_sidt 320 ret 321 322 ENTRY(stack_start) 323 .long SYMBOL_NAME(init_task_union)+8192 324 .long __KERNEL_DS 325 326 /* This is the default interrupt "handler" :-) */ 327 int_msg: 328 .asciz "Unknown interrupt\n" 329 ALIGN 330 ignore_int: 331 cld 332 pushl %eax 333 pushl %ecx 334 pushl %edx 335 pushl %es 336 pushl %ds 337 movl $(__KERNEL_DS),%eax 338 movl %eax,%ds 339 movl %eax,%es 340 pushl $int_msg 341 call SYMBOL_NAME(printk) 342 popl %eax 343 popl %ds 344 popl %es 345 popl %edx 346 popl %ecx 347 popl %eax 348 iret 349 350 /* 351 * The interrupt descriptor table has room for 256 idt's, 352 * the global descriptor table is dependent on the number 353 * of tasks we can have.. 354 */ 355 #define IDT_ENTRIES 256 356 #define GDT_ENTRIES (__TSS(NR_CPUS)) 357 358 359 .globl SYMBOL_NAME(idt) 360 .globl SYMBOL_NAME(gdt) 361 362 ALIGN 363 .word 0 364 idt_descr: 365 .word IDT_ENTRIES*8-1 # idt contains 256 entries 366 SYMBOL_NAME(idt): 367 .long SYMBOL_NAME(idt_table) 368 369 .word 0 370 gdt_descr: 371 .word GDT_ENTRIES*8-1 372 SYMBOL_NAME(gdt): 373 .long SYMBOL_NAME(gdt_table) 374 375 /* 376 * This is initialized to create an identity-mapping at 0-8M (for bootup 377 * purposes) and another mapping of the 0-8M area at virtual address 378 * PAGE_OFFSET. 379 */ 380 .org 0x1000 381 ENTRY(swapper_pg_dir) 382 .long 0x00102007 383 .long 0x00103007 384 .fill BOOT_USER_PGD_PTRS-2,4,0 385 /* default: 766 entries */ 386 .long 0x00102007 387 .long 0x00103007 388 /* default: 254 entries */ 389 .fill BOOT_KERNEL_PGD_PTRS-2,4,0 390 391 /* 392 * The page tables are initialized to only 8MB here - the final page 393 * tables are set up later depending on memory size. 394 */ 395 .org 0x2000 396 ENTRY(pg0) 397 398 .org 0x3000 399 ENTRY(pg1) 400 401 /* 402 * empty_zero_page must immediately follow the page tables ! (The 403 * initialization loop counts until empty_zero_page) 404 */ 405 406 .org 0x4000 407 ENTRY(empty_zero_page) 408 409 .org 0x5000 410 411 /* 412 * Real beginning of normal "text" segment 413 */ 414 ENTRY(stext) 415 ENTRY(_stext) 416 417 /* 418 * This starts the data section. Note that the above is all 419 * in the text section because it has alignment requirements 420 * that we cannot fulfill any other way. 421 */ 422 .data 423 424 ALIGN 425 /* 426 * This contains typically 140 quadwords, depending on NR_CPUS. 427 * 428 * NOTE! Make sure the gdt descriptor in head.S matches this if you 429 * change anything. 430 */ 431 ENTRY(gdt_table) 432 .quad 0x0000000000000000 /* NULL descriptor */ 433 .quad 0x0000000000000000 /* not used */ 434 .quad 0x00cf9a000000ffff /* 0x10 kernel 4GB code at 0x00000000 */ 435 .quad 0x00cf92000000ffff /* 0x18 kernel 4GB data at 0x00000000 */ 436 .quad 0x00cffa000000ffff /* 0x23 user 4GB code at 0x00000000 */ 437 .quad 0x00cff2000000ffff /* 0x2b user 4GB data at 0x00000000 */ 438 .quad 0x0000000000000000 /* not used */ 439 .quad 0x0000000000000000 /* not used */ 440 /* 441 * The APM segments have byte granularity and their bases 442 * and limits are set at run time. 443 */ 444 .quad 0x0040920000000000 /* 0x40 APM set up for bad BIOS's */ 445 .quad 0x00409a0000000000 /* 0x48 APM CS code */ 446 .quad 0x00009a0000000000 /* 0x50 APM CS 16 code (16 bit) */ 447 .quad 0x0040920000000000 /* 0x58 APM DS data */ 448 .fill NR_CPUS*4,8,0 /* space for TSS's and LDT's */