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