When enter FSP, bootloader need to save fs and gs, when back to bootloader, bootloader need to restore fs and gs, so it could avoid bootloader access wrong data segment when usging fs and gs. Signed-off-by: Hongbin1 Zhang <hongbin1.zhang@intel.com> Cc: Chasel Chiu <chasel.chiu@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Duggapu Chinni B <chinni.b.duggapu@intel.com> Cc: Star Zeng <star.zeng@intel.com> Cc: Ted Kuo <ted.kuo@intel.com> Cc: Ashraf Ali S <ashraf.ali.s@intel.com> Cc: Ray Ni <ray.ni@intel.com>
229 lines
5.0 KiB
NASM
229 lines
5.0 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/FS/GS/SS to make sure they are correct referred to current GDT
|
|
mov ds, ax
|
|
mov es, ax
|
|
mov fs, ax
|
|
mov gs, 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/FS/GS/SS
|
|
;
|
|
pop rcx
|
|
mov ds, rcx
|
|
mov es, rcx
|
|
mov fs, rcx
|
|
mov gs, rcx
|
|
mov ss, rcx
|
|
|
|
;
|
|
; Restore IFLAG
|
|
;
|
|
popfq
|
|
|
|
ret
|
|
|