2 * linux/arch/x86_64/kernel/head.S -- start in 32bit and switch to 64bit
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>
9 * $Id: head.S,v 1.59 2004/02/10 05:53:06 ak Exp $
13 #include <linux/linkage.h>
14 #include <linux/threads.h>
16 #include <asm/segment.h>
19 #include <asm/offset.h>
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
29 /* %bx: 1 if comming from smp trampoline on secondary cpu */
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.
40 movl %ebx,%ebp /* Save trampoline flag */
42 movl $__KERNEL_DS,%eax
45 /* First check if extended functions are implemented */
46 movl $0x80000000, %eax
48 cmpl $0x80000000, %eax
50 /* Check if long mode is implemented */
59 * Prepare for entering 64bits mode
62 /* Enable PAE mode and PGE */
68 /* Setup early boot stage 4 level pagetables */
72 /* Setup EFER (Extended Feature Enable Register) */
75 /* Fool rdmsr and reset %eax to avoid dependences */
77 /* Enable Long Mode */
79 /* Enable System Call */
82 /* No Execute supported? */
88 /* Make changes effective */
92 /* Enable paging and in turn activate Long Mode */
94 /* Enable protected mode */
106 /* Make changes effective */
108 jmp reach_compatibility_mode
109 reach_compatibility_mode:
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.
118 testw %bp,%bp /* secondary CPU? */
121 /* Load new GDT with the 64bit segment using 32bit descriptor */
127 /* Finally jump in 64bit mode */
133 movq init_rsp(%rip),%rsp
135 /* zero EFLAGS after setting rsp */
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.
148 * Setup up a dummy PDA. this is just for some early bootup code
149 * that does in_interrupt()
151 movl $MSR_GS_BASE,%ecx
157 /* set up data segments. actually 0 would do too */
158 movl $__KERNEL_DS,%eax
163 /* esi is pointer to real mode structure with interesting info.
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
172 movq initial_code(%rip),%rax
175 /* SMP bootup changes these two */
178 .quad x86_64_start_kernel
181 .quad init_task_union+THREAD_SIZE-8
186 /* This isn't an x86-64 CPU so hang */
193 .word gdt32_end-gdt_table32
194 .long gdt_table32-__START_KERNEL+0x100000
198 .long reach_long64-__START_KERNEL+0x100000
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)
211 ENTRY(init_level4_pgt)
212 .quad 0x0000000000102007 /* -> level3_ident_pgt */
214 .quad 0x000000000010a007
216 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
217 .quad 0x0000000000103007 /* -> level3_kernel_pgt */
220 /* Kernel does not "know" about 4-th level of page tables. */
221 ENTRY(level3_ident_pgt)
222 .quad 0x0000000000104007
226 ENTRY(level3_kernel_pgt)
228 /* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
229 .quad 0x0000000000105007 /* -> level2_kernel_pgt */
233 ENTRY(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
261 ENTRY(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 */
289 ENTRY(empty_zero_page)
292 ENTRY(empty_bad_page)
295 ENTRY(empty_bad_pte_table)
298 ENTRY(empty_bad_pmd_table)
301 ENTRY(level3_physmem_pgt)
302 .quad 0x0000000000105007 /* -> level2_kernel_pgt (so that __va works even before pagetable_init) */
305 #ifdef CONFIG_ACPI_SLEEP
306 ENTRY(wakeup_level4_pgt)
307 .quad 0x0000000000102007 /* -> level3_ident_pgt */
309 .quad 0x000000000010a007
311 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
312 .quad 0x0000000000103007 /* -> level3_kernel_pgt */
317 .globl SYMBOL_NAME(gdt)
324 .word gdt_end-gdt_table
325 SYMBOL_NAME_LABEL(gdt)
329 .align 64 /* cacheline aligned */
331 .quad 0x0000000000000000 /* This one is magic */
332 .quad 0x0000000000000000 /* unused */
333 .quad 0x00af9a000000ffff /* __KERNEL_CS */
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
341 .align 64 /* cacheline aligned, keep this synchronized with asm/desc.h */
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)
356 /* when you add something here fix constant in desc.h */
359 .fill NR_CPUS*PER_CPU_GDT_SIZE,1,0