; | |
; Copyright (c) 2010, Intel Corporation. All rights reserved.<BR> | |
; 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. | |
; | |
; | |
; Module Name: | |
; | |
; AsmDispatchExecute.asm | |
; | |
; Abstract: | |
; | |
; This is the assembly code to transition from long mode to compatibility mode to execute 32-bit code and then | |
; transit back to long mode. | |
; | |
;------------------------------------------------------------------------------- | |
.code | |
;---------------------------------------------------------------------------- | |
; Procedure: AsmExecute32BitCode | |
; | |
; Input: None | |
; | |
; Output: None | |
; | |
; Prototype: EFI_STATUS | |
; AsmExecute32BitCode ( | |
; IN UINT64 Function, | |
; IN UINT64 Param1, | |
; IN UINT64 Param2, | |
; IN IA32_DESCRIPTOR *InternalGdtr | |
; ); | |
; | |
; | |
; Description: A thunk function to execute 32-bit code in long mode. | |
; | |
;---------------------------------------------------------------------------- | |
AsmExecute32BitCode PROC | |
; | |
; save orignal GDTR and CS | |
; | |
mov rax, ds | |
push rax | |
mov rax, cs | |
push rax | |
sub rsp, 10h | |
sgdt fword ptr [rsp] | |
; | |
; load internal GDT | |
; | |
lgdt fword ptr [r9] | |
; | |
; Save general purpose register and rflag register | |
; | |
pushfq | |
push rdi | |
push rsi | |
push rbp | |
push rbx | |
; | |
; save CR3 | |
; | |
mov rax, cr3 | |
mov rbp, rax | |
; | |
; Prepare the CS and return address for the transition from 32-bit to 64-bit mode | |
; | |
mov rax, 10h ; load long mode selector | |
shl rax, 32 | |
mov r9, OFFSET ReloadCS ;Assume the ReloadCS is under 4G | |
or rax, r9 | |
push rax | |
; | |
; Save parameters for 32-bit function call | |
; | |
mov rax, r8 | |
shl rax, 32 | |
or rax, rdx | |
push rax | |
; | |
; save the 32-bit function entry and the return address into stack which will be | |
; retrieve in compatibility mode. | |
; | |
mov rax, OFFSET ReturnBack ;Assume the ReloadCS is under 4G | |
shl rax, 32 | |
or rax, rcx | |
push rax | |
; | |
; let rax save DS | |
; | |
mov rax, 018h | |
; | |
; Change to Compatible Segment | |
; | |
mov rcx, 08h ; load compatible mode selector | |
shl rcx, 32 | |
mov rdx, OFFSET Compatible ; assume address < 4G | |
or rcx, rdx | |
push rcx | |
retf | |
Compatible: | |
; reload DS/ES/SS to make sure they are correct referred to current GDT | |
mov ds, ax | |
mov es, ax | |
mov ss, ax | |
; | |
; Disable paging | |
; | |
mov rcx, cr0 | |
btc ecx, 31 | |
mov cr0, rcx | |
; | |
; Clear EFER.LME | |
; | |
mov ecx, 0C0000080h | |
rdmsr | |
btc eax, 8 | |
wrmsr | |
; Now we are in protected mode | |
; | |
; Call 32-bit function. Assume the function entry address and parameter value is less than 4G | |
; | |
pop rax ; Here is the function entry | |
; | |
; Now the parameter is at the bottom of the stack, then call in to IA32 function. | |
; | |
jmp rax | |
ReturnBack: | |
pop rcx ; drop param1 | |
pop rcx ; drop param2 | |
; | |
; restore CR4 | |
; | |
mov rax, cr4 | |
bts eax, 5 | |
mov cr4, rax | |
; | |
; restore CR3 | |
; | |
mov eax, ebp | |
mov cr3, rax | |
; | |
; Set EFER.LME to re-enable ia32-e | |
; | |
mov ecx, 0C0000080h | |
rdmsr | |
bts eax, 8 | |
wrmsr | |
; | |
; Enable paging | |
; | |
mov rax, cr0 | |
bts eax, 31 | |
mov cr0, rax | |
; Now we are in compatible mode | |
; | |
; Reload cs register | |
; | |
retf | |
ReloadCS: | |
; | |
; Now we're in Long Mode | |
; | |
; | |
; Restore C register and eax hold the return status from 32-bit function. | |
; Note: Do not touch rax from now which hold the return value from IA32 function | |
; | |
pop rbx | |
pop rbp | |
pop rsi | |
pop rdi | |
popfq | |
; | |
; Switch to orignal GDT and CS. here rsp is pointer to the orignal GDT descriptor. | |
; | |
lgdt fword ptr[rsp] | |
; | |
; drop GDT descriptor in stack | |
; | |
add rsp, 10h | |
; | |
; switch to orignal CS and GDTR | |
; | |
pop r9 ; get CS | |
shl r9, 32 ; rcx[32..47] <- Cs | |
mov rcx, OFFSET @F | |
or rcx, r9 | |
push rcx | |
retf | |
@@: | |
; | |
; Reload original DS/ES/SS | |
; | |
pop rcx | |
mov ds, rcx | |
mov es, rcx | |
mov ss, rcx | |
ret | |
AsmExecute32BitCode ENDP | |
END |