audk/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.nasm

225 lines
4.9 KiB
NASM

;
; Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
; SPDX-License-Identifier: BSD-2-Clause-Patent
;
;
; Module Name:
;
; Thunk64To32.nasm
;
; 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.
;
;-------------------------------------------------------------------------------
DEFAULT REL
SECTION .text
;----------------------------------------------------------------------------
; Procedure: AsmExecute32BitCode
;
; Input: None
;
; Output: None
;
; Prototype: UINT32
; 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.
;
;----------------------------------------------------------------------------
global ASM_PFX(AsmExecute32BitCode)
ASM_PFX(AsmExecute32BitCode):
;
; save IFLAG and disable it
;
pushfq
cli
;
; save original GDTR and CS
;
mov rax, ds
push rax
mov rax, cs
push rax
sub rsp, 0x10
sgdt [rsp]
;
; load internal GDT
;
lgdt [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, dword 0x10 ; load long mode selector
shl rax, 32
lea r9, [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.
;
lea rax, [ReturnBack] ;Assume the ReloadCS is under 4G
shl rax, 32
or rax, rcx
push rax
;
; let rax save DS
;
mov rax, dword 0x18
;
; Change to Compatible Segment
;
mov rcx, dword 0x8 ; load compatible mode selector
shl rcx, 32
lea rdx, [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, 0xC0000080
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:
mov ebx, eax ; save return status
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, 0xC0000080
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
;
mov eax, ebx ; put return status to EAX
pop rbx
pop rbp
pop rsi
pop rdi
popfq
;
; Switch to original GDT and CS. here rsp is pointer to the original GDT descriptor.
;
lgdt [rsp]
;
; drop GDT descriptor in stack
;
add rsp, 0x10
;
; switch to original CS and GDTR
;
pop r9 ; get CS
shl r9, 32 ; rcx[32..47] <- Cs
lea rcx, [.0]
or rcx, r9
push rcx
retf
.0:
;
; Reload original DS/ES/SS
;
pop rcx
mov ds, rcx
mov es, rcx
mov ss, rcx
;
; Restore IFLAG
;
popfq
ret