summaryrefslogtreecommitdiff
path: root/Core/MdeModulePkg/Universal/EbcDxe/X64/EbcLowLevel.S
diff options
context:
space:
mode:
Diffstat (limited to 'Core/MdeModulePkg/Universal/EbcDxe/X64/EbcLowLevel.S')
-rw-r--r--Core/MdeModulePkg/Universal/EbcDxe/X64/EbcLowLevel.S147
1 files changed, 147 insertions, 0 deletions
diff --git a/Core/MdeModulePkg/Universal/EbcDxe/X64/EbcLowLevel.S b/Core/MdeModulePkg/Universal/EbcDxe/X64/EbcLowLevel.S
new file mode 100644
index 0000000000..b01486a871
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/EbcDxe/X64/EbcLowLevel.S
@@ -0,0 +1,147 @@
+#/** @file
+#
+# This code provides low level routines that support the Virtual Machine
+# for option ROMs.
+#
+# Copyright (c) 2007 - 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.
+#
+#**/
+
+#---------------------------------------------------------------------------
+# 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