]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/EbcDxe/Ia32/EbcSupport.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / EbcDxe / Ia32 / EbcSupport.c
index d88b762ec25c84509faa471d21c0c86aa1b65754..a25139536f635b449db9f8bc48076135cc0dcc20 100644 (file)
@@ -1,20 +1,15 @@
 /** @file\r
   This module contains EBC support routines that are customized based on\r
-  the target processor.\r
+  the target ia32 processor.\r
 \r
-Copyright (c) 2006 - 2010, Intel Corporation. <BR>\r
-All rights reserved. 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
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "EbcInt.h"\r
 #include "EbcExecute.h"\r
+#include "EbcDebuggerHook.h"\r
 \r
 //\r
 // NOTE: This is the stack size allocated for the interpreter\r
@@ -23,10 +18,72 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 //       platform-specific configurations.\r
 //\r
 #define VM_STACK_SIZE   (1024 * 4)\r
-#define EBC_THUNK_SIZE  32\r
 \r
 #define STACK_REMAIN_SIZE (1024 * 4)\r
 \r
+//\r
+// This is instruction buffer used to create EBC thunk\r
+//\r
+#define EBC_ENTRYPOINT_SIGNATURE           0xAFAFAFAF\r
+#define EBC_LL_EBC_ENTRYPOINT_SIGNATURE    0xFAFAFAFA\r
+UINT8  mInstructionBufferTemplate[] = {\r
+  //\r
+  // Add a magic code here to help the VM recognize the thunk..\r
+  // mov eax, 0xca112ebc  => B8 BC 2E 11 CA\r
+  //\r
+  0xB8, 0xBC, 0x2E, 0x11, 0xCA,\r
+  //\r
+  // Add code bytes to load up a processor register with the EBC entry point.\r
+  //  mov eax, EbcEntryPoint  => B8 XX XX XX XX (To be fixed at runtime)\r
+  // These 4 bytes of the thunk entry is the address of the EBC\r
+  // entry point.\r
+  //\r
+  0xB8,\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
+  //\r
+  // Stick in a load of ecx with the address of appropriate VM function.\r
+  //  mov ecx, EbcLLEbcInterpret  => B9 XX XX XX XX (To be fixed at runtime)\r
+  //\r
+  0xB9,\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
+  //\r
+  // Stick in jump opcode bytes\r
+  //  jmp ecx => FF E1\r
+  //\r
+  0xFF, 0xE1,\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
   This function is called to execute an EBC CALLEX instruction.\r
@@ -54,54 +111,37 @@ EbcLLCALLEX (
 {\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
-  if (*((UINT8 *)FuncAddr) != 0xB8) {\r
-    IsThunk = 0;\r
-    goto Action;\r
-  }\r
-  if (*((UINT8 *)FuncAddr + 1) != 0xBC)  {\r
-    IsThunk = 0;\r
-    goto Action;\r
-  }\r
-  if (*((UINT8 *)FuncAddr + 2) != 0x2E)  {\r
-    IsThunk = 0;\r
-    goto Action;\r
-  }\r
-  if (*((UINT8 *)FuncAddr + 3) != 0x11)  {\r
-    IsThunk = 0;\r
-    goto Action;\r
-  }\r
-  if (*((UINT8 *)FuncAddr + 4) != 0xCA)  {\r
-    IsThunk = 0;\r
-    goto Action;\r
-  }\r
-  if (*((UINT8 *)FuncAddr + 5) != 0xB8)  {\r
-    IsThunk = 0;\r
-    goto Action;\r
-  }\r
-  if (*((UINT8 *)FuncAddr + 10) != 0xB9)  {\r
-    IsThunk = 0;\r
-    goto Action;\r
-  }\r
-  if (*((UINT8 *)FuncAddr + 15) != 0xFF)  {\r
-    IsThunk = 0;\r
-    goto Action;\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
-  if (*((UINT8 *)FuncAddr + 16) != 0xE1)  {\r
+  //\r
+  // Check if we need thunk to native\r
+  //\r
+  if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) {\r
     IsThunk = 0;\r
-    goto Action;\r
   }\r
 \r
-  TargetEbcAddr = ((UINTN)(*((UINT8 *)FuncAddr + 9)) << 24) + ((UINTN)(*((UINT8 *)FuncAddr + 8)) << 16) +\r
-                    ((UINTN)(*((UINT8 *)FuncAddr + 7)) << 8) + ((UINTN)(*((UINT8 *)FuncAddr + 6)));\r
-\r
-Action:\r
   if (IsThunk == 1){\r
     //\r
     // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and\r
@@ -114,31 +154,31 @@ Action:
     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
+    // The callee is not a thunk to EBC, call native code,\r
+    // and get return value.\r
     //\r
-    EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);\r
+    VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);\r
 \r
     //\r
-    // Get return value and advance the IP.\r
+    // Advance the IP.\r
     //\r
-    VmPtr->Gpr[7] = EbcLLGetReturnValue ();\r
     VmPtr->Ip += Size;\r
   }\r
 }\r
 \r
 \r
 /**\r
-  Begin executing an EBC image. The address of the entry point is passed\r
-  in via a processor register, so we'll need to make a call to get the\r
-  value.\r
+  Begin executing an EBC image.\r
 \r
   This is a thunk function. Microsoft x64 compiler only provide fast_call\r
   calling convention, so the first four arguments are passed by rcx, rdx,\r
   r8, and r9, while other arguments are passed in stack.\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
@@ -160,23 +200,25 @@ Action:
 \r
 **/\r
 UINT64\r
+EFIAPI\r
 EbcInterpret (\r
-  IN OUT UINTN      Arg1,\r
-  IN OUT UINTN      Arg2,\r
-  IN OUT UINTN      Arg3,\r
-  IN OUT UINTN      Arg4,\r
-  IN OUT UINTN      Arg5,\r
-  IN OUT UINTN      Arg6,\r
-  IN OUT UINTN      Arg7,\r
-  IN OUT UINTN      Arg8,\r
-  IN OUT UINTN      Arg9,\r
-  IN OUT UINTN      Arg10,\r
-  IN OUT UINTN      Arg11,\r
-  IN OUT UINTN      Arg12,\r
-  IN OUT UINTN      Arg13,\r
-  IN OUT UINTN      Arg14,\r
-  IN OUT UINTN      Arg15,\r
-  IN OUT UINTN      Arg16\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
@@ -188,9 +230,9 @@ EbcInterpret (
   UINTN       StackIndex;\r
 \r
   //\r
-  // Get the EBC entry point from the processor register.\r
+  // Get the EBC entry point\r
   //\r
-  Addr = EbcLLGetEbcEntryPoint ();\r
+  Addr = EntryPoint;\r
 \r
   //\r
   // Now clear out our context\r
@@ -220,7 +262,7 @@ EbcInterpret (
   VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);\r
   VmContext.Gpr[0] = (UINT64)(UINTN) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);\r
   VmContext.HighStackBottom = (UINTN)VmContext.Gpr[0];\r
-  VmContext.Gpr[0] &= ~(sizeof (UINTN) - 1);\r
+  VmContext.Gpr[0] &= ~((VM_REGISTER)(sizeof (UINTN) - 1));\r
   VmContext.Gpr[0] -= sizeof (UINTN);\r
 \r
   //\r
@@ -285,10 +327,11 @@ EbcInterpret (
   //\r
   // Begin executing the EBC code\r
   //\r
+  EbcDebuggerHookEbcInterpret (&VmContext);\r
   EbcExecute (&VmContext);\r
 \r
   //\r
-  // Return the value in R[7] unless there was an error\r
+  // Return the value in Gpr[7] unless there was an error\r
   //\r
   ReturnEBCStack(StackIndex);\r
   return (UINT64) VmContext.Gpr[7];\r
@@ -296,10 +339,9 @@ EbcInterpret (
 \r
 \r
 /**\r
-  Begin executing an EBC image. The address of the entry point is passed\r
-  in via a processor register, so we'll need to make a call to get the\r
-  value.\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
@@ -308,7 +350,9 @@ EbcInterpret (
 \r
 **/\r
 UINT64\r
+EFIAPI\r
 ExecuteEbcImageEntryPoint (\r
+  IN UINTN                EntryPoint,\r
   IN EFI_HANDLE           ImageHandle,\r
   IN EFI_SYSTEM_TABLE     *SystemTable\r
   )\r
@@ -322,15 +366,10 @@ ExecuteEbcImageEntryPoint (
   UINTN       StackIndex;\r
 \r
   //\r
-  // Get the EBC entry point from the processor register. Make sure you don't\r
-  // call any functions before this or you could mess up the register the\r
-  // entry point is passed in.\r
+  // Get the EBC entry point\r
   //\r
-  Addr = EbcLLGetEbcEntryPoint ();\r
+  Addr = EntryPoint;\r
 \r
-  //\r
-  //  Print(L"*** Thunked into EBC entry point - ImageHandle = 0x%X\n", (UINTN)ImageHandle);\r
-  //  Print(L"EBC entry point is 0x%X\n", (UINT32)(UINTN)Addr);\r
   //\r
   // Now clear out our context\r
   //\r
@@ -389,11 +428,13 @@ ExecuteEbcImageEntryPoint (
   //\r
   // Begin executing the EBC code\r
   //\r
+  EbcDebuggerHookExecuteEbcImageEntryPoint (&VmContext);\r
   EbcExecute (&VmContext);\r
 \r
   //\r
-  // Return the value in R[7] unless there was an error\r
+  // Return the value in Gpr[7] unless there was an error\r
   //\r
+  ReturnEBCStack(StackIndex);\r
   return (UINT64) VmContext.Gpr[7];\r
 }\r
 \r
@@ -426,8 +467,6 @@ EbcCreateThunks (
   UINT8       *Ptr;\r
   UINT8       *ThunkBase;\r
   UINT32      Index;\r
-  UINT32      Addr;\r
-  INT32       Size;\r
   INT32       ThunkSize;\r
 \r
   //\r
@@ -437,10 +476,9 @@ EbcCreateThunks (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  Size      = EBC_THUNK_SIZE;\r
-  ThunkSize = Size;\r
+  ThunkSize = sizeof(mInstructionBufferTemplate);\r
 \r
-  Ptr = AllocatePool (Size);\r
+  Ptr = EbcAllocatePoolForThunk (sizeof(mInstructionBufferTemplate));\r
 \r
   if (Ptr == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
@@ -458,74 +496,26 @@ EbcCreateThunks (
   *Thunk = (VOID *) Ptr;\r
 \r
   //\r
-  // Add a magic code here to help the VM recognize the thunk..\r
-  // mov eax, 0xca112ebc  => B8 BC 2E 11 CA\r
+  // Copy whole thunk instruction buffer template\r
   //\r
-  *Ptr = 0xB8;\r
-  Ptr++;\r
-  Size--;\r
-  Addr = (UINT32) 0xCA112EBC;\r
-  for (Index = 0; Index < sizeof (Addr); Index++) {\r
-    *Ptr = (UINT8) (UINTN) Addr;\r
-    Addr >>= 8;\r
-    Ptr++;\r
-    Size--;\r
-  }\r
+  CopyMem (Ptr, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate));\r
 \r
   //\r
-  // Add code bytes to load up a processor register with the EBC entry point.\r
-  // mov eax, 0xaa55aa55  => B8 55 AA 55 AA\r
-  // The first 8 bytes of the thunk entry is the address of the EBC\r
-  // entry point.\r
+  // Patch EbcEntryPoint and EbcLLEbcInterpret\r
   //\r
-  *Ptr = 0xB8;\r
-  Ptr++;\r
-  Size--;\r
-  Addr = (UINT32) EbcEntryPoint;\r
-  for (Index = 0; Index < sizeof (Addr); Index++) {\r
-    *Ptr = (UINT8) (UINTN) Addr;\r
-    Addr >>= 8;\r
-    Ptr++;\r
-    Size--;\r
-  }\r
-  //\r
-  // Stick in a load of ecx with the address of appropriate VM function.\r
-  //  mov ecx 12345678h  => 0xB9 0x78 0x56 0x34 0x12\r
-  //\r
-  if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {\r
-    Addr = (UINT32) (UINTN) ExecuteEbcImageEntryPoint;\r
-  } else {\r
-    Addr = (UINT32) (UINTN) EbcInterpret;\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
-  // MOV ecx\r
-  //\r
-  *Ptr = 0xB9;\r
-  Ptr++;\r
-  Size--;\r
-  for (Index = 0; Index < sizeof (Addr); Index++) {\r
-    *Ptr = (UINT8) Addr;\r
-    Addr >>= 8;\r
-    Ptr++;\r
-    Size--;\r
-  }\r
-  //\r
-  // Stick in jump opcode bytes for jmp ecx => 0xFF 0xE1\r
-  //\r
-  *Ptr = 0xFF;\r
-  Ptr++;\r
-  Size--;\r
-  *Ptr = 0xE1;\r
-  Size--;\r
-\r
-  //\r
-  // Double check that our defined size is ok (application error)\r
-  //\r
-  if (Size < 0) {\r
-    ASSERT (FALSE);\r
-    return EFI_BUFFER_TOO_SMALL;\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