Contributed-under: TianoCore Contribution Agreement 1.0 Signed off by: Jiewen Yao <jiewen.yao@intel.com> Reviewed by: Ravi Rangarajan <ravi.p.rangarajan@intel.com> Reviewed by: Maurice Ma <maurice.ma@intel.com> Reviewed by: Giri Mudusuru <giri.p.mudusuru@intel.com> Reviewed by: Liming Gao <liming.gao@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15676 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			231 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			231 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| #
 | |
| # Copyright (c) 2014, 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:
 | |
| #
 | |
| #    Thunk64To32.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.
 | |
| #
 | |
| #-------------------------------------------------------------------------------
 | |
| 
 | |
| #----------------------------------------------------------------------------
 | |
| # 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.
 | |
| #
 | |
| #----------------------------------------------------------------------------
 | |
| 
 | |
| ASM_GLOBAL ASM_PFX(AsmExecute32BitCode)
 | |
| ASM_PFX(AsmExecute32BitCode):
 | |
|     #
 | |
|     # save IFLAG and disable it
 | |
|     #
 | |
|     pushfq
 | |
|     cli
 | |
| 
 | |
|     #
 | |
|     # save orignal GDTR and CS
 | |
|     #
 | |
|     movl    %ds, %eax
 | |
|     push    %rax
 | |
|     movl    %cs, %eax
 | |
|     push    %rax
 | |
|     subq    $0x10, %rsp
 | |
|     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
 | |
|     #
 | |
|     movq    %cr3, %rax
 | |
|     movq    %rax, %rbp
 | |
| 
 | |
|     #
 | |
|     # Prepare the CS and return address for the transition from 32-bit to 64-bit mode
 | |
|     #
 | |
|     movq    $0x10, %rax              # load long mode selector
 | |
|     shl     $32, %rax
 | |
|     lea     ReloadCS(%rip), %r9   #Assume the ReloadCS is under 4G
 | |
|     orq     %r9, %rax
 | |
|     push    %rax
 | |
|     #
 | |
|     # Save parameters for 32-bit function call
 | |
|     #
 | |
|     movq    %r8, %rax
 | |
|     shl     $32, %rax
 | |
|     orq     %rdx, %rax
 | |
|     push    %rax
 | |
|     #
 | |
|     # save the 32-bit function entry and the return address into stack which will be
 | |
|     # retrieve in compatibility mode.
 | |
|     #
 | |
|     lea     ReturnBack(%rip), %rax   #Assume the ReloadCS is under 4G
 | |
|     shl     $32, %rax
 | |
|     orq     %rcx, %rax
 | |
|     push    %rax
 | |
| 
 | |
|     #
 | |
|     # let rax save DS
 | |
|     #
 | |
|     movq    $0x18, %rax
 | |
| 
 | |
|     #
 | |
|     # Change to Compatible Segment
 | |
|     #
 | |
|     movq    $8, %rcx               # load compatible mode selector
 | |
|     shl     $32, %rcx
 | |
|     lea     Compatible(%rip), %rdx # assume address < 4G
 | |
|     orq     %rdx, %rcx
 | |
|     push    %rcx
 | |
|     .byte   0xcb                # retf
 | |
| 
 | |
| Compatible:
 | |
|     # reload DS/ES/SS to make sure they are correct referred to current GDT
 | |
|     movw    %ax, %ds
 | |
|     movw    %ax, %es
 | |
|     movw    %ax, %ss
 | |
| 
 | |
|     #
 | |
|     # Disable paging
 | |
|     #
 | |
|     movq    %cr0, %rcx
 | |
|     btc     $31, %ecx
 | |
|     movq    %rcx, %cr0
 | |
|     #
 | |
|     # Clear EFER.LME
 | |
|     #
 | |
|     movl    $0xC0000080, %ecx
 | |
|     rdmsr
 | |
|     btc     $8, %eax
 | |
|     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:
 | |
|     movl  %eax, %ebx            # save return status
 | |
|     pop   %rcx                  # drop param1
 | |
|     pop   %rcx                  # drop param2
 | |
| 
 | |
|     #
 | |
|     # restore CR4
 | |
|     #
 | |
|     movq    %cr4, %rax
 | |
|     bts     $5, %eax
 | |
|     movq    %rax, %cr4
 | |
| 
 | |
|     #
 | |
|     # restore CR3
 | |
|     #
 | |
|     movl    %ebp, %eax
 | |
|     movq    %rax, %cr3
 | |
| 
 | |
|     #
 | |
|     # Set EFER.LME to re-enable ia32-e
 | |
|     #
 | |
|     movl    $0xC0000080, %ecx
 | |
|     rdmsr
 | |
|     bts     $8, %eax
 | |
|     wrmsr
 | |
|     #
 | |
|     # Enable paging
 | |
|     #
 | |
|     movq    %cr0, %rax
 | |
|     bts     $31, %eax
 | |
|     mov     %rax, %cr0
 | |
| # Now we are in compatible mode
 | |
| 
 | |
|     #
 | |
|     # Reload cs register
 | |
|     #
 | |
|     .byte   0xcb                # 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
 | |
|     #
 | |
|     movl    %ebx, %eax # put return status to EAX
 | |
|     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    (%rsp)
 | |
|     #
 | |
|     # drop GDT descriptor in stack
 | |
|     #
 | |
|     addq    $0x10, %rsp
 | |
|     #
 | |
|     # switch to orignal CS and GDTR
 | |
|     #
 | |
|     pop     %r9                 # get  CS
 | |
|     shl     $32, %r9            # rcx[32..47] <- Cs
 | |
|     lea     ReturnToLongMode(%rip), %rcx
 | |
|     orq     %r9, %rcx
 | |
|     push    %rcx
 | |
|     .byte   0xcb                # retf
 | |
| ReturnToLongMode:
 | |
|     #
 | |
|     # Reload original DS/ES/SS
 | |
|     #
 | |
|     pop     %rcx
 | |
|     movl    %ecx, %ds
 | |
|     movl    %ecx, %es
 | |
|     movl    %ecx, %ss
 | |
| 
 | |
|     #
 | |
|     # Restore IFLAG
 | |
|     #
 | |
|     popfq
 | |
| 
 | |
|     ret
 | |
| 
 |