import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / arch / x86_64 / kernel / head.S
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 */ 
30 startup_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
86 1:
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
109 reach_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
125 second:         
126         movl    $0x100F10, %eax
127         /* Finally jump in 64bit mode */
128         ljmp    *(%eax)
129
130         .code64
131         .org 0x100      
132 reach_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
177 initial_code:
178         .quad   x86_64_start_kernel
179         .globl init_rsp
180 init_rsp:
181         .quad  init_task_union+THREAD_SIZE-8
182
183         
184 .code32
185 ENTRY(no_long_mode)
186         /* This isn't an x86-64 CPU so hang */
187 1:
188         jmp     1b      
189         
190         .globl pGDT32   
191 .org 0xf00
192 pGDT32:
193         .word   gdt32_end-gdt_table32
194         .long   gdt_table32-__START_KERNEL+0x100000
195
196 .org 0xf10      
197 ljumpvector:
198         .long   reach_long64-__START_KERNEL+0x100000
199         .word   __KERNEL_CS
200
201 ENTRY(stext)
202 ENTRY(_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
211 ENTRY(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. */
221 ENTRY(level3_ident_pgt)
222         .quad   0x0000000000104007
223         .fill   511,8,0
224         
225 .org 0x3000
226 ENTRY(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
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
257 temp_boot_pmds:
258         .fill   492,8,0
259                 
260 .org 0x5000
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 */
286         .fill   492,8,0
287
288 .org 0x6000
289 ENTRY(empty_zero_page)
290
291 .org 0x7000
292 ENTRY(empty_bad_page)
293
294 .org 0x8000
295 ENTRY(empty_bad_pte_table)
296
297 .org 0x9000
298 ENTRY(empty_bad_pmd_table)
299
300 .org 0xa000
301 ENTRY(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
306 ENTRY(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
323 pGDT64:
324         .word   gdt_end-gdt_table
325 SYMBOL_NAME_LABEL(gdt)
326         .quad   gdt_table
327         
328
329 .align 64 /* cacheline aligned */
330 ENTRY(gdt_table32)
331         .quad   0x0000000000000000      /* This one is magic */
332         .quad   0x0000000000000000      /* unused */
333         .quad   0x00af9a000000ffff      /* __KERNEL_CS */
334 gdt32_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 */
342 ENTRY(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
358 gdt_cpu_table:  
359         .fill NR_CPUS*PER_CPU_GDT_SIZE,1,0
360 gdt_end:        
361         .globl gdt_end
362
363         .align  64
364 ENTRY(idt_table)        
365         .rept   256
366         .quad   0
367         .quad   0
368         .endr