]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Ebc/Dxe/EbcInt.c
Add EBC, FTW, Crc32SectionExtract, NullMemoryTest modules.
[mirror_edk2.git] / MdeModulePkg / Universal / Ebc / Dxe / EbcInt.c
diff --git a/MdeModulePkg/Universal/Ebc/Dxe/EbcInt.c b/MdeModulePkg/Universal/Ebc/Dxe/EbcInt.c
new file mode 100644 (file)
index 0000000..2b647d9
--- /dev/null
@@ -0,0 +1,1172 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\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
+\r
+Module Name:\r
+\r
+  EbcInt.c\r
+\r
+Abstract:\r
+\r
+  Top level module for the EBC virtual machine implementation.\r
+  Provides auxilliary support routines for the VM. That is, routines\r
+  that are not particularly related to VM execution of EBC instructions.\r
+\r
+--*/\r
+\r
+#include "EbcInt.h"\r
+#include "EbcExecute.h"\r
+\r
+//\r
+// We'll keep track of all thunks we create in a linked list. Each\r
+// thunk is tied to an image handle, so we have a linked list of\r
+// image handles, with each having a linked list of thunks allocated\r
+// to that image handle.\r
+//\r
+typedef struct _EBC_THUNK_LIST {\r
+  VOID                    *ThunkBuffer;\r
+  struct _EBC_THUNK_LIST  *Next;\r
+} EBC_THUNK_LIST;\r
+\r
+typedef struct _EBC_IMAGE_LIST {\r
+  struct _EBC_IMAGE_LIST  *Next;\r
+  EFI_HANDLE              ImageHandle;\r
+  EBC_THUNK_LIST          *ThunkList;\r
+} EBC_IMAGE_LIST;\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcUnloadImage (\r
+  IN EFI_EBC_PROTOCOL     *This,\r
+  IN EFI_HANDLE           ImageHandle\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcCreateThunk (\r
+  IN EFI_EBC_PROTOCOL     *This,\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN VOID                 *EbcEntryPoint,\r
+  OUT VOID                **Thunk\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcGetVersion (\r
+  IN EFI_EBC_PROTOCOL     *This,\r
+  IN OUT UINT64           *Version\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeEbcCallback (\r
+  IN EFI_DEBUG_SUPPORT_PROTOCOL  *This\r
+  );\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+CommonEbcExceptionHandler (\r
+  IN EFI_EXCEPTION_TYPE   InterruptType,\r
+  IN EFI_SYSTEM_CONTEXT   SystemContext\r
+  );\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+EbcPeriodicNotifyFunction (\r
+  IN EFI_EVENT     Event,\r
+  IN VOID          *Context\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcDebugPeriodic (\r
+  IN VM_CONTEXT *VmPtr\r
+  );\r
+\r
+//\r
+// These two functions and the  GUID are used to produce an EBC test protocol.\r
+// This functionality is definitely not required for execution.\r
+//\r
+STATIC\r
+EFI_STATUS\r
+InitEbcVmTestProtocol (\r
+  IN EFI_HANDLE     *Handle\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+EbcVmTestUnsupported (\r
+  VOID\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcRegisterICacheFlush (\r
+  IN EFI_EBC_PROTOCOL               *This,\r
+  IN EBC_ICACHE_FLUSH               Flush\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcDebugGetMaximumProcessorIndex (\r
+  IN EFI_DEBUG_SUPPORT_PROTOCOL     *This,\r
+  OUT UINTN                         *MaxProcessorIndex\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcDebugRegisterPeriodicCallback (\r
+  IN EFI_DEBUG_SUPPORT_PROTOCOL     *This,\r
+  IN UINTN                          ProcessorIndex,\r
+  IN EFI_PERIODIC_CALLBACK          PeriodicCallback\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcDebugRegisterExceptionCallback (\r
+  IN EFI_DEBUG_SUPPORT_PROTOCOL     *This,\r
+  IN UINTN                          ProcessorIndex,\r
+  IN EFI_EXCEPTION_CALLBACK         ExceptionCallback,\r
+  IN EFI_EXCEPTION_TYPE             ExceptionType\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcDebugInvalidateInstructionCache (\r
+  IN EFI_DEBUG_SUPPORT_PROTOCOL     *This,\r
+  IN UINTN                          ProcessorIndex,\r
+  IN VOID                           *Start,\r
+  IN UINT64                         Length\r
+  );\r
+\r
+//\r
+// We have one linked list of image handles for the whole world. Since\r
+// there should only be one interpreter, make them global. They must\r
+// also be global since the execution of an EBC image does not provide\r
+// a This pointer.\r
+//\r
+static EBC_IMAGE_LIST         *mEbcImageList = NULL;\r
+\r
+//\r
+// Callback function to flush the icache after thunk creation\r
+//\r
+static EBC_ICACHE_FLUSH       mEbcICacheFlush;\r
+\r
+//\r
+// These get set via calls by the debug agent\r
+//\r
+static EFI_PERIODIC_CALLBACK  mDebugPeriodicCallback                            = NULL;\r
+static EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = {NULL};\r
+static EFI_GUID               mEfiEbcVmTestProtocolGuid = EFI_EBC_VM_TEST_PROTOCOL_GUID;\r
+\r
+static VOID*      mStackBuffer[MAX_STACK_NUM];\r
+static EFI_HANDLE mStackBufferIndex[MAX_STACK_NUM];\r
+static UINTN      mStackNum = 0;\r
+\r
+//\r
+// Event for Periodic callback\r
+//\r
+static EFI_EVENT              mEbcPeriodicEvent;\r
+VM_CONTEXT                    *mVmPtr = NULL;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeEbcDriver (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initializes the VM EFI interface.  Allocates memory for the VM interface\r
+  and registers the VM protocol.\r
+\r
+Arguments:\r
+\r
+  ImageHandle - EFI image handle.\r
+  SystemTable - Pointer to the EFI system table.\r
+\r
+Returns:\r
+  Standard EFI status code.\r
+\r
+--*/\r
+{\r
+  EFI_EBC_PROTOCOL            *EbcProtocol;\r
+  EFI_EBC_PROTOCOL            *OldEbcProtocol;\r
+  EFI_STATUS                  Status;\r
+  EFI_DEBUG_SUPPORT_PROTOCOL  *EbcDebugProtocol;\r
+  EFI_HANDLE                  *HandleBuffer;\r
+  UINTN                       NumHandles;\r
+  UINTN                       Index;\r
+  BOOLEAN                     Installed;\r
+\r
+  EbcProtocol      = NULL;\r
+  EbcDebugProtocol = NULL;\r
+\r
+  //\r
+  // Allocate memory for our protocol. Then fill in the blanks.\r
+  //\r
+  EbcProtocol = AllocatePool (sizeof (EFI_EBC_PROTOCOL));\r
+\r
+  if (EbcProtocol == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  EbcProtocol->CreateThunk          = EbcCreateThunk;\r
+  EbcProtocol->UnloadImage          = EbcUnloadImage;\r
+  EbcProtocol->RegisterICacheFlush  = EbcRegisterICacheFlush;\r
+  EbcProtocol->GetVersion           = EbcGetVersion;\r
+  mEbcICacheFlush                   = NULL;\r
+\r
+  //\r
+  // Find any already-installed EBC protocols and uninstall them\r
+  //\r
+  Installed     = FALSE;\r
+  HandleBuffer  = NULL;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiEbcProtocolGuid,\r
+                  NULL,\r
+                  &NumHandles,\r
+                  &HandleBuffer\r
+                  );\r
+  if (Status == EFI_SUCCESS) {\r
+    //\r
+    // Loop through the handles\r
+    //\r
+    for (Index = 0; Index < NumHandles; Index++) {\r
+      Status = gBS->HandleProtocol (\r
+                      HandleBuffer[Index],\r
+                      &gEfiEbcProtocolGuid,\r
+                      (VOID **) &OldEbcProtocol\r
+                      );\r
+      if (Status == EFI_SUCCESS) {\r
+        if (gBS->ReinstallProtocolInterface (\r
+                  HandleBuffer[Index],\r
+                  &gEfiEbcProtocolGuid,\r
+                  OldEbcProtocol,\r
+                  EbcProtocol\r
+                  ) == EFI_SUCCESS) {\r
+          Installed = TRUE;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  if (HandleBuffer != NULL) {\r
+    FreePool (HandleBuffer);\r
+    HandleBuffer = NULL;\r
+  }\r
+  //\r
+  // Add the protocol so someone can locate us if we haven't already.\r
+  //\r
+  if (!Installed) {\r
+    Status = gBS->InstallProtocolInterface (\r
+                    &ImageHandle,\r
+                    &gEfiEbcProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    EbcProtocol\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (EbcProtocol);\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  Status = InitEBCStack();\r
+  if (EFI_ERROR(Status)) {\r
+    goto ErrorExit;\r
+  }\r
+\r
+  //\r
+  // Allocate memory for our debug protocol. Then fill in the blanks.\r
+  //\r
+  EbcDebugProtocol = AllocatePool (sizeof (EFI_DEBUG_SUPPORT_PROTOCOL));\r
+\r
+  if (EbcDebugProtocol == NULL) {\r
+    goto ErrorExit;\r
+  }\r
+\r
+  EbcDebugProtocol->Isa                         = IsaEbc;\r
+  EbcDebugProtocol->GetMaximumProcessorIndex    = EbcDebugGetMaximumProcessorIndex;\r
+  EbcDebugProtocol->RegisterPeriodicCallback    = EbcDebugRegisterPeriodicCallback;\r
+  EbcDebugProtocol->RegisterExceptionCallback   = EbcDebugRegisterExceptionCallback;\r
+  EbcDebugProtocol->InvalidateInstructionCache  = EbcDebugInvalidateInstructionCache;\r
+\r
+  //\r
+  // Add the protocol so the debug agent can find us\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &ImageHandle,\r
+                  &gEfiDebugSupportProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  EbcDebugProtocol\r
+                  );\r
+  //\r
+  // This is recoverable, so free the memory and continue.\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (EbcDebugProtocol);\r
+    goto ErrorExit;\r
+  }\r
+  //\r
+  // Install EbcDebugSupport Protocol Successfully\r
+  // Now we need to initialize the Ebc default Callback\r
+  //\r
+  Status = InitializeEbcCallback (EbcDebugProtocol);\r
+\r
+  //\r
+  // Produce a VM test interface protocol. Not required for execution.\r
+  //\r
+  DEBUG_CODE_BEGIN ();\r
+    InitEbcVmTestProtocol (&ImageHandle);\r
+  DEBUG_CODE_END ();\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ErrorExit:\r
+  FreeEBCStack();\r
+  HandleBuffer  = NULL;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiEbcProtocolGuid,\r
+                  NULL,\r
+                  &NumHandles,\r
+                  &HandleBuffer\r
+                  );\r
+  if (Status == EFI_SUCCESS) {\r
+    //\r
+    // Loop through the handles\r
+    //\r
+    for (Index = 0; Index < NumHandles; Index++) {\r
+      Status = gBS->HandleProtocol (\r
+                      HandleBuffer[Index],\r
+                      &gEfiEbcProtocolGuid,\r
+                      (VOID **) &OldEbcProtocol\r
+                      );\r
+      if (Status == EFI_SUCCESS) {\r
+        gBS->UninstallProtocolInterface (\r
+               HandleBuffer[Index],\r
+               &gEfiEbcProtocolGuid,\r
+               OldEbcProtocol\r
+               );\r
+      }\r
+    }\r
+  }\r
+\r
+  if (HandleBuffer != NULL) {\r
+    FreePool (HandleBuffer);\r
+    HandleBuffer = NULL;\r
+  }\r
+\r
+  FreePool (EbcProtocol);\r
+\r
+  return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcCreateThunk (\r
+  IN EFI_EBC_PROTOCOL   *This,\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN VOID               *EbcEntryPoint,\r
+  OUT VOID              **Thunk\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This is the top-level routine plugged into the EBC protocol. Since thunks\r
+  are very processor-specific, from here we dispatch directly to the very\r
+  processor-specific routine EbcCreateThunks().\r
+\r
+Arguments:\r
+\r
+  This          - protocol instance pointer\r
+  ImageHandle   - handle to the image. The EBC interpreter may use this to keep\r
+                  track of any resource allocations performed in loading and\r
+                  executing the image.\r
+  EbcEntryPoint - the entry point for the image (as defined in the file header)\r
+  Thunk         - pointer to thunk pointer where the address of the created\r
+                  thunk is returned.\r
+\r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = EbcCreateThunks (\r
+            ImageHandle,\r
+            EbcEntryPoint,\r
+            Thunk,\r
+            FLAG_THUNK_ENTRY_POINT\r
+            );\r
+  return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcDebugGetMaximumProcessorIndex (\r
+  IN EFI_DEBUG_SUPPORT_PROTOCOL          *This,\r
+  OUT UINTN                              *MaxProcessorIndex\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This EBC debugger protocol service is called by the debug agent\r
+\r
+Arguments:\r
+\r
+  This              - pointer to the caller's debug support protocol interface\r
+  MaxProcessorIndex - pointer to a caller allocated UINTN in which the maximum\r
+                      processor index is returned.\r
+\r
+Returns:\r
+\r
+  Standard EFI_STATUS\r
+\r
+--*/\r
+{\r
+  *MaxProcessorIndex = 0;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcDebugRegisterPeriodicCallback (\r
+  IN EFI_DEBUG_SUPPORT_PROTOCOL  *This,\r
+  IN UINTN                       ProcessorIndex,\r
+  IN EFI_PERIODIC_CALLBACK       PeriodicCallback\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This protocol service is called by the debug agent to register a function\r
+  for us to call on a periodic basis.\r
+\r
+\r
+Arguments:\r
+\r
+  This              - pointer to the caller's debug support protocol interface\r
+  PeriodicCallback  - pointer to the function to call periodically\r
+\r
+Returns:\r
+\r
+  Always EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  if ((mDebugPeriodicCallback == NULL) && (PeriodicCallback == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if ((mDebugPeriodicCallback != NULL) && (PeriodicCallback != NULL)) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  mDebugPeriodicCallback = PeriodicCallback;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcDebugRegisterExceptionCallback (\r
+  IN EFI_DEBUG_SUPPORT_PROTOCOL  *This,\r
+  IN UINTN                       ProcessorIndex,\r
+  IN EFI_EXCEPTION_CALLBACK      ExceptionCallback,\r
+  IN EFI_EXCEPTION_TYPE          ExceptionType\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This protocol service is called by the debug agent to register a function\r
+  for us to call when we detect an exception.\r
+\r
+\r
+Arguments:\r
+\r
+  This              - pointer to the caller's debug support protocol interface\r
+  ExceptionCallback - pointer to the function to the exception\r
+\r
+Returns:\r
+\r
+  Always EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  if ((ExceptionType < 0) || (ExceptionType > MAX_EBC_EXCEPTION)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if ((mDebugExceptionCallback[ExceptionType] == NULL) && (ExceptionCallback == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if ((mDebugExceptionCallback[ExceptionType] != NULL) && (ExceptionCallback != NULL)) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+  mDebugExceptionCallback[ExceptionType] = ExceptionCallback;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcDebugInvalidateInstructionCache (\r
+  IN EFI_DEBUG_SUPPORT_PROTOCOL          *This,\r
+  IN UINTN                               ProcessorIndex,\r
+  IN VOID                                *Start,\r
+  IN UINT64                              Length\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This EBC debugger protocol service is called by the debug agent.  Required\r
+  for DebugSupport compliance but is only stubbed out for EBC.\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EbcDebugSignalException (\r
+  IN EFI_EXCEPTION_TYPE                   ExceptionType,\r
+  IN EXCEPTION_FLAGS                      ExceptionFlags,\r
+  IN VM_CONTEXT                           *VmPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The VM interpreter calls this function when an exception is detected.\r
+\r
+Arguments:\r
+\r
+  VmPtr - pointer to a VM context for passing info to the EFI debugger.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS if it returns at all\r
+\r
+--*/\r
+{\r
+  EFI_SYSTEM_CONTEXT_EBC  EbcContext;\r
+  EFI_SYSTEM_CONTEXT      SystemContext;\r
+\r
+  ASSERT ((ExceptionType >= 0) && (ExceptionType <= MAX_EBC_EXCEPTION));\r
+  //\r
+  // Save the exception in the context passed in\r
+  //\r
+  VmPtr->ExceptionFlags |= ExceptionFlags;\r
+  VmPtr->LastException = ExceptionType;\r
+  //\r
+  // If it's a fatal exception, then flag it in the VM context in case an\r
+  // attached debugger tries to return from it.\r
+  //\r
+  if (ExceptionFlags & EXCEPTION_FLAG_FATAL) {\r
+    VmPtr->StopFlags |= STOPFLAG_APP_DONE;\r
+  }\r
+\r
+  //\r
+  // If someone's registered for exception callbacks, then call them.\r
+  //\r
+  // EBC driver will register default exception callback to report the\r
+  // status code via the status code API\r
+  //\r
+  if (mDebugExceptionCallback[ExceptionType] != NULL) {\r
+\r
+    //\r
+    // Initialize the context structure\r
+    //\r
+    EbcContext.R0                   = VmPtr->R[0];\r
+    EbcContext.R1                   = VmPtr->R[1];\r
+    EbcContext.R2                   = VmPtr->R[2];\r
+    EbcContext.R3                   = VmPtr->R[3];\r
+    EbcContext.R4                   = VmPtr->R[4];\r
+    EbcContext.R5                   = VmPtr->R[5];\r
+    EbcContext.R6                   = VmPtr->R[6];\r
+    EbcContext.R7                   = VmPtr->R[7];\r
+    EbcContext.Ip                   = (UINT64)(UINTN)VmPtr->Ip;\r
+    EbcContext.Flags                = VmPtr->Flags;\r
+    EbcContext.ControlFlags         = 0;\r
+    SystemContext.SystemContextEbc  = &EbcContext;\r
+\r
+    mDebugExceptionCallback[ExceptionType] (ExceptionType, SystemContext);\r
+    //\r
+    // Restore the context structure and continue to execute\r
+    //\r
+    VmPtr->R[0]  = EbcContext.R0;\r
+    VmPtr->R[1]  = EbcContext.R1;\r
+    VmPtr->R[2]  = EbcContext.R2;\r
+    VmPtr->R[3]  = EbcContext.R3;\r
+    VmPtr->R[4]  = EbcContext.R4;\r
+    VmPtr->R[5]  = EbcContext.R5;\r
+    VmPtr->R[6]  = EbcContext.R6;\r
+    VmPtr->R[7]  = EbcContext.R7;\r
+    VmPtr->Ip    = (VMIP)(UINTN)EbcContext.Ip;\r
+    VmPtr->Flags = EbcContext.Flags;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+InitializeEbcCallback (\r
+  IN EFI_DEBUG_SUPPORT_PROTOCOL  *This\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  To install default Callback function for the VM interpreter.\r
+\r
+Arguments:\r
+\r
+  This - pointer to the instance of DebugSupport protocol\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  INTN       Index;\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  // For ExceptionCallback\r
+  //\r
+  for (Index = 0; Index <= MAX_EBC_EXCEPTION; Index++) {\r
+    EbcDebugRegisterExceptionCallback (\r
+      This,\r
+      0,\r
+      CommonEbcExceptionHandler,\r
+      Index\r
+      );\r
+  }\r
+\r
+  //\r
+  // For PeriodicCallback\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  EbcPeriodicNotifyFunction,\r
+                  &mVmPtr,\r
+                  &mEbcPeriodicEvent\r
+                  );\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->SetTimer (\r
+                  mEbcPeriodicEvent,\r
+                  TimerPeriodic,\r
+                  EBC_VM_PERIODIC_CALLBACK_RATE\r
+                  );\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+VOID\r
+CommonEbcExceptionHandler (\r
+  IN EFI_EXCEPTION_TYPE   InterruptType,\r
+  IN EFI_SYSTEM_CONTEXT   SystemContext\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The default Exception Callback for the VM interpreter.\r
+  In this function, we report status code, and print debug information\r
+  about EBC_CONTEXT, then dead loop.\r
+\r
+Arguments:\r
+\r
+  InterruptType - Interrupt type.\r
+  SystemContext - EBC system context.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  //\r
+  // We deadloop here to make it easy to debug this issue.\r
+  //\r
+  ASSERT (FALSE);\r
+\r
+  return ;\r
+}\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+EbcPeriodicNotifyFunction (\r
+  IN EFI_EVENT     Event,\r
+  IN VOID          *Context\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The periodic callback function for EBC VM interpreter, which is used\r
+  to support the EFI debug support protocol.\r
+\r
+Arguments:\r
+\r
+  Event   - The Periodic Callback Event.\r
+  Context - It should be the address of VM_CONTEXT pointer.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  VM_CONTEXT *VmPtr;\r
+\r
+  VmPtr = *(VM_CONTEXT **)Context;\r
+\r
+  if (VmPtr != NULL) {\r
+    EbcDebugPeriodic (VmPtr);\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EbcDebugPeriodic (\r
+  IN VM_CONTEXT *VmPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The VM interpreter calls this function on a periodic basis to support\r
+  the EFI debug support protocol.\r
+\r
+Arguments:\r
+\r
+  VmPtr - pointer to a VM context for passing info to the debugger.\r
+\r
+Returns:\r
+\r
+  Standard EFI status.\r
+\r
+--*/\r
+{\r
+  EFI_SYSTEM_CONTEXT_EBC   EbcContext;\r
+  EFI_SYSTEM_CONTEXT       SystemContext;\r
+\r
+  //\r
+  // If someone's registered for periodic callbacks, then call them.\r
+  //\r
+  if (mDebugPeriodicCallback != NULL) {\r
+\r
+    //\r
+    // Initialize the context structure\r
+    //\r
+    EbcContext.R0                   = VmPtr->R[0];\r
+    EbcContext.R1                   = VmPtr->R[1];\r
+    EbcContext.R2                   = VmPtr->R[2];\r
+    EbcContext.R3                   = VmPtr->R[3];\r
+    EbcContext.R4                   = VmPtr->R[4];\r
+    EbcContext.R5                   = VmPtr->R[5];\r
+    EbcContext.R6                   = VmPtr->R[6];\r
+    EbcContext.R7                   = VmPtr->R[7];\r
+    EbcContext.Ip                   = (UINT64)(UINTN)VmPtr->Ip;\r
+    EbcContext.Flags                = VmPtr->Flags;\r
+    EbcContext.ControlFlags         = 0;\r
+    SystemContext.SystemContextEbc  = &EbcContext;\r
+\r
+    mDebugPeriodicCallback (SystemContext);\r
+\r
+    //\r
+    // Restore the context structure and continue to execute\r
+    //\r
+    VmPtr->R[0]  = EbcContext.R0;\r
+    VmPtr->R[1]  = EbcContext.R1;\r
+    VmPtr->R[2]  = EbcContext.R2;\r
+    VmPtr->R[3]  = EbcContext.R3;\r
+    VmPtr->R[4]  = EbcContext.R4;\r
+    VmPtr->R[5]  = EbcContext.R5;\r
+    VmPtr->R[6]  = EbcContext.R6;\r
+    VmPtr->R[7]  = EbcContext.R7;\r
+    VmPtr->Ip    = (VMIP)(UINTN)EbcContext.Ip;\r
+    VmPtr->Flags = EbcContext.Flags;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcUnloadImage (\r
+  IN EFI_EBC_PROTOCOL   *This,\r
+  IN EFI_HANDLE         ImageHandle\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This routine is called by the core when an image is being unloaded from\r
+  memory. Basically we now have the opportunity to do any necessary cleanup.\r
+  Typically this will include freeing any memory allocated for thunk-creation.\r
+\r
+Arguments:\r
+\r
+  This          - protocol instance pointer\r
+  ImageHandle   - handle to the image being unloaded.\r
+\r
+Returns:\r
+\r
+  EFI_INVALID_PARAMETER  - the ImageHandle passed in was not found in\r
+                           the internal list of EBC image handles.\r
+  EFI_STATUS             - completed successfully\r
+\r
+--*/\r
+{\r
+  EBC_THUNK_LIST  *ThunkList;\r
+  EBC_THUNK_LIST  *NextThunkList;\r
+  EBC_IMAGE_LIST  *ImageList;\r
+  EBC_IMAGE_LIST  *PrevImageList;\r
+  //\r
+  // First go through our list of known image handles and see if we've already\r
+  // created an image list element for this image handle.\r
+  //\r
+  ReturnEBCStackByHandle(ImageHandle);\r
+  PrevImageList = NULL;\r
+  for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {\r
+    if (ImageList->ImageHandle == ImageHandle) {\r
+      break;\r
+    }\r
+    //\r
+    // Save the previous so we can connect the lists when we remove this one\r
+    //\r
+    PrevImageList = ImageList;\r
+  }\r
+\r
+  if (ImageList == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Free up all the thunk buffers and thunks list elements for this image\r
+  // handle.\r
+  //\r
+  ThunkList = ImageList->ThunkList;\r
+  while (ThunkList != NULL) {\r
+    NextThunkList = ThunkList->Next;\r
+    FreePool (ThunkList->ThunkBuffer);\r
+    FreePool (ThunkList);\r
+    ThunkList = NextThunkList;\r
+  }\r
+  //\r
+  // Now remove this image list element from the chain\r
+  //\r
+  if (PrevImageList == NULL) {\r
+    //\r
+    // Remove from head\r
+    //\r
+    mEbcImageList = ImageList->Next;\r
+  } else {\r
+    PrevImageList->Next = ImageList->Next;\r
+  }\r
+  //\r
+  // Now free up the image list element\r
+  //\r
+  FreePool (ImageList);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EbcAddImageThunk (\r
+  IN EFI_HANDLE      ImageHandle,\r
+  IN VOID            *ThunkBuffer,\r
+  IN UINT32          ThunkSize\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Add a thunk to our list of thunks for a given image handle.\r
+  Also flush the instruction cache since we've written thunk code\r
+  to memory that will be executed eventually.\r
+\r
+Arguments:\r
+\r
+  ImageHandle - the image handle to which the thunk is tied\r
+  ThunkBuffer - the buffer we've created/allocated\r
+  ThunkSize    - the size of the thunk memory allocated\r
+\r
+Returns:\r
+\r
+  EFI_OUT_OF_RESOURCES    - memory allocation failed\r
+  EFI_SUCCESS             - successful completion\r
+\r
+--*/\r
+{\r
+  EBC_THUNK_LIST  *ThunkList;\r
+  EBC_IMAGE_LIST  *ImageList;\r
+  EFI_STATUS      Status;\r
+\r
+  //\r
+  // It so far so good, then flush the instruction cache\r
+  //\r
+  if (mEbcICacheFlush != NULL) {\r
+    Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS) (UINTN) ThunkBuffer, ThunkSize);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  //\r
+  // Go through our list of known image handles and see if we've already\r
+  // created a image list element for this image handle.\r
+  //\r
+  for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {\r
+    if (ImageList->ImageHandle == ImageHandle) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (ImageList == NULL) {\r
+    //\r
+    // Allocate a new one\r
+    //\r
+    ImageList = AllocatePool (sizeof (EBC_IMAGE_LIST));\r
+\r
+    if (ImageList == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    ImageList->ThunkList    = NULL;\r
+    ImageList->ImageHandle  = ImageHandle;\r
+    ImageList->Next         = mEbcImageList;\r
+    mEbcImageList           = ImageList;\r
+  }\r
+  //\r
+  // Ok, now create a new thunk element to add to the list\r
+  //\r
+  ThunkList = AllocatePool (sizeof (EBC_THUNK_LIST));\r
+\r
+  if (ThunkList == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Add it to the head of the list\r
+  //\r
+  ThunkList->Next         = ImageList->ThunkList;\r
+  ThunkList->ThunkBuffer  = ThunkBuffer;\r
+  ImageList->ThunkList    = ThunkList;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcRegisterICacheFlush (\r
+  IN EFI_EBC_PROTOCOL   *This,\r
+  IN EBC_ICACHE_FLUSH   Flush\r
+  )\r
+{\r
+  mEbcICacheFlush = Flush;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EbcGetVersion (\r
+  IN EFI_EBC_PROTOCOL   *This,\r
+  IN OUT UINT64         *Version\r
+  )\r
+{\r
+  if (Version == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *Version = GetVmVersion ();\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+GetEBCStack(\r
+  EFI_HANDLE Handle,\r
+  VOID       **StackBuffer,\r
+  UINTN      *BufferIndex\r
+  )\r
+{\r
+  UINTN   Index;\r
+  EFI_TPL OldTpl;\r
+  OldTpl = gBS->RaiseTPL(TPL_HIGH_LEVEL);\r
+  for (Index = 0; Index < mStackNum; Index ++) {\r
+    if (mStackBufferIndex[Index] == NULL) {\r
+      mStackBufferIndex[Index] = Handle;\r
+      break;\r
+    }\r
+  }\r
+  gBS->RestoreTPL(OldTpl);\r
+  if (Index == mStackNum) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  *BufferIndex = Index;\r
+  *StackBuffer = mStackBuffer[Index];\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+ReturnEBCStack(\r
+  UINTN Index\r
+  )\r
+{\r
+  mStackBufferIndex[Index] =NULL;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+ReturnEBCStackByHandle(\r
+  EFI_HANDLE Handle\r
+  )\r
+{\r
+  UINTN Index;\r
+  for (Index = 0; Index < mStackNum; Index ++) {\r
+    if (mStackBufferIndex[Index] == Handle) {\r
+      break;\r
+    }\r
+  }\r
+  if (Index == mStackNum) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  mStackBufferIndex[Index] = NULL;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+InitEBCStack (\r
+  VOID\r
+  )\r
+{\r
+  for (mStackNum = 0; mStackNum < MAX_STACK_NUM; mStackNum ++) {\r
+    mStackBuffer[mStackNum] = AllocatePool(STACK_POOL_SIZE);\r
+    mStackBufferIndex[mStackNum] = NULL;\r
+    if (mStackBuffer[mStackNum] == NULL) {\r
+      break;\r
+    }\r
+  }\r
+  if (mStackNum == 0) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FreeEBCStack(\r
+  VOID\r
+  )\r
+{\r
+  UINTN Index;\r
+  for (Index = 0; Index < mStackNum; Index ++) {\r
+    FreePool(mStackBuffer[Index]);\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+STATIC\r
+EFI_STATUS\r
+InitEbcVmTestProtocol (\r
+  IN EFI_HANDLE     *IHandle\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Produce an EBC VM test protocol that can be used for regression tests.\r
+\r
+Arguments:\r
+\r
+  IHandle - handle on which to install the protocol.\r
+\r
+Returns:\r
+\r
+  EFI_OUT_OF_RESOURCES  - memory allocation failed\r
+  EFI_SUCCESS           - successful completion\r
+\r
+--*/\r
+{\r
+  EFI_HANDLE Handle;\r
+  EFI_STATUS Status;\r
+  EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;\r
+\r
+  //\r
+  // Allocate memory for the protocol, then fill in the fields\r
+  //\r
+  EbcVmTestProtocol = AllocatePool (sizeof (EFI_EBC_VM_TEST_PROTOCOL));\r
+  if (EbcVmTestProtocol == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  EbcVmTestProtocol->Execute      = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;\r
+\r
+  DEBUG_CODE_BEGIN ();\r
+    EbcVmTestProtocol->Assemble     = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;\r
+    EbcVmTestProtocol->Disassemble  = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;\r
+  DEBUG_CODE_END ();\r
+\r
+  //\r
+  // Publish the protocol\r
+  //\r
+  Handle  = NULL;\r
+  Status  = gBS->InstallProtocolInterface (&Handle, &mEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (EbcVmTestProtocol);\r
+  }\r
+  return Status;\r
+}\r
+STATIC\r
+EFI_STATUS\r
+EbcVmTestUnsupported ()\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r