mirror of
				https://gitlab.com/qemu-project/edk2.git
				synced 2025-10-30 07:56:39 +08:00 
			
		
		
		
	 786ae76884
			
		
	
	786ae76884
	
	
	
		
			
			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
 | |
| 
 |