1/* 2 * linux/arch/x86_64/kernel/head.S -- start in 32bit and switch to 64bit 3 * 4 * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE 5 * Copyright (C) 2000 Pavel Machek <pavel@suse.cz> 6 * Copyright (C) 2000 Karsten Keil <kkeil@suse.de> 7 * Copyright (C) 2001,2002 Andi Kleen <ak@suse.de> 8 * 9 * $Id: head.S,v 1.59 2004/02/10 05:53:06 ak Exp $ 10 */ 11 12 13#include <linux/linkage.h> 14#include <linux/threads.h> 15#include <asm/desc.h> 16#include <asm/segment.h> 17#include <asm/page.h> 18#include <asm/msr.h> 19#include <asm/offset.h> 20 21/* we are not able to switch in one step to the final KERNEL ADRESS SPACE 22 * because we need identity-mapped pages on setup so define __START_KERNEL to 23 * 0x100000 for this stage 24 * 25 */ 26 27 .text 28 .code32 29/* %bx: 1 if comming from smp trampoline on secondary cpu */ 30startup_32: 31 32 /* 33 * At this point the CPU runs in 32bit protected mode (CS.D = 1) with 34 * paging disabled and the point of this file is to switch to 64bit 35 * long mode with a kernel mapping for kerneland to jump into the 36 * kernel virtual addresses. 37 * There is no stack until we set one up. 38 */ 39 40 movl %ebx,%ebp /* Save trampoline flag */ 41 42 movl $__KERNEL_DS,%eax 43 movl %eax,%ds 44 45 /* First check if extended functions are implemented */ 46 movl $0x80000000, %eax 47 cpuid 48 cmpl $0x80000000, %eax 49 jbe no_long_mode 50 /* Check if long mode is implemented */ 51 mov $0x80000001, %eax 52 cpuid 53 btl $29, %edx 54 jnc no_long_mode 55 56 movl %edx,%edi 57 58 /* 59 * Prepare for entering 64bits mode 60 */ 61 62 /* Enable PAE mode and PGE */ 63 xorl %eax, %eax 64 btsl $5, %eax 65 btsl $7, %eax 66 movl %eax, %cr4 67 68 /* Setup early boot stage 4 level pagetables */ 69 movl $0x101000, %eax 70 movl %eax, %cr3 71 72 /* Setup EFER (Extended Feature Enable Register) */ 73 movl $MSR_EFER, %ecx 74 rdmsr 75 /* Fool rdmsr and reset %eax to avoid dependences */ 76 xorl %eax, %eax 77 /* Enable Long Mode */ 78 btsl $_EFER_LME, %eax 79 /* Enable System Call */ 80 btsl $_EFER_SCE, %eax 81 82 /* No Execute supported? */ 83 btl $20,%edi 84 jnc 1f 85 btsl $_EFER_NX, %eax 861: 87 88 /* Make changes effective */ 89 wrmsr 90 91 xorl %eax, %eax 92 /* Enable paging and in turn activate Long Mode */ 93 btsl $31, %eax 94 /* Enable protected mode */ 95 btsl $0, %eax 96 /* Enable MP */ 97 btsl $1, %eax 98 /* Enable ET */ 99 btsl $4, %eax 100 /* Enable NE */ 101 btsl $5, %eax 102 /* Enable WP */ 103 btsl $16, %eax 104 /* Enable AM */ 105 btsl $18, %eax 106 /* Make changes effective */ 107 movl %eax, %cr0 108 jmp reach_compatibility_mode 109reach_compatibility_mode: 110 111 /* 112 * At this point we're in long mode but in 32bit compatibility mode 113 * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn 114 * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we load 115 * the new gdt/idt that has __KERNEL_CS with CS.L = 1. 116 */ 117 118 testw %bp,%bp /* secondary CPU? */ 119 jnz second 120 121 /* Load new GDT with the 64bit segment using 32bit descriptor */ 122 movl $0x100F00, %eax 123 lgdt (%eax) 124 125second: 126 movl $0x100F10, %eax 127 /* Finally jump in 64bit mode */ 128 ljmp *(%eax) 129 130 .code64 131 .org 0x100 132reach_long64: 133 movq init_rsp(%rip),%rsp 134 135 /* zero EFLAGS after setting rsp */ 136 pushq $0 137 popfq 138 139 /* 140 * We must switch to a new descriptor in kernel space for the GDT 141 * because soon the kernel won't have access anymore to the userspace 142 * addresses where we're currently running on. We have to do that here 143 * because in 32bit we couldn't load a 64bit linear address. 144 */ 145 lgdt pGDT64 146 147 /* 148 * Setup up a dummy PDA. this is just for some early bootup code 149 * that does in_interrupt() 150 */ 151 movl $MSR_GS_BASE,%ecx 152 movq $cpu_pda,%rax 153 movq %rax,%rdx 154 shrq $32,%rdx 155 wrmsr 156 157 /* set up data segments. actually 0 would do too */ 158 movl $__KERNEL_DS,%eax 159 movl %eax,%ds 160 movl %eax,%ss 161 movl %eax,%es 162 163 /* esi is pointer to real mode structure with interesting info. 164 pass it to C */ 165 movl %esi, %edi 166 167 /* Finally jump to run C code and to be on real kernel address 168 * Since we are running on identity-mapped space we have to jump 169 * to the full 64bit address , this is only possible as indirect 170 * jump 171 */ 172 movq initial_code(%rip),%rax 173 jmp *%rax 174 175 /* SMP bootup changes these two */ 176 .globl initial_code 177initial_code: 178 .quad x86_64_start_kernel 179 .globl init_rsp 180init_rsp: 181 .quad init_task_union+THREAD_SIZE-8 182 183 184.code32 185ENTRY(no_long_mode) 186 /* This isn't an x86-64 CPU so hang */ 1871: 188 jmp 1b 189 190 .globl pGDT32 191.org 0xf00 192pGDT32: 193 .word gdt32_end-gdt_table32 194 .long gdt_table32-__START_KERNEL+0x100000 195 196.org 0xf10 197ljumpvector: 198 .long reach_long64-__START_KERNEL+0x100000 199 .word __KERNEL_CS 200 201ENTRY(stext) 202ENTRY(_stext) 203 204 /* 205 * This default setting generates an ident mapping at address 0x100000 206 * and a mapping for the kernel that precisely maps virtual address 207 * 0xffffffff80000000 to physical address 0x000000. (always using 208 * 2Mbyte large pages provided by PAE mode) 209 */ 210.org 0x1000 211ENTRY(init_level4_pgt) 212 .quad 0x0000000000102007 /* -> level3_ident_pgt */ 213 .fill 255,8,0 214 .quad 0x000000000010a007 215 .fill 254,8,0 216 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ 217 .quad 0x0000000000103007 /* -> level3_kernel_pgt */ 218 219.org 0x2000 220/* Kernel does not "know" about 4-th level of page tables. */ 221ENTRY(level3_ident_pgt) 222 .quad 0x0000000000104007 223 .fill 511,8,0 224 225.org 0x3000 226ENTRY(level3_kernel_pgt) 227 .fill 510,8,0 228 /* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */ 229 .quad 0x0000000000105007 /* -> level2_kernel_pgt */ 230 .fill 1,8,0 231 232.org 0x4000 233ENTRY(level2_ident_pgt) 234 /* 40MB for bootup. */ 235 .quad 0x0000000000000283 236 .quad 0x0000000000200183 237 .quad 0x0000000000400183 238 .quad 0x0000000000600183 239 .quad 0x0000000000800183 240 .quad 0x0000000000A00183 241 .quad 0x0000000000C00183 242 .quad 0x0000000000E00183 243 .quad 0x0000000001000183 244 .quad 0x0000000001200183 245 .quad 0x0000000001400183 246 .quad 0x0000000001600183 247 .quad 0x0000000001800183 248 .quad 0x0000000001A00183 249 .quad 0x0000000001C00183 250 .quad 0x0000000001E00183 251 .quad 0x0000000002000183 252 .quad 0x0000000002200183 253 .quad 0x0000000002400183 254 .quad 0x0000000002600183 255 /* Temporary mappings for the super early allocator in arch/x86_64/mm/init.c */ 256 .globl temp_boot_pmds 257temp_boot_pmds: 258 .fill 492,8,0 259 260.org 0x5000 261ENTRY(level2_kernel_pgt) 262 /* 40MB kernel mapping. The kernel code cannot be bigger than that. 263 When you change this change KERNEL_TEXT_SIZE in pgtable.h too. */ 264 /* (2^48-(2*1024*1024*1024)-((2^39)*511)-((2^30)*510)) = 0 */ 265 .quad 0x0000000000000183 266 .quad 0x0000000000200183 267 .quad 0x0000000000400183 268 .quad 0x0000000000600183 269 .quad 0x0000000000800183 270 .quad 0x0000000000A00183 271 .quad 0x0000000000C00183 272 .quad 0x0000000000E00183 273 .quad 0x0000000001000183 274 .quad 0x0000000001200183 275 .quad 0x0000000001400183 276 .quad 0x0000000001600183 277 .quad 0x0000000001800183 278 .quad 0x0000000001A00183 279 .quad 0x0000000001C00183 280 .quad 0x0000000001E00183 281 .quad 0x0000000002000183 282 .quad 0x0000000002200183 283 .quad 0x0000000002400183 284 .quad 0x0000000002600183 285 /* Module mapping starts here */ 286 .fill 492,8,0 287 288.org 0x6000 289ENTRY(empty_zero_page) 290 291.org 0x7000 292ENTRY(empty_bad_page) 293 294.org 0x8000 295ENTRY(empty_bad_pte_table) 296 297.org 0x9000 298ENTRY(empty_bad_pmd_table) 299 300.org 0xa000 301ENTRY(level3_physmem_pgt) 302 .quad 0x0000000000105007 /* -> level2_kernel_pgt (so that __va works even before pagetable_init) */ 303 304 .org 0xb000 305#ifdef CONFIG_ACPI_SLEEP 306ENTRY(wakeup_level4_pgt) 307 .quad 0x0000000000102007 /* -> level3_ident_pgt */ 308 .fill 255,8,0 309 .quad 0x000000000010a007 310 .fill 254,8,0 311 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ 312 .quad 0x0000000000103007 /* -> level3_kernel_pgt */ 313#endif 314 315.data 316 317.globl SYMBOL_NAME(gdt) 318 319 .globl pGDT64 320 .word 0 321 .align 16 322 .word 0 323pGDT64: 324 .word gdt_end-gdt_table 325SYMBOL_NAME_LABEL(gdt) 326 .quad gdt_table 327 328 329.align 64 /* cacheline aligned */ 330ENTRY(gdt_table32) 331 .quad 0x0000000000000000 /* This one is magic */ 332 .quad 0x0000000000000000 /* unused */ 333 .quad 0x00af9a000000ffff /* __KERNEL_CS */ 334gdt32_end: 335 336/* We need valid kernel segments for data and code in long mode too 337 * IRET will check the segment types kkeil 2000/10/28 338 * Also sysret mandates a special GDT layout 339 */ 340 341.align 64 /* cacheline aligned, keep this synchronized with asm/desc.h */ 342ENTRY(gdt_table) 343 .quad 0x0000000000000000 /* This one is magic */ 344 .quad 0x008f9a000000ffff /* __KERNEL_COMPAT32_CS */ 345 .quad 0x00af9a000000ffff /* __KERNEL_CS */ 346 .quad 0x00cf92000000ffff /* __KERNEL_DS */ 347 .quad 0x00cffe000000ffff /* __USER32_CS */ 348 .quad 0x00cff2000000ffff /* __USER_DS, __USER32_DS */ 349 .quad 0x00affa000000ffff /* __USER_CS */ 350 .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) 351 .word 0 # base address = 0 352 .word 0x9A00 # code read/exec 353 .word 0x00CF # granularity = 4096, 386 354 # (+5th nibble of limit) 355 /* __KERNEL32_CS */ 356 /* when you add something here fix constant in desc.h */ 357 .globl gdt_cpu_table 358gdt_cpu_table: 359 .fill NR_CPUS*PER_CPU_GDT_SIZE,1,0 360gdt_end: 361 .globl gdt_end 362 363 .align 64 364ENTRY(idt_table) 365 .rept 256 366 .quad 0 367 .quad 0 368 .endr 369