+++ /dev/null
-/*++\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