]>
Commit | Line | Data |
---|---|---|
e20ee534 LG |
1 | TITLE LongMode.asm: Assembly code for the entering long mode |
2 | ||
3 | ;------------------------------------------------------------------------------ | |
4 | ;* | |
5 | ;* Copyright (c) 2006, Intel Corporation | |
6 | ;* All rights reserved. This program and the accompanying materials | |
7 | ;* are licensed and made available under the terms and conditions of the BSD License | |
8 | ;* which accompanies this distribution. The full text of the license may be found at | |
9 | ;* http://opensource.org/licenses/bsd-license.php | |
10 | ;* | |
11 | ;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
12 | ;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
13 | ;* | |
14 | ;* LongMode.asm | |
15 | ;* | |
16 | ;* Abstract: | |
17 | ;* | |
18 | ;* Transition from 32-bit protected mode EFI environment into x64 | |
19 | ;* 64-bit bit long mode. | |
20 | ;* | |
21 | ;------------------------------------------------------------------------------ | |
22 | ||
23 | .686p | |
24 | .model flat | |
25 | ||
26 | ; | |
27 | ; Create the exception handler code in IA32 C code | |
28 | ; | |
29 | ||
30 | .code | |
31 | .stack | |
32 | .MMX | |
33 | .XMM | |
34 | ||
35 | _LoadGo64Gdt PROC Near Public | |
36 | push ebp ; C prolog | |
37 | push edi | |
38 | mov ebp, esp | |
39 | ; | |
40 | ; Disable interrupts | |
41 | ; | |
42 | cli | |
43 | ; | |
44 | ; Reload the selectors | |
45 | ; Note: | |
46 | ; Make the Selectors 64-bit ready | |
47 | ; | |
48 | mov edi, OFFSET gdtr ; Load GDT register | |
49 | mov ax,cs ; Get the selector data from our code image | |
50 | mov es,ax | |
51 | lgdt FWORD PTR es:[edi] ; and update the GDTR | |
52 | ||
53 | db 067h | |
54 | db 0eah ; Far Jump Offset:Selector to reload CS | |
55 | dd OFFSET DataSelectorRld; Offset is ensuing instruction boundary | |
56 | dw LINEAR_CODE_SEL ; Selector is our code selector, 10h | |
57 | DataSelectorRld:: | |
58 | mov ax, SYS_DATA_SEL ; Update the Base for the new selectors, too | |
59 | mov ds, ax | |
60 | mov es, ax | |
61 | mov fs, ax | |
62 | mov gs, ax | |
63 | mov ss, ax | |
64 | ||
65 | pop edi | |
66 | pop ebp | |
67 | ret | |
68 | _LoadGo64Gdt endp | |
69 | ||
70 | ||
71 | ; VOID | |
72 | ; ActivateLongMode ( | |
73 | ; IN EFI_PHYSICAL_ADDRESS PageTables, | |
74 | ; IN EFI_PHYSICAL_ADDRESS HobStart, | |
75 | ; IN EFI_PHYSICAL_ADDRESS Stack, | |
76 | ; IN EFI_PHYSICAL_ADDRESS PpisNeededByDxeIplEntryPoint, | |
77 | ; IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint | |
78 | ; ) | |
79 | ; | |
80 | ; Input: [ebp][0h] = Original ebp | |
81 | ; [ebp][4h] = Return address | |
82 | ; [ebp][8h] = PageTables | |
83 | ; [ebp][10h] = HobStart | |
84 | ; [ebp][18h] = Stack | |
85 | ; [ebp][20h] = CodeEntryPoint1 <--- Call this first (for each call, pass HOB pointer) | |
86 | ; [ebp][28h] = CodeEntryPoint2 <--- Call this second | |
87 | ; | |
88 | ; | |
89 | _ActivateLongMode PROC Near Public | |
90 | push ebp ; C prolog | |
91 | mov ebp, esp | |
92 | ||
93 | ; | |
94 | ; Use CPUID to determine if the processor supports long mode. | |
95 | ; | |
96 | mov eax, 80000000h ; Extended-function code 8000000h. | |
97 | cpuid ; Is largest extended function | |
98 | cmp eax, 80000000h ; any function > 80000000h? | |
99 | jbe no_long_mode ; If not, no long mode. | |
100 | mov eax, 80000001h ; Extended-function code 8000001h. | |
101 | cpuid ; Now EDX = extended-features flags. | |
102 | bt edx, 29 ; Test if long mode is supported. | |
103 | jnc no_long_mode ; Exit if not supported. | |
104 | ||
105 | ; | |
106 | ; Enable the 64-bit page-translation-table entries by | |
107 | ; setting CR4.PAE=1 (this is _required_ before activating | |
108 | ; long mode). Paging is not enabled until after long mode | |
109 | ; is enabled. | |
110 | ; | |
111 | mov eax, cr4 | |
112 | bts eax, 5 | |
113 | mov cr4, eax | |
114 | ||
115 | ; | |
116 | ; Get the long-mode page tables, and initialize the | |
117 | ; 64-bit CR3 (page-table base address) to point to the base | |
118 | ; of the PML4 page table. The PML4 page table must be located | |
119 | ; below 4 Gbytes because only 32 bits of CR3 are loaded when | |
120 | ; the processor is not in 64-bit mode. | |
121 | ; | |
122 | mov eax, [ebp+8h] ; Get Page Tables | |
123 | mov cr3, eax ; Initialize CR3 with PML4 base. | |
124 | ||
125 | ; | |
126 | ; Enable long mode (set EFER.LME=1). | |
127 | ; | |
128 | mov ecx, 0c0000080h ; EFER MSR number. | |
129 | rdmsr ; Read EFER. | |
130 | bts eax, 8 ; Set LME=1. | |
131 | wrmsr ; Write EFER. | |
132 | ||
133 | ; | |
134 | ; Enable paging to activate long mode (set CR0.PG=1) | |
135 | ; | |
136 | ||
137 | ||
138 | mov eax, cr0 ; Read CR0. | |
139 | bts eax, 31 ; Set PG=1. | |
140 | mov cr0, eax ; Write CR0. | |
141 | jmp go_to_long_mode | |
142 | go_to_long_mode: | |
143 | ||
144 | ; | |
145 | ; This is the next instruction after enabling paging. Jump to long mode | |
146 | ; | |
147 | db 067h | |
148 | db 0eah ; Far Jump Offset:Selector to reload CS | |
149 | dd OFFSET in_long_mode; Offset is ensuing instruction boundary | |
150 | dw SYS_CODE64_SEL ; Selector is our code selector, 10h | |
151 | in_long_mode:: | |
152 | mov ax, SYS_DATA64_SEL | |
153 | mov es, ax | |
154 | mov ss, ax | |
155 | mov ds, ax | |
156 | ;; jmp $ | |
157 | ||
158 | ||
159 | ; | |
160 | ; We're in long mode, so marshall the arguments to call the | |
161 | ; passed in function pointers | |
162 | ; Recall | |
163 | ; [ebp][10h] = HobStart | |
164 | ; [ebp][18h] = Stack | |
165 | ; [ebp][20h] = PpisNeededByDxeIplEntryPoint <--- Call this first (for each call, pass HOB pointer) | |
166 | ; [ebp][28h] = DxeCoreEntryPoint <--- Call this second | |
167 | ; | |
168 | db 48h | |
169 | mov ebx, [ebp+18h] ; Setup the stack | |
170 | db 48h | |
171 | mov esp, ebx ; On a new stack now | |
172 | ||
173 | ||
174 | ;; 00000905 FF D0 call rax | |
175 | ||
176 | db 48h | |
177 | mov ecx, [ebp+10h] ; Pass Hob Start in RCX | |
178 | db 48h | |
179 | mov eax, [ebp+28h] ; Get the function pointer for | |
180 | ; DxeCoreEntryPoint into EAX | |
181 | ||
182 | ;; 00000905 FF D0 call rax | |
183 | db 0ffh | |
184 | db 0d0h | |
185 | ||
186 | ; | |
187 | ; WE SHOULD NEVER GET HERE!!!!!!!!!!!!! | |
188 | ; | |
189 | no_long_mode: | |
190 | jmp no_long_mode | |
191 | _ActivateLongMode endp | |
192 | ||
193 | align 16 | |
194 | ||
195 | gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit | |
196 | dd OFFSET GDT_BASE ; (GDT base gets set above) | |
197 | ||
198 | ;-----------------------------------------------------------------------------; | |
199 | ; global descriptor table (GDT) | |
200 | ;-----------------------------------------------------------------------------; | |
201 | ||
202 | align 16 | |
203 | ||
204 | public GDT_BASE | |
205 | GDT_BASE: | |
206 | ; null descriptor | |
207 | NULL_SEL equ $-GDT_BASE ; Selector [0] | |
208 | dw 0 ; limit 15:0 | |
209 | dw 0 ; base 15:0 | |
210 | db 0 ; base 23:16 | |
211 | db 0 ; type | |
212 | db 0 ; limit 19:16, flags | |
213 | db 0 ; base 31:24 | |
214 | ||
215 | ; linear data segment descriptor | |
216 | LINEAR_SEL equ $-GDT_BASE ; Selector [0x8] | |
217 | dw 0FFFFh ; limit 0xFFFFF | |
218 | dw 0 ; base 0 | |
219 | db 0 | |
220 | db 092h ; present, ring 0, data, expand-up, writable | |
221 | db 0CFh ; page-granular, 32-bit | |
222 | db 0 | |
223 | ||
224 | ; linear code segment descriptor | |
225 | LINEAR_CODE_SEL equ $-GDT_BASE ; Selector [0x10] | |
226 | dw 0FFFFh ; limit 0xFFFFF | |
227 | dw 0 ; base 0 | |
228 | db 0 | |
229 | db 09Fh ; present, ring 0, data, expand-up, writable | |
230 | db 0CFh ; page-granular, 32-bit | |
231 | db 0 | |
232 | ||
233 | ; system data segment descriptor | |
234 | SYS_DATA_SEL equ $-GDT_BASE ; Selector [0x18] | |
235 | dw 0FFFFh ; limit 0xFFFFF | |
236 | dw 0 ; base 0 | |
237 | db 0 | |
238 | db 093h ; present, ring 0, data, expand-up, writable | |
239 | db 0CFh ; page-granular, 32-bit | |
240 | db 0 | |
241 | ||
242 | ; system code segment descriptor | |
243 | SYS_CODE_SEL equ $-GDT_BASE ; Selector [0x20] | |
244 | dw 0FFFFh ; limit 0xFFFFF | |
245 | dw 0 ; base 0 | |
246 | db 0 | |
247 | db 09Ah ; present, ring 0, data, expand-up, writable | |
248 | db 0CFh ; page-granular, 32-bit | |
249 | db 0 | |
250 | ||
251 | ; spare segment descriptor | |
252 | SPARE3_SEL equ $-GDT_BASE ; Selector [0x28] | |
253 | dw 0 ; limit 0xFFFFF | |
254 | dw 0 ; base 0 | |
255 | db 0 | |
256 | db 0 ; present, ring 0, data, expand-up, writable | |
257 | db 0 ; page-granular, 32-bit | |
258 | db 0 | |
259 | ||
260 | ; | |
261 | ; system data segment descriptor | |
262 | ; | |
263 | SYS_DATA64_SEL equ $-GDT_BASE ; Selector [0x30] | |
264 | dw 0FFFFh ; limit 0xFFFFF | |
265 | dw 0 ; base 0 | |
266 | db 0 | |
267 | db 092h ; P | DPL [1..2] | 1 | 1 | C | R | A | |
268 | db 0CFh ; G | D | L | AVL | Segment [19..16] | |
269 | db 0 | |
270 | ||
271 | ; | |
272 | ; system code segment descriptor | |
273 | ; | |
274 | SYS_CODE64_SEL equ $-GDT_BASE ; Selector [0x38] | |
275 | dw 0FFFFh ; limit 0xFFFFF | |
276 | dw 0 ; base 0 | |
277 | db 0 | |
278 | db 09Ah ; P | DPL [1..2] | 1 | 1 | C | R | A | |
279 | db 0AFh ; G | D | L | AVL | Segment [19..16] | |
280 | db 0 | |
281 | ||
282 | ; spare segment descriptor | |
283 | SPARE4_SEL equ $-GDT_BASE ; Selector [0x40] | |
284 | dw 0 ; limit 0xFFFFF | |
285 | dw 0 ; base 0 | |
286 | db 0 | |
287 | db 0 ; present, ring 0, data, expand-up, writable | |
288 | db 0 ; page-granular, 32-bit | |
289 | db 0 | |
290 | ||
291 | GDT_END: | |
292 | ||
e20ee534 LG |
293 | END |
294 |