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