Initial import.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
932
EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c
Normal file
932
EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c
Normal file
@@ -0,0 +1,932 @@
|
||||
/*++
|
||||
|
||||
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;
|
||||
|
||||
//
|
||||
// Function prototypes
|
||||
//
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
InitializeEbcDriver (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
);
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
//
|
||||
// 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 = NULL;
|
||||
static EFI_GUID mEfiEbcVmTestProtocolGuid = EFI_EBC_VM_TEST_PROTOCOL_GUID;
|
||||
|
||||
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;
|
||||
|
||||
//
|
||||
// Allocate memory for our protocol. Then fill in the blanks.
|
||||
//
|
||||
Status = gBS->AllocatePool (
|
||||
EfiBootServicesData,
|
||||
sizeof (EFI_EBC_PROTOCOL),
|
||||
(VOID **) &EbcProtocol
|
||||
);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
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) {
|
||||
gBS->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)) {
|
||||
gBS->FreePool (EbcProtocol);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Allocate memory for our debug protocol. Then fill in the blanks.
|
||||
//
|
||||
Status = gBS->AllocatePool (
|
||||
EfiBootServicesData,
|
||||
sizeof (EFI_DEBUG_SUPPORT_PROTOCOL),
|
||||
(VOID **) &EbcDebugProtocol
|
||||
);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
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)) {
|
||||
gBS->FreePool (EbcDebugProtocol);
|
||||
}
|
||||
//
|
||||
// Produce a VM test interface protocol. Not required for execution.
|
||||
//
|
||||
DEBUG_CODE (
|
||||
InitEbcVmTestProtocol (&ImageHandle);
|
||||
);
|
||||
|
||||
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
|
||||
|
||||
--*/
|
||||
{
|
||||
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
|
||||
PeriodicCallback - pointer to the function to call periodically
|
||||
|
||||
Returns:
|
||||
|
||||
Always EFI_SUCCESS
|
||||
|
||||
--*/
|
||||
{
|
||||
mDebugExceptionCallback = 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;
|
||||
EFI_STATUS_CODE_VALUE StatusCodeValue;
|
||||
BOOLEAN Report;
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
//
|
||||
// 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;
|
||||
SystemContext.SystemContextEbc = &EbcContext;
|
||||
//
|
||||
// If someone's registered for exception callbacks, then call them.
|
||||
// Otherwise report the status code via the status code API
|
||||
//
|
||||
if (mDebugExceptionCallback != NULL) {
|
||||
mDebugExceptionCallback (ExceptionType, SystemContext);
|
||||
}
|
||||
//
|
||||
// Determine if we should report the exception. We report all of them by default,
|
||||
// but if a debugger is attached don't report the breakpoint, debug, and step exceptions.
|
||||
// Note that EXCEPT_EBC_OVERFLOW is never reported by this VM implementation, so is
|
||||
// not included in the switch statement.
|
||||
//
|
||||
Report = TRUE;
|
||||
switch (ExceptionType) {
|
||||
case EXCEPT_EBC_UNDEFINED:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_UNDEFINED;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_DIVIDE_ERROR:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_DIVIDE_ERROR;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_DEBUG:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_DEBUG;
|
||||
Report = (BOOLEAN) ((mDebugExceptionCallback == NULL) ? TRUE : FALSE);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_BREAKPOINT:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_BREAKPOINT;
|
||||
Report = (BOOLEAN) ((mDebugExceptionCallback == NULL) ? TRUE : FALSE);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_INVALID_OPCODE:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_INVALID_OPCODE;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_STACK_FAULT:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_STACK_FAULT;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_ALIGNMENT_CHECK:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_ALIGNMENT_CHECK;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_INSTRUCTION_ENCODING:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_INSTRUCTION_ENCODING;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_BAD_BREAK:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_BAD_BREAK;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_STEP:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_STEP;
|
||||
Report = (BOOLEAN) ((mDebugExceptionCallback == NULL) ? TRUE : FALSE);
|
||||
break;
|
||||
|
||||
default:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_NON_SPECIFIC;
|
||||
break;
|
||||
}
|
||||
//
|
||||
// If we determined that we should report the condition, then do so now.
|
||||
//
|
||||
if (Report) {
|
||||
REPORT_STATUS_CODE (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED, StatusCodeValue);
|
||||
}
|
||||
|
||||
switch (ExceptionType) {
|
||||
//
|
||||
// If ReportStatusCode returned, then for most exceptions we do an assert. The
|
||||
// ExceptionType++ is done simply to force the ASSERT() condition to be met.
|
||||
// For breakpoints, assume a debugger did not insert a software breakpoint
|
||||
// and skip the instruction.
|
||||
//
|
||||
case EXCEPT_EBC_BREAKPOINT:
|
||||
VmPtr->Ip += 2;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_STEP:
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_UNDEFINED:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_UNDEFINED);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_DIVIDE_ERROR:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_DIVIDE_ERROR);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_DEBUG:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_DEBUG);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_INVALID_OPCODE:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_INVALID_OPCODE);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_STACK_FAULT:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_STACK_FAULT);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_ALIGNMENT_CHECK:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_ALIGNMENT_CHECK);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_INSTRUCTION_ENCODING:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_INSTRUCTION_ENCODING);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_BAD_BREAK:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_BAD_BREAK);
|
||||
break;
|
||||
|
||||
default:
|
||||
//
|
||||
// Unknown
|
||||
//
|
||||
ASSERT (0);
|
||||
break;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
--*/
|
||||
{
|
||||
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.
|
||||
//
|
||||
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;
|
||||
gBS->FreePool (ThunkList->ThunkBuffer);
|
||||
gBS->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
|
||||
//
|
||||
gBS->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
|
||||
//
|
||||
Status = gBS->AllocatePool (
|
||||
EfiBootServicesData,
|
||||
sizeof (EBC_IMAGE_LIST),
|
||||
(VOID **) &ImageList
|
||||
);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
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
|
||||
//
|
||||
Status = gBS->AllocatePool (
|
||||
EfiBootServicesData,
|
||||
sizeof (EBC_THUNK_LIST),
|
||||
(VOID **) &ThunkList
|
||||
);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
//
|
||||
Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_EBC_VM_TEST_PROTOCOL), (VOID **) &EbcVmTestProtocol);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
EbcVmTestProtocol->Execute = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;
|
||||
|
||||
DEBUG_CODE(
|
||||
EbcVmTestProtocol->Assemble = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;
|
||||
EbcVmTestProtocol->Disassemble = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;
|
||||
);
|
||||
|
||||
//
|
||||
// Publish the protocol
|
||||
//
|
||||
Handle = NULL;
|
||||
Status = gBS->InstallProtocolInterface (&Handle, &mEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);
|
||||
if (EFI_ERROR (Status)) {
|
||||
gBS->FreePool (EbcVmTestProtocol);
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EbcVmTestUnsupported ()
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
Reference in New Issue
Block a user