# # Copyright (c) 2010, Intel Corporation. All rights reserved.
# 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: # # AsmDispatchExecute.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: EFI_STATUS # 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 orignal GDTR and CS # movq %ds, %rax push %rax movq %cs, %rax 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 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: 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 # 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 # 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 retf ReturnToLongMode: # # Reload original DS/ES/SS # pop %rcx movq %rcx, %ds movq %rcx, %es movq %rcx, %ss ret