summaryrefslogtreecommitdiff
path: root/EdkModulePkg/Core/DxeIplPeim/Ia32/LongMode.asm
diff options
context:
space:
mode:
Diffstat (limited to 'EdkModulePkg/Core/DxeIplPeim/Ia32/LongMode.asm')
-rw-r--r--EdkModulePkg/Core/DxeIplPeim/Ia32/LongMode.asm294
1 files changed, 294 insertions, 0 deletions
diff --git a/EdkModulePkg/Core/DxeIplPeim/Ia32/LongMode.asm b/EdkModulePkg/Core/DxeIplPeim/Ia32/LongMode.asm
new file mode 100644
index 0000000000..a241273048
--- /dev/null
+++ b/EdkModulePkg/Core/DxeIplPeim/Ia32/LongMode.asm
@@ -0,0 +1,294 @@
+ TITLE LongMode.asm: Assembly code for the entering long mode
+
+;------------------------------------------------------------------------------
+;*
+;* Copyright (c) 2006, Intel Corporation
+;* All rights reserved. This program and the accompanying materials
+;* are licensed and made available under the terms and conditions of the BSD License
+;* which accompanies this distribution. The full text of the license may be found at
+;* http://opensource.org/licenses/bsd-license.php
+;*
+;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;*
+;* LongMode.asm
+;*
+;* Abstract:
+;*
+;* Transition from 32-bit protected mode EFI environment into x64
+;* 64-bit bit long mode.
+;*
+;------------------------------------------------------------------------------
+
+.686p
+.model flat
+
+;
+; Create the exception handler code in IA32 C code
+;
+
+.code
+.stack
+.MMX
+.XMM
+
+_LoadGo64Gdt PROC Near Public
+ push ebp ; C prolog
+ push edi
+ mov ebp, esp
+ ;
+ ; Disable interrupts
+ ;
+ cli
+ ;
+ ; Reload the selectors
+ ; Note:
+ ; Make the Selectors 64-bit ready
+ ;
+ mov edi, OFFSET gdtr ; Load GDT register
+ mov ax,cs ; Get the selector data from our code image
+ mov es,ax
+ lgdt FWORD PTR es:[edi] ; and update the GDTR
+
+ db 067h
+ db 0eah ; Far Jump Offset:Selector to reload CS
+ dd OFFSET DataSelectorRld; Offset is ensuing instruction boundary
+ dw LINEAR_CODE_SEL ; Selector is our code selector, 10h
+DataSelectorRld::
+ mov ax, SYS_DATA_SEL ; Update the Base for the new selectors, too
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ pop edi
+ pop ebp
+ ret
+_LoadGo64Gdt endp
+
+
+; VOID
+; ActivateLongMode (
+; IN EFI_PHYSICAL_ADDRESS PageTables,
+; IN EFI_PHYSICAL_ADDRESS HobStart,
+; IN EFI_PHYSICAL_ADDRESS Stack,
+; IN EFI_PHYSICAL_ADDRESS PpisNeededByDxeIplEntryPoint,
+; IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint
+; )
+;
+; Input: [ebp][0h] = Original ebp
+; [ebp][4h] = Return address
+; [ebp][8h] = PageTables
+; [ebp][10h] = HobStart
+; [ebp][18h] = Stack
+; [ebp][20h] = CodeEntryPoint1 <--- Call this first (for each call, pass HOB pointer)
+; [ebp][28h] = CodeEntryPoint2 <--- Call this second
+;
+;
+_ActivateLongMode PROC Near Public
+ push ebp ; C prolog
+ mov ebp, esp
+
+ ;
+ ; Use CPUID to determine if the processor supports long mode.
+ ;
+ mov eax, 80000000h ; Extended-function code 8000000h.
+ cpuid ; Is largest extended function
+ cmp eax, 80000000h ; any function > 80000000h?
+ jbe no_long_mode ; If not, no long mode.
+ mov eax, 80000001h ; Extended-function code 8000001h.
+ cpuid ; Now EDX = extended-features flags.
+ bt edx, 29 ; Test if long mode is supported.
+ jnc no_long_mode ; Exit if not supported.
+
+ ;
+ ; Enable the 64-bit page-translation-table entries by
+ ; setting CR4.PAE=1 (this is _required_ before activating
+ ; long mode). Paging is not enabled until after long mode
+ ; is enabled.
+ ;
+ mov eax, cr4
+ bts eax, 5
+ mov cr4, eax
+
+ ;
+ ; Get the long-mode page tables, and initialize the
+ ; 64-bit CR3 (page-table base address) to point to the base
+ ; of the PML4 page table. The PML4 page table must be located
+ ; below 4 Gbytes because only 32 bits of CR3 are loaded when
+ ; the processor is not in 64-bit mode.
+ ;
+ mov eax, [ebp+8h] ; Get Page Tables
+ mov cr3, eax ; Initialize CR3 with PML4 base.
+
+ ;
+ ; Enable long mode (set EFER.LME=1).
+ ;
+ mov ecx, 0c0000080h ; EFER MSR number.
+ rdmsr ; Read EFER.
+ bts eax, 8 ; Set LME=1.
+ wrmsr ; Write EFER.
+
+ ;
+ ; Enable paging to activate long mode (set CR0.PG=1)
+ ;
+
+
+ mov eax, cr0 ; Read CR0.
+ bts eax, 31 ; Set PG=1.
+ mov cr0, eax ; Write CR0.
+ jmp go_to_long_mode
+go_to_long_mode:
+
+ ;
+ ; This is the next instruction after enabling paging. Jump to long mode
+ ;
+ db 067h
+ db 0eah ; Far Jump Offset:Selector to reload CS
+ dd OFFSET in_long_mode; Offset is ensuing instruction boundary
+ dw SYS_CODE64_SEL ; Selector is our code selector, 10h
+in_long_mode::
+ mov ax, SYS_DATA64_SEL
+ mov es, ax
+ mov ss, ax
+ mov ds, ax
+;; jmp $
+
+
+ ;
+ ; We're in long mode, so marshall the arguments to call the
+ ; passed in function pointers
+ ; Recall
+ ; [ebp][10h] = HobStart
+ ; [ebp][18h] = Stack
+ ; [ebp][20h] = PpisNeededByDxeIplEntryPoint <--- Call this first (for each call, pass HOB pointer)
+ ; [ebp][28h] = DxeCoreEntryPoint <--- Call this second
+ ;
+ db 48h
+ mov ebx, [ebp+18h] ; Setup the stack
+ db 48h
+ mov esp, ebx ; On a new stack now
+
+
+;; 00000905 FF D0 call rax
+
+ db 48h
+ mov ecx, [ebp+10h] ; Pass Hob Start in RCX
+ db 48h
+ mov eax, [ebp+28h] ; Get the function pointer for
+ ; DxeCoreEntryPoint into EAX
+
+;; 00000905 FF D0 call rax
+ db 0ffh
+ db 0d0h
+
+ ;
+ ; WE SHOULD NEVER GET HERE!!!!!!!!!!!!!
+ ;
+no_long_mode:
+ jmp no_long_mode
+_ActivateLongMode endp
+
+ align 16
+
+gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit
+ dd OFFSET GDT_BASE ; (GDT base gets set above)
+
+;-----------------------------------------------------------------------------;
+; global descriptor table (GDT)
+;-----------------------------------------------------------------------------;
+
+ align 16
+
+public GDT_BASE
+GDT_BASE:
+; null descriptor
+NULL_SEL equ $-GDT_BASE ; Selector [0]
+ dw 0 ; limit 15:0
+ dw 0 ; base 15:0
+ db 0 ; base 23:16
+ db 0 ; type
+ db 0 ; limit 19:16, flags
+ db 0 ; base 31:24
+
+; linear data segment descriptor
+LINEAR_SEL equ $-GDT_BASE ; Selector [0x8]
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 092h ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; linear code segment descriptor
+LINEAR_CODE_SEL equ $-GDT_BASE ; Selector [0x10]
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 09Fh ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; system data segment descriptor
+SYS_DATA_SEL equ $-GDT_BASE ; Selector [0x18]
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 093h ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; system code segment descriptor
+SYS_CODE_SEL equ $-GDT_BASE ; Selector [0x20]
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 09Ah ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; spare segment descriptor
+SPARE3_SEL equ $-GDT_BASE ; Selector [0x28]
+ dw 0 ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 0 ; present, ring 0, data, expand-up, writable
+ db 0 ; page-granular, 32-bit
+ db 0
+
+;
+; system data segment descriptor
+;
+SYS_DATA64_SEL equ $-GDT_BASE ; Selector [0x30]
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 092h ; P | DPL [1..2] | 1 | 1 | C | R | A
+ db 0CFh ; G | D | L | AVL | Segment [19..16]
+ db 0
+
+;
+; system code segment descriptor
+;
+SYS_CODE64_SEL equ $-GDT_BASE ; Selector [0x38]
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 09Ah ; P | DPL [1..2] | 1 | 1 | C | R | A
+ db 0AFh ; G | D | L | AVL | Segment [19..16]
+ db 0
+
+; spare segment descriptor
+SPARE4_SEL equ $-GDT_BASE ; Selector [0x40]
+ dw 0 ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 0 ; present, ring 0, data, expand-up, writable
+ db 0 ; page-granular, 32-bit
+ db 0
+
+GDT_END:
+
+END
+