1 TITLE LongMode.asm: Assembly code for the entering long mode
3 ;------------------------------------------------------------------------------
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
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.
18 ;* Transition from 32-bit protected mode EFI environment into x64
19 ;* 64-bit bit long mode.
21 ;------------------------------------------------------------------------------
27 ; Create the exception handler code in IA32 C code
35 _LoadGo64Gdt PROC Near Public
44 ; Reload the selectors
46 ; Make the Selectors 64-bit ready
48 mov edi, OFFSET gdtr ; Load GDT register
49 mov ax,cs ; Get the selector data from our code image
51 lgdt FWORD PTR es:[edi] ; and update the GDTR
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
58 mov ax, SYS_DATA_SEL ; Update the Base for the new selectors, too
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
80 ; Input: [ebp][0h] = Original ebp
81 ; [ebp][4h] = Return address
82 ; [ebp][8h] = PageTables
83 ; [ebp][10h] = HobStart
85 ; [ebp][20h] = CodeEntryPoint1 <--- Call this first (for each call, pass HOB pointer)
86 ; [ebp][28h] = CodeEntryPoint2 <--- Call this second
89 _ActivateLongMode PROC Near Public
94 ; Use CPUID to determine if the processor supports long mode.
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.
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
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.
122 mov eax, [ebp+8h] ; Get Page Tables
123 mov cr3, eax ; Initialize CR3 with PML4 base.
126 ; Enable long mode (set EFER.LME=1).
128 mov ecx, 0c0000080h ; EFER MSR number.
130 bts eax, 8 ; Set LME=1.
134 ; Enable paging to activate long mode (set CR0.PG=1)
138 mov eax, cr0 ; Read CR0.
139 bts eax, 31 ; Set PG=1.
140 mov cr0, eax ; Write CR0.
145 ; This is the next instruction after enabling paging. Jump to long mode
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
152 mov ax, SYS_DATA64_SEL
160 ; We're in long mode, so marshall the arguments to call the
161 ; passed in function pointers
163 ; [ebp][10h] = HobStart
165 ; [ebp][20h] = PpisNeededByDxeIplEntryPoint <--- Call this first (for each call, pass HOB pointer)
166 ; [ebp][28h] = DxeCoreEntryPoint <--- Call this second
169 mov ebx, [ebp+18h] ; Setup the stack
171 mov esp, ebx ; On a new stack now
174 ;; 00000905 FF D0 call rax
177 mov ecx, [ebp+10h] ; Pass Hob Start in RCX
179 mov eax, [ebp+28h] ; Get the function pointer for
180 ; DxeCoreEntryPoint into EAX
182 ;; 00000905 FF D0 call rax
187 ; WE SHOULD NEVER GET HERE!!!!!!!!!!!!!
191 _ActivateLongMode endp
195 gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit
196 dd OFFSET GDT_BASE ; (GDT base gets set above)
198 ;-----------------------------------------------------------------------------;
199 ; global descriptor table (GDT)
200 ;-----------------------------------------------------------------------------;
207 NULL_SEL equ $-GDT_BASE ; Selector [0]
212 db 0 ; limit 19:16, flags
215 ; linear data segment descriptor
216 LINEAR_SEL equ $-GDT_BASE ; Selector [0x8]
217 dw 0FFFFh ; limit 0xFFFFF
220 db 092h ; present, ring 0, data, expand-up, writable
221 db 0CFh ; page-granular, 32-bit
224 ; linear code segment descriptor
225 LINEAR_CODE_SEL equ $-GDT_BASE ; Selector [0x10]
226 dw 0FFFFh ; limit 0xFFFFF
229 db 09Fh ; present, ring 0, data, expand-up, writable
230 db 0CFh ; page-granular, 32-bit
233 ; system data segment descriptor
234 SYS_DATA_SEL equ $-GDT_BASE ; Selector [0x18]
235 dw 0FFFFh ; limit 0xFFFFF
238 db 093h ; present, ring 0, data, expand-up, writable
239 db 0CFh ; page-granular, 32-bit
242 ; system code segment descriptor
243 SYS_CODE_SEL equ $-GDT_BASE ; Selector [0x20]
244 dw 0FFFFh ; limit 0xFFFFF
247 db 09Ah ; present, ring 0, data, expand-up, writable
248 db 0CFh ; page-granular, 32-bit
251 ; spare segment descriptor
252 SPARE3_SEL equ $-GDT_BASE ; Selector [0x28]
256 db 0 ; present, ring 0, data, expand-up, writable
257 db 0 ; page-granular, 32-bit
261 ; system data segment descriptor
263 SYS_DATA64_SEL equ $-GDT_BASE ; Selector [0x30]
264 dw 0FFFFh ; limit 0xFFFFF
267 db 092h ; P | DPL [1..2] | 1 | 1 | C | R | A
268 db 0CFh ; G | D | L | AVL | Segment [19..16]
272 ; system code segment descriptor
274 SYS_CODE64_SEL equ $-GDT_BASE ; Selector [0x38]
275 dw 0FFFFh ; limit 0xFFFFF
278 db 09Ah ; P | DPL [1..2] | 1 | 1 | C | R | A
279 db 0AFh ; G | D | L | AVL | Segment [19..16]
282 ; spare segment descriptor
283 SPARE4_SEL equ $-GDT_BASE ; Selector [0x40]
287 db 0 ; present, ring 0, data, expand-up, writable
288 db 0 ; page-granular, 32-bit