--- /dev/null
+#/** @file\r
+#\r
+# This code provides low level routines that support the Virtual Machine\r
+# for option ROMs.\r
+#\r
+# Copyright (c) 2015, The Linux Foundation. All rights reserved.\r
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#**/\r
+\r
+#---------------------------------------------------------------------------\r
+# Equate files needed.\r
+#---------------------------------------------------------------------------\r
+\r
+ASM_GLOBAL ASM_PFX(CopyMem);\r
+ASM_GLOBAL ASM_PFX(EbcInterpret);\r
+ASM_GLOBAL ASM_PFX(ExecuteEbcImageEntryPoint);\r
+\r
+#****************************************************************************\r
+# EbcLLCALLEX\r
+#\r
+# This function is called to execute an EBC CALLEX instruction.\r
+# This instruction requires that we thunk out to external native\r
+# code. For AArch64, we copy the VM stack into the main stack and then pop\r
+# the first 8 arguments off according to the AArch64 Procedure Call Standard\r
+# On return, we restore the stack pointer to its original location.\r
+#\r
+#****************************************************************************\r
+# UINTN EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)\r
+ASM_GLOBAL ASM_PFX(EbcLLCALLEXNative);\r
+ASM_PFX(EbcLLCALLEXNative):\r
+ stp x19, x20, [sp, #-16]!\r
+ stp x29, x30, [sp, #-16]!\r
+\r
+ mov x19, x0\r
+ mov x20, sp\r
+ sub x2, x2, x1 // Length = NewStackPointer-FramePtr\r
+ sub sp, sp, x2\r
+ sub sp, sp, #64 // Make sure there is room for at least 8 args in the new stack\r
+ mov x0, sp\r
+\r
+ bl CopyMem // Sp, NewStackPointer, Length\r
+\r
+ ldp x0, x1, [sp], #16\r
+ ldp x2, x3, [sp], #16\r
+ ldp x4, x5, [sp], #16\r
+ ldp x6, x7, [sp], #16\r
+\r
+ blr x19\r
+\r
+ mov sp, x20\r
+ ldp x29, x30, [sp], #16\r
+ ldp x19, x20, [sp], #16\r
+\r
+ ret\r
+\r
+#****************************************************************************\r
+# EbcLLEbcInterpret\r
+#\r
+# This function is called by the thunk code to handle an Native to EBC call\r
+# This can handle up to 16 arguments (1-8 on in x0-x7, 9-16 are on the stack)\r
+# x9 contains the Entry point that will be the first argument when\r
+# EBCInterpret is called.\r
+#\r
+#****************************************************************************\r
+ASM_GLOBAL ASM_PFX(EbcLLEbcInterpret);\r
+ASM_PFX(EbcLLEbcInterpret):\r
+ stp x29, x30, [sp, #-16]!\r
+\r
+ // copy the current arguments 9-16 from old location and add arg 7 to stack\r
+ // keeping 16 byte stack alignment\r
+ sub sp, sp, #80\r
+ str x7, [sp]\r
+ ldr x11, [sp, #96]\r
+ str x11, [sp, #8]\r
+ ldr x11, [sp, #104]\r
+ str x11, [sp, #16]\r
+ ldr x11, [sp, #112]\r
+ str x11, [sp, #24]\r
+ ldr x11, [sp, #120]\r
+ str x11, [sp, #32]\r
+ ldr x11, [sp, #128]\r
+ str x11, [sp, #40]\r
+ ldr x11, [sp, #136]\r
+ str x11, [sp, #48]\r
+ ldr x11, [sp, #144]\r
+ str x11, [sp, #56]\r
+ ldr x11, [sp, #152]\r
+ str x11, [sp, #64]\r
+\r
+ // Shift arguments and add entry point and as argument 1\r
+ mov x7, x6\r
+ mov x6, x5\r
+ mov x5, x4\r
+ mov x4, x3\r
+ mov x3, x2\r
+ mov x2, x1\r
+ mov x1, x0\r
+ mov x0, x9\r
+\r
+ # call C-code\r
+ bl ASM_PFX(EbcInterpret)\r
+ add sp, sp, #80\r
+\r
+ ldp x29, x30, [sp], #16\r
+\r
+ ret\r
+\r
+#****************************************************************************\r
+# EbcLLExecuteEbcImageEntryPoint\r
+#\r
+# This function is called by the thunk code to handle the image entry point\r
+# x9 contains the Entry point that will be the first argument when\r
+# ExecuteEbcImageEntryPoint is called.\r
+#\r
+#****************************************************************************\r
+ASM_GLOBAL ASM_PFX(EbcLLExecuteEbcImageEntryPoint);\r
+ASM_PFX(EbcLLExecuteEbcImageEntryPoint):\r
+ stp x29, x30, [sp, #-16]!\r
+ # build new paramater calling convention\r
+ mov x2, x1\r
+ mov x1, x0\r
+ mov x0, x9\r
+\r
+ # call C-code\r
+ bl ASM_PFX(ExecuteEbcImageEntryPoint)\r
+ ldp x29, x30, [sp], #16\r
+ ret\r
--- /dev/null
+/** @file\r
+ This module contains EBC support routines that are customized based on\r
+ the target AArch64 processor.\r
+\r
+Copyright (c) 2015, The Linux Foundation. All rights reserved.\r
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EbcInt.h"\r
+#include "EbcExecute.h"\r
+\r
+//\r
+// Amount of space that is not used in the stack\r
+//\r
+#define STACK_REMAIN_SIZE (1024 * 4)\r
+\r
+//\r
+// This is instruction buffer used to create EBC thunk\r
+//\r
+#define EBC_MAGIC_SIGNATURE 0xCA112EBCCA112EBCull\r
+#define EBC_ENTRYPOINT_SIGNATURE 0xAFAFAFAFAFAFAFAFull\r
+#define EBC_LL_EBC_ENTRYPOINT_SIGNATURE 0xFAFAFAFAFAFAFAFAull\r
+UINT8 mInstructionBufferTemplate[] = {\r
+ 0x03, 0x00, 0x00, 0x14, //b pc+16\r
+ //\r
+ // Add a magic code here to help the VM recognize the thunk..\r
+ //\r
+ (UINT8)(EBC_MAGIC_SIGNATURE & 0xFF),\r
+ (UINT8)((EBC_MAGIC_SIGNATURE >> 8) & 0xFF),\r
+ (UINT8)((EBC_MAGIC_SIGNATURE >> 16) & 0xFF),\r
+ (UINT8)((EBC_MAGIC_SIGNATURE >> 24) & 0xFF),\r
+ (UINT8)((EBC_MAGIC_SIGNATURE >> 32) & 0xFF),\r
+ (UINT8)((EBC_MAGIC_SIGNATURE >> 40) & 0xFF),\r
+ (UINT8)((EBC_MAGIC_SIGNATURE >> 48) & 0xFF),\r
+ (UINT8)((EBC_MAGIC_SIGNATURE >> 56) & 0xFF),\r
+ 0x69, 0x00, 0x00, 0x58, //ldr x9, #32\r
+ 0x8A, 0x00, 0x00, 0x58, //ldr x10, #40\r
+ 0x05, 0x00, 0x00, 0x14, //b pc+32\r
+ (UINT8)(EBC_ENTRYPOINT_SIGNATURE & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 32) & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 40) & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 48) & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 56) & 0xFF),\r
+ (UINT8)(EBC_LL_EBC_ENTRYPOINT_SIGNATURE & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 32) & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 40) & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 48) & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 56) & 0xFF),\r
+ 0x40, 0x01, 0x1F, 0xD6 //br x10\r
+\r
+};\r
+\r
+/**\r
+ Begin executing an EBC image.\r
+ This is used for Ebc Thunk call.\r
+\r
+ @return The value returned by the EBC application we're going to run.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+EbcLLEbcInterpret (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Begin executing an EBC image.\r
+ This is used for Ebc image entrypoint.\r
+\r
+ @return The value returned by the EBC application we're going to run.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+EbcLLExecuteEbcImageEntryPoint (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Pushes a 64 bit unsigned value to the VM stack.\r
+\r
+ @param VmPtr The pointer to current VM context.\r
+ @param Arg The value to be pushed.\r
+\r
+**/\r
+VOID\r
+PushU64 (\r
+ IN VM_CONTEXT *VmPtr,\r
+ IN UINT64 Arg\r
+ )\r
+{\r
+ //\r
+ // Advance the VM stack down, and then copy the argument to the stack.\r
+ // Hope it's aligned.\r
+ //\r
+ VmPtr->Gpr[0] -= sizeof (UINT64);\r
+ *(UINT64 *) VmPtr->Gpr[0] = Arg;\r
+ return;\r
+}\r
+\r
+\r
+/**\r
+ Begin executing an EBC image.\r
+\r
+ This is a thunk function.\r
+\r
+ @param EntryPoint The entrypoint of EBC code.\r
+ @param Arg1 The 1st argument.\r
+ @param Arg2 The 2nd argument.\r
+ @param Arg3 The 3rd argument.\r
+ @param Arg4 The 4th argument.\r
+ @param Arg5 The 5th argument.\r
+ @param Arg6 The 6th argument.\r
+ @param Arg7 The 7th argument.\r
+ @param Arg8 The 8th argument.\r
+ @param Arg9 The 9th argument.\r
+ @param Arg10 The 10th argument.\r
+ @param Arg11 The 11th argument.\r
+ @param Arg12 The 12th argument.\r
+ @param Arg13 The 13th argument.\r
+ @param Arg14 The 14th argument.\r
+ @param Arg15 The 15th argument.\r
+ @param Arg16 The 16th argument.\r
+\r
+ @return The value returned by the EBC application we're going to run.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+EbcInterpret (\r
+ IN UINTN EntryPoint,\r
+ IN UINTN Arg1,\r
+ IN UINTN Arg2,\r
+ IN UINTN Arg3,\r
+ IN UINTN Arg4,\r
+ IN UINTN Arg5,\r
+ IN UINTN Arg6,\r
+ IN UINTN Arg7,\r
+ IN UINTN Arg8,\r
+ IN UINTN Arg9,\r
+ IN UINTN Arg10,\r
+ IN UINTN Arg11,\r
+ IN UINTN Arg12,\r
+ IN UINTN Arg13,\r
+ IN UINTN Arg14,\r
+ IN UINTN Arg15,\r
+ IN UINTN Arg16\r
+ )\r
+{\r
+ //\r
+ // Create a new VM context on the stack\r
+ //\r
+ VM_CONTEXT VmContext;\r
+ UINTN Addr;\r
+ EFI_STATUS Status;\r
+ UINTN StackIndex;\r
+\r
+ //\r
+ // Get the EBC entry point\r
+ //\r
+ Addr = EntryPoint;\r
+\r
+ //\r
+ // Now clear out our context\r
+ //\r
+ ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));\r
+\r
+ //\r
+ // Set the VM instruction pointer to the correct location in memory.\r
+ //\r
+ VmContext.Ip = (VMIP) Addr;\r
+\r
+ //\r
+ // Initialize the stack pointer for the EBC. Get the current system stack\r
+ // pointer and adjust it down by the max needed for the interpreter.\r
+ //\r
+\r
+ //\r
+ // Adjust the VM's stack pointer down.\r
+ //\r
+\r
+ Status = GetEBCStack((EFI_HANDLE)(UINTN)-1, &VmContext.StackPool, &StackIndex);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+ VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);\r
+ VmContext.Gpr[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);\r
+ VmContext.HighStackBottom = (UINTN) VmContext.Gpr[0];\r
+ VmContext.Gpr[0] -= sizeof (UINTN);\r
+\r
+ //\r
+ // Align the stack on a natural boundary.\r
+ //\r
+ VmContext.Gpr[0] &= ~(VM_REGISTER)(sizeof (UINTN) - 1);\r
+\r
+ //\r
+ // Put a magic value in the stack gap, then adjust down again.\r
+ //\r
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;\r
+ VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];\r
+\r
+ //\r
+ // The stack upper to LowStackTop is belong to the VM.\r
+ //\r
+ VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];\r
+\r
+ //\r
+ // For the worst case, assume there are 4 arguments passed in registers, store\r
+ // them to VM's stack.\r
+ //\r
+ PushU64 (&VmContext, (UINT64) Arg16);\r
+ PushU64 (&VmContext, (UINT64) Arg15);\r
+ PushU64 (&VmContext, (UINT64) Arg14);\r
+ PushU64 (&VmContext, (UINT64) Arg13);\r
+ PushU64 (&VmContext, (UINT64) Arg12);\r
+ PushU64 (&VmContext, (UINT64) Arg11);\r
+ PushU64 (&VmContext, (UINT64) Arg10);\r
+ PushU64 (&VmContext, (UINT64) Arg9);\r
+ PushU64 (&VmContext, (UINT64) Arg8);\r
+ PushU64 (&VmContext, (UINT64) Arg7);\r
+ PushU64 (&VmContext, (UINT64) Arg6);\r
+ PushU64 (&VmContext, (UINT64) Arg5);\r
+ PushU64 (&VmContext, (UINT64) Arg4);\r
+ PushU64 (&VmContext, (UINT64) Arg3);\r
+ PushU64 (&VmContext, (UINT64) Arg2);\r
+ PushU64 (&VmContext, (UINT64) Arg1);\r
+\r
+ //\r
+ // Interpreter assumes 64-bit return address is pushed on the stack.\r
+ // AArch64 does not do this so pad the stack accordingly.\r
+ //\r
+ PushU64 (&VmContext, (UINT64) 0);\r
+ PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);\r
+\r
+ //\r
+ // For AArch64, this is where we say our return address is\r
+ //\r
+ VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];\r
+\r
+ //\r
+ // We need to keep track of where the EBC stack starts. This way, if the EBC\r
+ // accesses any stack variables above its initial stack setting, then we know\r
+ // it's accessing variables passed into it, which means the data is on the\r
+ // VM's stack.\r
+ // When we're called, on the stack (high to low) we have the parameters, the\r
+ // return address, then the saved ebp. Save the pointer to the return address.\r
+ // EBC code knows that's there, so should look above it for function parameters.\r
+ // The offset is the size of locals (VMContext + Addr + saved ebp).\r
+ // Note that the interpreter assumes there is a 16 bytes of return address on\r
+ // the stack too, so adjust accordingly.\r
+ // VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));\r
+ //\r
+\r
+ //\r
+ // Begin executing the EBC code\r
+ //\r
+ EbcExecute (&VmContext);\r
+\r
+ //\r
+ // Return the value in R[7] unless there was an error\r
+ //\r
+ ReturnEBCStack(StackIndex);\r
+ return (UINT64) VmContext.Gpr[7];\r
+}\r
+\r
+\r
+/**\r
+ Begin executing an EBC image.\r
+\r
+ @param EntryPoint The entrypoint of EBC code.\r
+ @param ImageHandle image handle for the EBC application we're executing\r
+ @param SystemTable standard system table passed into an driver's entry\r
+ point\r
+\r
+ @return The value returned by the EBC application we're going to run.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+ExecuteEbcImageEntryPoint (\r
+ IN UINTN EntryPoint,\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ //\r
+ // Create a new VM context on the stack\r
+ //\r
+ VM_CONTEXT VmContext;\r
+ UINTN Addr;\r
+ EFI_STATUS Status;\r
+ UINTN StackIndex;\r
+\r
+ //\r
+ // Get the EBC entry point\r
+ //\r
+ Addr = EntryPoint;\r
+\r
+ //\r
+ // Now clear out our context\r
+ //\r
+ ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));\r
+\r
+ //\r
+ // Save the image handle so we can track the thunks created for this image\r
+ //\r
+ VmContext.ImageHandle = ImageHandle;\r
+ VmContext.SystemTable = SystemTable;\r
+\r
+ //\r
+ // Set the VM instruction pointer to the correct location in memory.\r
+ //\r
+ VmContext.Ip = (VMIP) Addr;\r
+\r
+ //\r
+ // Initialize the stack pointer for the EBC. Get the current system stack\r
+ // pointer and adjust it down by the max needed for the interpreter.\r
+ //\r
+\r
+ Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+ VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);\r
+ VmContext.Gpr[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);\r
+ VmContext.HighStackBottom = (UINTN) VmContext.Gpr[0];\r
+ VmContext.Gpr[0] -= sizeof (UINTN);\r
+\r
+\r
+ //\r
+ // Put a magic value in the stack gap, then adjust down again\r
+ //\r
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;\r
+ VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];\r
+\r
+ //\r
+ // Align the stack on a natural boundary\r
+ VmContext.Gpr[0] &= ~(VM_REGISTER)(sizeof(UINTN) - 1);\r
+ //\r
+ VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];\r
+\r
+ //\r
+ // Simply copy the image handle and system table onto the EBC stack.\r
+ // Greatly simplifies things by not having to spill the args.\r
+ //\r
+ PushU64 (&VmContext, (UINT64) SystemTable);\r
+ PushU64 (&VmContext, (UINT64) ImageHandle);\r
+\r
+ //\r
+ // VM pushes 16-bytes for return address. Simulate that here.\r
+ //\r
+ PushU64 (&VmContext, (UINT64) 0);\r
+ PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);\r
+\r
+ //\r
+ // For AArch64, this is where we say our return address is\r
+ //\r
+ VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];\r
+\r
+ //\r
+ // Entry function needn't access high stack context, simply\r
+ // put the stack pointer here.\r
+ //\r
+\r
+ //\r
+ // Begin executing the EBC code\r
+ //\r
+ EbcExecute (&VmContext);\r
+\r
+ //\r
+ // Return the value in R[7] unless there was an error\r
+ //\r
+ ReturnEBCStack(StackIndex);\r
+ return (UINT64) VmContext.Gpr[7];\r
+}\r
+\r
+\r
+/**\r
+ Create thunks for an EBC image entry point, or an EBC protocol service.\r
+\r
+ @param ImageHandle Image handle for the EBC image. If not null, then\r
+ we're creating a thunk for an image entry point.\r
+ @param EbcEntryPoint Address of the EBC code that the thunk is to call\r
+ @param Thunk Returned thunk we create here\r
+ @param Flags Flags indicating options for creating the thunk\r
+\r
+ @retval EFI_SUCCESS The thunk was created successfully.\r
+ @retval EFI_INVALID_PARAMETER The parameter of EbcEntryPoint is not 16-bit\r
+ aligned.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory to created the EBC\r
+ Thunk.\r
+ @retval EFI_BUFFER_TOO_SMALL EBC_THUNK_SIZE is not larger enough.\r
+\r
+**/\r
+EFI_STATUS\r
+EbcCreateThunks (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN VOID *EbcEntryPoint,\r
+ OUT VOID **Thunk,\r
+ IN UINT32 Flags\r
+ )\r
+{\r
+ UINT8 *Ptr;\r
+ UINT8 *ThunkBase;\r
+ UINT32 Index;\r
+ INT32 ThunkSize;\r
+\r
+ //\r
+ // Check alignment of pointer to EBC code\r
+ //\r
+ if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ThunkSize = sizeof(mInstructionBufferTemplate);\r
+\r
+ Ptr = AllocatePool (sizeof(mInstructionBufferTemplate));\r
+\r
+ if (Ptr == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Print(L"Allocate TH: 0x%X\n", (UINT32)Ptr);\r
+ //\r
+ // Save the start address so we can add a pointer to it to a list later.\r
+ //\r
+ ThunkBase = Ptr;\r
+\r
+ //\r
+ // Give them the address of our buffer we're going to fix up\r
+ //\r
+ *Thunk = (VOID *) Ptr;\r
+\r
+ //\r
+ // Copy whole thunk instruction buffer template\r
+ //\r
+ CopyMem (Ptr, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate));\r
+\r
+ //\r
+ // Patch EbcEntryPoint and EbcLLEbcInterpret\r
+ //\r
+ for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {\r
+ if (*(UINTN *)&Ptr[Index] == EBC_ENTRYPOINT_SIGNATURE) {\r
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcEntryPoint;\r
+ }\r
+ if (*(UINTN *)&Ptr[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {\r
+ if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {\r
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcLLExecuteEbcImageEntryPoint;\r
+ } else {\r
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcLLEbcInterpret;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Add the thunk to the list for this image. Do this last since the add\r
+ // function flushes the cache for us.\r
+ //\r
+ EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This function is called to execute an EBC CALLEX instruction.\r
+ The function check the callee's content to see whether it is common native\r
+ code or a thunk to another piece of EBC code.\r
+ If the callee is common native code, use EbcLLCAllEXASM to manipulate,\r
+ otherwise, set the VM->IP to target EBC code directly to avoid another VM\r
+ be startup which cost time and stack space.\r
+\r
+ @param VmPtr Pointer to a VM context.\r
+ @param FuncAddr Callee's address\r
+ @param NewStackPointer New stack pointer after the call\r
+ @param FramePtr New frame pointer after the call\r
+ @param Size The size of call instruction\r
+\r
+**/\r
+VOID\r
+EbcLLCALLEX (\r
+ IN VM_CONTEXT *VmPtr,\r
+ IN UINTN FuncAddr,\r
+ IN UINTN NewStackPointer,\r
+ IN VOID *FramePtr,\r
+ IN UINT8 Size\r
+ )\r
+{\r
+ UINTN IsThunk;\r
+ UINTN TargetEbcAddr;\r
+ UINT8 InstructionBuffer[sizeof(mInstructionBufferTemplate)];\r
+ UINTN Index;\r
+ UINTN IndexOfEbcEntrypoint;\r
+\r
+ IsThunk = 1;\r
+ TargetEbcAddr = 0;\r
+ IndexOfEbcEntrypoint = 0;\r
+\r
+ //\r
+ // Processor specific code to check whether the callee is a thunk to EBC.\r
+ //\r
+ CopyMem (InstructionBuffer, (VOID *)FuncAddr, sizeof(InstructionBuffer));\r
+ //\r
+ // Fill the signature according to mInstructionBufferTemplate\r
+ //\r
+ for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {\r
+ if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_ENTRYPOINT_SIGNATURE) {\r
+ *(UINTN *)&InstructionBuffer[Index] = EBC_ENTRYPOINT_SIGNATURE;\r
+ IndexOfEbcEntrypoint = Index;\r
+ }\r
+ if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {\r
+ *(UINTN *)&InstructionBuffer[Index] = EBC_LL_EBC_ENTRYPOINT_SIGNATURE;\r
+ }\r
+ }\r
+ //\r
+ // Check if we need thunk to native\r
+ //\r
+ if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) {\r
+ IsThunk = 0;\r
+ }\r
+\r
+ if (IsThunk == 1){\r
+ //\r
+ // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and\r
+ // put our return address and frame pointer on the VM stack.\r
+ // Then set the VM's IP to new EBC code.\r
+ //\r
+ VmPtr->Gpr[0] -= 8;\r
+ VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr);\r
+ VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0];\r
+ VmPtr->Gpr[0] -= 8;\r
+ VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));\r
+\r
+ CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + IndexOfEbcEntrypoint, sizeof(UINTN));\r
+ VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;\r
+ } else {\r
+ //\r
+ // The callee is not a thunk to EBC, call native code,\r
+ // and get return value.\r
+ //\r
+ VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);\r
+\r
+ //\r
+ // Advance the IP.\r
+ //\r
+ VmPtr->Ip += Size;\r
+ }\r
+}\r
+\r