mirror of https://github.com/acidanthera/audk.git
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
|
||
|
|