Blame view

arch/x86/kernel/trampoline_64.S 4.23 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /*
   *
   *	Trampoline.S	Derived from Setup.S by Linus Torvalds
   *
   *	4 Jan 1997 Michael Chastain: changed to gnu as.
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
6
   *	15 Sept 2005 Eric Biederman: 64bit PIC support
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
   *
   *	Entry: CS:IP point to the start of our code, we are 
   *	in real mode with no stack, but the rest of the 
   *	trampoline page to make our stack and everything else
   *	is a mystery.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
16
17
   *	On entry to trampoline_data, the processor is in real mode
   *	with 16-bit addressing and 16-bit data.  CS has some value
   *	and IP is zero.  Thus, data addresses need to be absolute
   *	(no relocation) and are taken with regard to r_base.
   *
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
18
19
20
21
   *	With the addition of trampoline_level4_pgt this code can
   *	now enter a 64bit kernel that lives at arbitrary 64bit
   *	physical addresses.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
   *	If you work on this file, check the object module with objdump
   *	--full-contents --reloc to make sure there are no relocation
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
24
   *	entries.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
   */
  
  #include <linux/linkage.h>
5f6856399   Jan Beulich   x86: cpuinit-anno...
28
  #include <linux/init.h>
0341c14da   Jeremy Fitzhardinge   x86: use _types.h...
29
30
  #include <asm/pgtable_types.h>
  #include <asm/page_types.h>
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
31
32
  #include <asm/msr.h>
  #include <asm/segment.h>
0a1e8869f   Cyrill Gorcunov   x86: trampoline_6...
33
  #include <asm/processor-flags.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34

4822b7fc6   H. Peter Anvin   x86, trampoline: ...
35
36
37
  	.section ".x86_trampoline","a"
  	.balign PAGE_SIZE
  	.code16
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
  
  ENTRY(trampoline_data)
  r_base = .
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
41
  	cli			# We should be safe anyway
0a1e8869f   Cyrill Gorcunov   x86: trampoline_6...
42
  	wbinvd
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
  	mov	%cs, %ax	# Code and data in the same place
  	mov	%ax, %ds
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
45
46
  	mov	%ax, %es
  	mov	%ax, %ss
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48

4822b7fc6   H. Peter Anvin   x86, trampoline: ...
49
  	movl	$0xA5A5A5A5, trampoline_status - r_base
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  				# write marker for master knows we're running
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
51
52
53
54
  					# Setup stack
  	movw	$(trampoline_stack_end - r_base), %sp
  
  	call	verify_cpu		# Verify the cpu supports long mode
a4831e08b   Vivek Goyal   [PATCH] x86-64: M...
55
56
  	testl   %eax, %eax		# Check for return code
  	jnz	no_longmode
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
57
58
59
60
  
  	mov	%cs, %ax
  	movzx	%ax, %esi		# Find the 32bit trampoline location
  	shll	$4, %esi
4822b7fc6   H. Peter Anvin   x86, trampoline: ...
61
62
63
64
65
66
67
  					# Fixup the absolute vectors
  	leal	(startup_32 - r_base)(%esi), %eax
  	movl	%eax, startup_32_vector - r_base
  	leal	(startup_64 - r_base)(%esi), %eax
  	movl	%eax, startup_64_vector - r_base
  	leal	(tgdt - r_base)(%esi), %eax
  	movl	%eax, (tgdt + 2 - r_base)
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
68

983d5dbdb   Vivek Goyal   [PATCH] x86_64: F...
69
70
71
72
73
74
  	/*
  	 * GDT tables in non default location kernel can be beyond 16MB and
  	 * lgdt will not be able to load the address as in real mode default
  	 * operand size is 16bit. Use lgdtl instead to force operand size
  	 * to 32 bit.
  	 */
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
75
76
  	lidtl	tidt - r_base	# load idt with 0, 0
  	lgdtl	tgdt - r_base	# load gdt with whatever is appropriate
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77

0a1e8869f   Cyrill Gorcunov   x86: trampoline_6...
78
79
  	mov	$X86_CR0_PE, %ax	# protected mode (PE) bit
  	lmsw	%ax			# into protected mode
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
80
81
82
83
84
85
86
87
88
  
  	# flush prefetch and jump to startup_32
  	ljmpl	*(startup_32_vector - r_base)
  
  	.code32
  	.balign 4
  startup_32:
  	movl	$__KERNEL_DS, %eax	# Initialize the %ds segment register
  	movl	%eax, %ds
0a1e8869f   Cyrill Gorcunov   x86: trampoline_6...
89
90
  	movl	$X86_CR4_PAE, %eax
  	movl	%eax, %cr4		# Enable PAE mode
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
91
92
93
94
95
96
97
98
99
  
  					# Setup trampoline 4 level pagetables
  	leal	(trampoline_level4_pgt - r_base)(%esi), %eax
  	movl	%eax, %cr3
  
  	movl	$MSR_EFER, %ecx
  	movl	$(1 << _EFER_LME), %eax	# Enable Long Mode
  	xorl	%edx, %edx
  	wrmsr
0a1e8869f   Cyrill Gorcunov   x86: trampoline_6...
100
101
102
  	# Enable paging and in turn activate Long Mode
  	# Enable protected mode
  	movl	$(X86_CR0_PG | X86_CR0_PE), %eax
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  	movl	%eax, %cr0
  
  	/*
  	 * At this point we're in long mode but in 32bit compatibility mode
  	 * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
  	 * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use
  	 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
  	 */
  	ljmp	*(startup_64_vector - r_base)(%esi)
  
  	.code64
  	.balign 4
  startup_64:
  	# Now jump into the kernel using virtual addresses
  	movq	$secondary_startup_64, %rax
  	jmp	*%rax
  
  	.code16
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
121
122
123
  no_longmode:
  	hlt
  	jmp no_longmode
c5cbac694   Kees Cook   x86, cpu: Rename ...
124
  #include "verify_cpu.S"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125

4822b7fc6   H. Peter Anvin   x86, trampoline: ...
126
  	.balign 4
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
  	# Careful these need to be in the same 64K segment as the above;
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
128
  tidt:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
  	.word	0			# idt limit = 0
  	.word	0, 0			# idt base = 0L
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  	# Duplicate the global descriptor table
  	# so the kernel can live anywhere
  	.balign 4
  tgdt:
  	.short	tgdt_end - tgdt		# gdt limit
  	.long	tgdt - r_base
  	.short 0
  	.quad	0x00cf9b000000ffff	# __KERNEL32_CS
  	.quad	0x00af9b000000ffff	# __KERNEL_CS
  	.quad	0x00cf93000000ffff	# __KERNEL_DS
  tgdt_end:
  
  	.balign 4
  startup_32_vector:
  	.long	startup_32 - r_base
  	.word	__KERNEL32_CS, 0
  
  	.balign 4
  startup_64_vector:
  	.long	startup_64 - r_base
  	.word	__KERNEL_CS, 0
4822b7fc6   H. Peter Anvin   x86, trampoline: ...
152
  	.balign 4
4822b7fc6   H. Peter Anvin   x86, trampoline: ...
153
154
  ENTRY(trampoline_status)
  	.long	0
90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
155
156
157
158
159
160
161
  trampoline_stack:
  	.org 0x1000
  trampoline_stack_end:
  ENTRY(trampoline_level4_pgt)
  	.quad	level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
  	.fill	510,8,0
  	.quad	level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162

90b1c2085   Vivek Goyal   [PATCH] x86-64: 6...
163
  ENTRY(trampoline_end)