#/** @file # # This code provides low level routines that support the Virtual Machine # for option ROMs. # # Copyright (c) 2007 - 2014, 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. # #**/ #--------------------------------------------------------------------------- # Equate files needed. #--------------------------------------------------------------------------- ASM_GLOBAL ASM_PFX(CopyMem); ASM_GLOBAL ASM_PFX(EbcInterpret); ASM_GLOBAL ASM_PFX(ExecuteEbcImageEntryPoint); #**************************************************************************** # EbcLLCALLEX # # This function is called to execute an EBC CALLEX instruction. # This instruction requires that we thunk out to external native # code. For x64, we switch stacks, copy the arguments to the stack # and jump to the specified function. # On return, we restore the stack pointer to its original location. # # Destroys no working registers. #**************************************************************************** # VOID EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr) ASM_GLOBAL ASM_PFX(EbcLLCALLEXNative); ASM_PFX(EbcLLCALLEXNative): push %rbp push %rbx mov %rsp, %rbp # Function prolog # Copy FuncAddr to a preserved register. mov %rcx, %rbx # Set stack pointer to new value sub %rdx, %r8 # # Fix X64 native function call prolog. Prepare space for at least 4 arguments, # even if the native function's arguments are less than 4. # # From MSDN x64 Software Conventions, Overview of x64 Calling Conventions: # "The caller is responsible for allocating space for parameters to the # callee, and must always allocate sufficient space for the 4 register # parameters, even if the callee doesn't have that many parameters. # This aids in the simplicity of supporting C unprototyped functions, # and vararg C/C++ functions." # cmp $0x20, %r8 jae skip_expansion mov $0x20, %r8 skip_expansion: sub %r8, %rsp # # Fix X64 native function call 16-byte alignment. # # From MSDN x64 Software Conventions, Stack Usage: # "The stack will always be maintained 16-byte aligned, except within # the prolog (for example, after the return address is pushed)." # and $0xFFFFFFFFFFFFFFF0, %rsp mov %rsp, %rcx sub $0x20, %rsp call ASM_PFX(CopyMem) add $0x20, %rsp # Considering the worst case, load 4 potiential arguments # into registers. mov (%rsp), %rcx mov 0x8(%rsp), %rdx mov 0x10(%rsp), %r8 mov 0x18(%rsp), %r9 # Now call the external routine call *%rbx # Function epilog mov %rbp, %rsp pop %rbx pop %rbp ret ASM_GLOBAL ASM_PFX(EbcLLEbcInterpret); ASM_PFX(EbcLLEbcInterpret): # save old parameter to stack mov %rcx, 0x8(%rsp) mov %rdx, 0x10(%rsp) mov %r8, 0x18(%rsp) mov %r9, 0x20(%rsp) # Construct new stack push %rbp mov %rsp, %rbp push %rsi push %rdi push %rbx sub $0x80, %rsp push %r10 mov %rbp, %rsi add $0x10, %rsi mov %rsp, %rdi add $0x8, %rdi mov $0x10, %rcx rep movsq # build new paramater calling convention mov 0x18(%rsp), %r9 mov 0x10(%rsp), %r8 mov 0x8(%rsp), %rdx mov %r10, %rcx # call C-code call ASM_PFX(EbcInterpret) add $0x88, %esp pop %rbx pop %rdi pop %rsi pop %rbp ret ASM_GLOBAL ASM_PFX(EbcLLExecuteEbcImageEntryPoint); ASM_PFX(EbcLLExecuteEbcImageEntryPoint): # build new paramater calling convention mov %rdx, %r8 mov %rcx, %rdx mov %r10, %rcx # call C-code sub $0x28, %rsp call ASM_PFX(ExecuteEbcImageEntryPoint) add $0x28, %rsp ret