diff options
| author | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
|---|---|---|
| committer | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
| commit | 7e2ccccace24636f29ddc210b94606abd4c7e42b (patch) | |
| tree | 545d43ea12671048956cafeb12303e84d601e571 /MdeModulePkg/Universal/EbcDxe/EbcInt.c | |
| parent | 27b044605cd5f6b33a3d231576003850b3fe305b (diff) | |
| download | edk2-trunk.tar.xz | |
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'MdeModulePkg/Universal/EbcDxe/EbcInt.c')
| -rw-r--r-- | MdeModulePkg/Universal/EbcDxe/EbcInt.c | 3134 |
1 files changed, 1567 insertions, 1567 deletions
diff --git a/MdeModulePkg/Universal/EbcDxe/EbcInt.c b/MdeModulePkg/Universal/EbcDxe/EbcInt.c index d2254c2765..56d1d5f679 100644 --- a/MdeModulePkg/Universal/EbcDxe/EbcInt.c +++ b/MdeModulePkg/Universal/EbcDxe/EbcInt.c @@ -1,1567 +1,1567 @@ -/** @file
- Top level module for the EBC virtual machine implementation.
- Provides auxiliary support routines for the VM. That is, routines
- that are not particularly related to VM execution of EBC instructions.
-
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "EbcInt.h"
-#include "EbcExecute.h"
-#include "EbcDebuggerHook.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 EBC_THUNK_LIST;
-struct _EBC_THUNK_LIST {
- VOID *ThunkBuffer;
- EBC_THUNK_LIST *Next;
-};
-
-typedef struct _EBC_IMAGE_LIST EBC_IMAGE_LIST;
-struct _EBC_IMAGE_LIST {
- EBC_IMAGE_LIST *Next;
- EFI_HANDLE ImageHandle;
- EBC_THUNK_LIST *ThunkList;
-};
-
-/**
- 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.
-
- @param This A pointer to the EFI_EBC_PROTOCOL instance.
- @param ImageHandle Handle of image for which the thunk is being
- created.
-
- @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
- internal list of EBC image handles.
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcUnloadImage (
- IN EFI_EBC_PROTOCOL *This,
- IN EFI_HANDLE ImageHandle
- );
-
-/**
- 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().
-
- @param This A pointer to the EFI_EBC_PROTOCOL instance.
- @param ImageHandle Handle of image for which the thunk is being
- created. The EBC interpreter may use this to
- keep track of any resource allocations
- performed in loading and executing the image.
- @param EbcEntryPoint Address of the actual EBC entry point or
- protocol service the thunk should call.
- @param Thunk Returned pointer to a thunk created.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
- @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcCreateThunk (
- IN EFI_EBC_PROTOCOL *This,
- IN EFI_HANDLE ImageHandle,
- IN VOID *EbcEntryPoint,
- OUT VOID **Thunk
- );
-
-/**
- Called to get the version of the interpreter.
-
- @param This A pointer to the EFI_EBC_PROTOCOL instance.
- @param Version Pointer to where to store the returned version
- of the interpreter.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_INVALID_PARAMETER Version pointer is NULL.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcGetVersion (
- IN EFI_EBC_PROTOCOL *This,
- IN OUT UINT64 *Version
- );
-
-/**
- To install default Callback function for the VM interpreter.
-
- @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
- instance.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval Others Some error occurs when creating periodic event.
-
-**/
-EFI_STATUS
-EFIAPI
-InitializeEbcCallback (
- IN EFI_DEBUG_SUPPORT_PROTOCOL *This
- );
-
-/**
- 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.
-
- @param InterruptType Interrupt type.
- @param SystemContext EBC system context.
-
-**/
-VOID
-EFIAPI
-CommonEbcExceptionHandler (
- IN EFI_EXCEPTION_TYPE InterruptType,
- IN EFI_SYSTEM_CONTEXT SystemContext
- );
-
-/**
- The periodic callback function for EBC VM interpreter, which is used
- to support the EFI debug support protocol.
-
- @param Event The Periodic Callback Event.
- @param Context It should be the address of VM_CONTEXT pointer.
-
-**/
-VOID
-EFIAPI
-EbcPeriodicNotifyFunction (
- IN EFI_EVENT Event,
- IN VOID *Context
- );
-
-/**
- The VM interpreter calls this function on a periodic basis to support
- the EFI debug support protocol.
-
- @param VmPtr Pointer to a VM context for passing info to the
- debugger.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-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.
-//
-
-/**
- Produces an EBC VM test protocol that can be used for regression tests.
-
- @param IHandle Handle on which to install the protocol.
-
- @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-InitEbcVmTestProtocol (
- IN EFI_HANDLE *IHandle
- );
-
-/**
- Returns the EFI_UNSUPPORTED Status.
-
- @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcVmTestUnsupported (
- VOID
- );
-
-/**
- Registers a callback function that the EBC interpreter calls to flush the
- processor instruction cache following creation of thunks.
-
- @param This A pointer to the EFI_EBC_PROTOCOL instance.
- @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcRegisterICacheFlush (
- IN EFI_EBC_PROTOCOL *This,
- IN EBC_ICACHE_FLUSH Flush
- );
-
-/**
- This EBC debugger protocol service is called by the debug agent
-
- @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
- instance.
- @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
- maximum supported processor index is returned.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcDebugGetMaximumProcessorIndex (
- IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
- OUT UINTN *MaxProcessorIndex
- );
-
-/**
- This protocol service is called by the debug agent to register a function
- for us to call on a periodic basis.
-
- @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
- instance.
- @param ProcessorIndex Specifies which processor the callback function
- applies to.
- @param PeriodicCallback A pointer to a function of type
- PERIODIC_CALLBACK that is the main periodic
- entry point of the debug agent. It receives as a
- parameter a pointer to the full context of the
- interrupted execution thread.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
- callback function was previously registered.
- @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
- callback function was previously registered.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcDebugRegisterPeriodicCallback (
- IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
- IN UINTN ProcessorIndex,
- IN EFI_PERIODIC_CALLBACK PeriodicCallback
- );
-
-/**
- This protocol service is called by the debug agent to register a function
- for us to call when we detect an exception.
-
- @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
- instance.
- @param ProcessorIndex Specifies which processor the callback function
- applies to.
- @param ExceptionCallback A pointer to a function of type
- EXCEPTION_CALLBACK that is called when the
- processor exception specified by ExceptionType
- occurs. Passing NULL unregisters any previously
- registered function associated with
- ExceptionType.
- @param ExceptionType Specifies which processor exception to hook.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
- callback function was previously registered.
- @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
- MAX_EBC_EXCEPTION.
- @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
- callback function was previously registered.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcDebugRegisterExceptionCallback (
- IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
- IN UINTN ProcessorIndex,
- IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
- IN EFI_EXCEPTION_TYPE ExceptionType
- );
-
-/**
- This EBC debugger protocol service is called by the debug agent. Required
- for DebugSupport compliance but is only stubbed out for EBC.
-
- @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
- instance.
- @param ProcessorIndex Specifies which processor the callback function
- applies to.
- @param Start StartSpecifies the physical base of the memory
- range to be invalidated.
- @param Length Specifies the minimum number of bytes in the
- processor's instruction cache to invalidate.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-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.
-//
-EBC_IMAGE_LIST *mEbcImageList = NULL;
-
-//
-// Callback function to flush the icache after thunk creation
-//
-EBC_ICACHE_FLUSH mEbcICacheFlush;
-
-//
-// These get set via calls by the debug agent
-//
-EFI_PERIODIC_CALLBACK mDebugPeriodicCallback = NULL;
-EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = { NULL };
-
-VOID *mStackBuffer[MAX_STACK_NUM];
-EFI_HANDLE mStackBufferIndex[MAX_STACK_NUM];
-UINTN mStackNum = 0;
-
-//
-// Event for Periodic callback
-//
-EFI_EVENT mEbcPeriodicEvent;
-VM_CONTEXT *mVmPtr = NULL;
-
-/**
- Check whether the emulator supports executing a certain PE/COFF image
-
- @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
- structure
- @param[in] ImageType Whether the image is an application, a boot time
- driver or a runtime driver.
- @param[in] DevicePath Path to device where the image originated
- (e.g., a PCI option ROM)
-
- @retval TRUE The image is supported by the emulator
- @retval FALSE The image is not supported by the emulator.
-**/
-BOOLEAN
-EFIAPI
-EbcIsImageSupported (
- IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
- IN UINT16 ImageType,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL
- )
-{
- if ((ImageType != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) &&
- (ImageType != EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER))
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
-/**
- Register a supported PE/COFF image with the emulator. After this call
- completes successfully, the PE/COFF image may be started as usual, and
- it is the responsibility of the emulator implementation that any branch
- into the code section of the image (including returns from functions called
- from the foreign code) is executed as if it were running on the machine
- type it was built for.
-
- @param[in] This This pointer for
- EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL structure
- @param[in] ImageBase The base address in memory of the PE/COFF image
- @param[in] ImageSize The size in memory of the PE/COFF image
- @param[in,out] EntryPoint The entry point of the PE/COFF image. Passed by
- reference so that the emulator may modify it.
-
- @retval EFI_SUCCESS The image was registered with the emulator and
- can be started as usual.
- @retval other The image could not be registered.
-
- If the PE/COFF machine type or image type are not supported by the emulator,
- then ASSERT().
-**/
-EFI_STATUS
-EFIAPI
-EbcRegisterImage (
- IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
- IN EFI_PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize,
- IN OUT EFI_IMAGE_ENTRY_POINT *EntryPoint
- )
-{
- DEBUG_CODE_BEGIN ();
- PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
- EFI_STATUS Status;
-
- ZeroMem (&ImageContext, sizeof (ImageContext));
-
- ImageContext.Handle = (VOID *)(UINTN)ImageBase;
- ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
-
- Status = PeCoffLoaderGetImageInfo (&ImageContext);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- ASSERT (ImageContext.Machine == EFI_IMAGE_MACHINE_EBC);
- ASSERT (
- ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ||
- ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
- );
- DEBUG_CODE_END ();
-
- EbcRegisterICacheFlush (
- NULL,
- (EBC_ICACHE_FLUSH)InvalidateInstructionCacheRange
- );
-
- return EbcCreateThunk (
- NULL,
- (VOID *)(UINTN)ImageBase,
- (VOID *)(UINTN)*EntryPoint,
- (VOID **)EntryPoint
- );
-}
-
-/**
- Unregister a PE/COFF image that has been registered with the emulator.
- This should be done before the image is unloaded from memory.
-
- @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
- structure
- @param[in] ImageBase The base address in memory of the PE/COFF image
-
- @retval EFI_SUCCESS The image was unregistered with the emulator.
- @retval other Image could not be unloaded.
-**/
-EFI_STATUS
-EFIAPI
-EbcUnregisterImage (
- IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
- IN EFI_PHYSICAL_ADDRESS ImageBase
- )
-{
- return EbcUnloadImage (NULL, (VOID *)(UINTN)ImageBase);
-}
-
-STATIC EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL mPeCoffEmuProtocol = {
- EbcIsImageSupported,
- EbcRegisterImage,
- EbcUnregisterImage,
- EDKII_PECOFF_IMAGE_EMULATOR_VERSION,
- EFI_IMAGE_MACHINE_EBC
-};
-
-/**
- Initializes the VM EFI interface. Allocates memory for the VM interface
- and registers the VM protocol.
-
- @param ImageHandle EFI image handle.
- @param SystemTable Pointer to the EFI system table.
-
- @return Standard EFI status code.
-
-**/
-EFI_STATUS
-EFIAPI
-InitializeEbcDriver (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- 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->InstallMultipleProtocolInterfaces (
- &ImageHandle,
- &gEfiEbcProtocolGuid,
- EbcProtocol,
- &gEdkiiPeCoffImageEmulatorProtocolGuid,
- &mPeCoffEmuProtocol,
- NULL
- );
- 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 ();
-
- EbcDebuggerHookInit (ImageHandle, EbcDebugProtocol);
-
- 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;
-}
-
-/**
- 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().
-
- @param This A pointer to the EFI_EBC_PROTOCOL instance.
- @param ImageHandle Handle of image for which the thunk is being
- created. The EBC interpreter may use this to
- keep track of any resource allocations
- performed in loading and executing the image.
- @param EbcEntryPoint Address of the actual EBC entry point or
- protocol service the thunk should call.
- @param Thunk Returned pointer to a thunk created.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
- @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcCreateThunk (
- IN EFI_EBC_PROTOCOL *This,
- IN EFI_HANDLE ImageHandle,
- IN VOID *EbcEntryPoint,
- OUT VOID **Thunk
- )
-{
- EFI_STATUS Status;
-
- Status = EbcCreateThunks (
- ImageHandle,
- EbcEntryPoint,
- Thunk,
- FLAG_THUNK_ENTRY_POINT
- );
- return Status;
-}
-
-/**
- This EBC debugger protocol service is called by the debug agent
-
- @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
- instance.
- @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
- maximum supported processor index is returned.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcDebugGetMaximumProcessorIndex (
- IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
- OUT UINTN *MaxProcessorIndex
- )
-{
- *MaxProcessorIndex = 0;
- return EFI_SUCCESS;
-}
-
-/**
- This protocol service is called by the debug agent to register a function
- for us to call on a periodic basis.
-
- @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
- instance.
- @param ProcessorIndex Specifies which processor the callback function
- applies to.
- @param PeriodicCallback A pointer to a function of type
- PERIODIC_CALLBACK that is the main periodic
- entry point of the debug agent. It receives as a
- parameter a pointer to the full context of the
- interrupted execution thread.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
- callback function was previously registered.
- @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
- callback function was previously registered.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcDebugRegisterPeriodicCallback (
- IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
- IN UINTN ProcessorIndex,
- IN EFI_PERIODIC_CALLBACK PeriodicCallback
- )
-{
- if ((mDebugPeriodicCallback == NULL) && (PeriodicCallback == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if ((mDebugPeriodicCallback != NULL) && (PeriodicCallback != NULL)) {
- return EFI_ALREADY_STARTED;
- }
-
- mDebugPeriodicCallback = PeriodicCallback;
- return EFI_SUCCESS;
-}
-
-/**
- This protocol service is called by the debug agent to register a function
- for us to call when we detect an exception.
-
- @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
- instance.
- @param ProcessorIndex Specifies which processor the callback function
- applies to.
- @param ExceptionCallback A pointer to a function of type
- EXCEPTION_CALLBACK that is called when the
- processor exception specified by ExceptionType
- occurs. Passing NULL unregisters any previously
- registered function associated with
- ExceptionType.
- @param ExceptionType Specifies which processor exception to hook.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
- callback function was previously registered.
- @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
- MAX_EBC_EXCEPTION.
- @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
- callback function was previously registered.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcDebugRegisterExceptionCallback (
- IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
- IN UINTN ProcessorIndex,
- IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
- IN EFI_EXCEPTION_TYPE ExceptionType
- )
-{
- 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;
-}
-
-/**
- This EBC debugger protocol service is called by the debug agent. Required
- for DebugSupport compliance but is only stubbed out for EBC.
-
- @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
- instance.
- @param ProcessorIndex Specifies which processor the callback function
- applies to.
- @param Start StartSpecifies the physical base of the memory
- range to be invalidated.
- @param Length Specifies the minimum number of bytes in the
- processor's instruction cache to invalidate.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcDebugInvalidateInstructionCache (
- IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
- IN UINTN ProcessorIndex,
- IN VOID *Start,
- IN UINT64 Length
- )
-{
- return EFI_SUCCESS;
-}
-
-/**
- The VM interpreter calls this function when an exception is detected.
-
- @param ExceptionType Specifies the processor exception detected.
- @param ExceptionFlags Specifies the exception context.
- @param VmPtr Pointer to a VM context for passing info to the
- EFI debugger.
-
- @retval EFI_SUCCESS This function completed successfully.
-
-**/
-EFI_STATUS
-EbcDebugSignalException (
- IN EFI_EXCEPTION_TYPE ExceptionType,
- IN EXCEPTION_FLAGS ExceptionFlags,
- IN VM_CONTEXT *VmPtr
- )
-{
- 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 = (UINTN)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) != 0) {
- 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 = (UINT64)VmPtr->Gpr[0];
- EbcContext.R1 = (UINT64)VmPtr->Gpr[1];
- EbcContext.R2 = (UINT64)VmPtr->Gpr[2];
- EbcContext.R3 = (UINT64)VmPtr->Gpr[3];
- EbcContext.R4 = (UINT64)VmPtr->Gpr[4];
- EbcContext.R5 = (UINT64)VmPtr->Gpr[5];
- EbcContext.R6 = (UINT64)VmPtr->Gpr[6];
- EbcContext.R7 = (UINT64)VmPtr->Gpr[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->Gpr[0] = EbcContext.R0;
- VmPtr->Gpr[1] = EbcContext.R1;
- VmPtr->Gpr[2] = EbcContext.R2;
- VmPtr->Gpr[3] = EbcContext.R3;
- VmPtr->Gpr[4] = EbcContext.R4;
- VmPtr->Gpr[5] = EbcContext.R5;
- VmPtr->Gpr[6] = EbcContext.R6;
- VmPtr->Gpr[7] = EbcContext.R7;
- VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
- VmPtr->Flags = EbcContext.Flags;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- To install default Callback function for the VM interpreter.
-
- @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
- instance.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval Others Some error occurs when creating periodic event.
-
-**/
-EFI_STATUS
-EFIAPI
-InitializeEbcCallback (
- IN EFI_DEBUG_SUPPORT_PROTOCOL *This
- )
-{
- 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;
-}
-
-/**
- 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.
-
- @param InterruptType Interrupt type.
- @param SystemContext EBC system context.
-
-**/
-VOID
-EFIAPI
-CommonEbcExceptionHandler (
- IN EFI_EXCEPTION_TYPE InterruptType,
- IN EFI_SYSTEM_CONTEXT SystemContext
- )
-{
- //
- // We print debug information to let user know what happen.
- //
- DEBUG ((
- DEBUG_ERROR,
- "EBC Interrupter Version - 0x%016lx\n",
- (UINT64)(((VM_MAJOR_VERSION & 0xFFFF) << 16) | ((VM_MINOR_VERSION & 0xFFFF)))
- ));
- DEBUG ((
- DEBUG_ERROR,
- "Exception Type - 0x%016lx\n",
- (UINT64)(UINTN)InterruptType
- ));
- DEBUG ((
- DEBUG_ERROR,
- " R0 - 0x%016lx, R1 - 0x%016lx\n",
- SystemContext.SystemContextEbc->R0,
- SystemContext.SystemContextEbc->R1
- ));
- DEBUG ((
- DEBUG_ERROR,
- " R2 - 0x%016lx, R3 - 0x%016lx\n",
- SystemContext.SystemContextEbc->R2,
- SystemContext.SystemContextEbc->R3
- ));
- DEBUG ((
- DEBUG_ERROR,
- " R4 - 0x%016lx, R5 - 0x%016lx\n",
- SystemContext.SystemContextEbc->R4,
- SystemContext.SystemContextEbc->R5
- ));
- DEBUG ((
- DEBUG_ERROR,
- " R6 - 0x%016lx, R7 - 0x%016lx\n",
- SystemContext.SystemContextEbc->R6,
- SystemContext.SystemContextEbc->R7
- ));
- DEBUG ((
- DEBUG_ERROR,
- " Flags - 0x%016lx\n",
- SystemContext.SystemContextEbc->Flags
- ));
- DEBUG ((
- DEBUG_ERROR,
- " ControlFlags - 0x%016lx\n",
- SystemContext.SystemContextEbc->ControlFlags
- ));
- DEBUG ((
- DEBUG_ERROR,
- " Ip - 0x%016lx\n\n",
- SystemContext.SystemContextEbc->Ip
- ));
-
- //
- // We deadloop here to make it easy to debug this issue.
- //
- CpuDeadLoop ();
-
- return;
-}
-
-/**
- The periodic callback function for EBC VM interpreter, which is used
- to support the EFI debug support protocol.
-
- @param Event The Periodic Callback Event.
- @param Context It should be the address of VM_CONTEXT pointer.
-
-**/
-VOID
-EFIAPI
-EbcPeriodicNotifyFunction (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- VM_CONTEXT *VmPtr;
-
- VmPtr = *(VM_CONTEXT **)Context;
-
- if (VmPtr != NULL) {
- EbcDebugPeriodic (VmPtr);
- }
-
- return;
-}
-
-/**
- The VM interpreter calls this function on a periodic basis to support
- the EFI debug support protocol.
-
- @param VmPtr Pointer to a VM context for passing info to the
- debugger.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcDebugPeriodic (
- IN VM_CONTEXT *VmPtr
- )
-{
- 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 = (UINT64)VmPtr->Gpr[0];
- EbcContext.R1 = (UINT64)VmPtr->Gpr[1];
- EbcContext.R2 = (UINT64)VmPtr->Gpr[2];
- EbcContext.R3 = (UINT64)VmPtr->Gpr[3];
- EbcContext.R4 = (UINT64)VmPtr->Gpr[4];
- EbcContext.R5 = (UINT64)VmPtr->Gpr[5];
- EbcContext.R6 = (UINT64)VmPtr->Gpr[6];
- EbcContext.R7 = (UINT64)VmPtr->Gpr[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->Gpr[0] = EbcContext.R0;
- VmPtr->Gpr[1] = EbcContext.R1;
- VmPtr->Gpr[2] = EbcContext.R2;
- VmPtr->Gpr[3] = EbcContext.R3;
- VmPtr->Gpr[4] = EbcContext.R4;
- VmPtr->Gpr[5] = EbcContext.R5;
- VmPtr->Gpr[6] = EbcContext.R6;
- VmPtr->Gpr[7] = EbcContext.R7;
- VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
- VmPtr->Flags = EbcContext.Flags;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- 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.
-
- @param This A pointer to the EFI_EBC_PROTOCOL instance.
- @param ImageHandle Handle of image for which the thunk is being
- created.
-
- @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
- internal list of EBC image handles.
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcUnloadImage (
- IN EFI_EBC_PROTOCOL *This,
- IN EFI_HANDLE ImageHandle
- )
-{
- 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);
-
- EbcDebuggerHookEbcUnloadImage (ImageHandle);
-
- return EFI_SUCCESS;
-}
-
-/**
- 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.
-
- @param ImageHandle The image handle to which the thunk is tied.
- @param ThunkBuffer The buffer that has been created/allocated.
- @param ThunkSize The size of the thunk memory allocated.
-
- @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-EbcAddImageThunk (
- IN EFI_HANDLE ImageHandle,
- IN VOID *ThunkBuffer,
- IN UINT32 ThunkSize
- )
-{
- 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;
-}
-
-/**
- Registers a callback function that the EBC interpreter calls to flush the
- processor instruction cache following creation of thunks.
-
- @param This A pointer to the EFI_EBC_PROTOCOL instance.
- @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcRegisterICacheFlush (
- IN EFI_EBC_PROTOCOL *This,
- IN EBC_ICACHE_FLUSH Flush
- )
-{
- mEbcICacheFlush = Flush;
- return EFI_SUCCESS;
-}
-
-/**
- Called to get the version of the interpreter.
-
- @param This A pointer to the EFI_EBC_PROTOCOL instance.
- @param Version Pointer to where to store the returned version
- of the interpreter.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_INVALID_PARAMETER Version pointer is NULL.
-
-**/
-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;
-}
-
-/**
- Returns the stack index and buffer assosicated with the Handle parameter.
-
- @param Handle The EFI handle as the index to the EBC stack.
- @param StackBuffer A pointer to hold the returned stack buffer.
- @param BufferIndex A pointer to hold the returned stack index.
-
- @retval EFI_OUT_OF_RESOURCES The Handle parameter does not correspond to any
- existing EBC stack.
- @retval EFI_SUCCESS The stack index and buffer were found and
- returned to the caller.
-
-**/
-EFI_STATUS
-GetEBCStack (
- IN EFI_HANDLE Handle,
- OUT VOID **StackBuffer,
- OUT 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;
-}
-
-/**
- Returns from the EBC stack by stack Index.
-
- @param Index Specifies which EBC stack to return from.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-ReturnEBCStack (
- IN UINTN Index
- )
-{
- mStackBufferIndex[Index] = NULL;
- return EFI_SUCCESS;
-}
-
-/**
- Returns from the EBC stack associated with the Handle parameter.
-
- @param Handle Specifies the EFI handle to find the EBC stack with.
-
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-ReturnEBCStackByHandle (
- IN 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;
-}
-
-/**
- Allocates memory to hold all the EBC stacks.
-
- @retval EFI_SUCCESS The EBC stacks were allocated successfully.
- @retval EFI_OUT_OF_RESOURCES Not enough memory available for EBC stacks.
-
-**/
-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;
-}
-
-/**
- Free all EBC stacks allocated before.
-
- @retval EFI_SUCCESS All the EBC stacks were freed.
-
-**/
-EFI_STATUS
-FreeEBCStack (
- VOID
- )
-{
- UINTN Index;
-
- for (Index = 0; Index < mStackNum; Index++) {
- FreePool (mStackBuffer[Index]);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Produces an EBC VM test protocol that can be used for regression tests.
-
- @param IHandle Handle on which to install the protocol.
-
- @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
- @retval EFI_SUCCESS The function completed successfully.
-
-**/
-EFI_STATUS
-InitEbcVmTestProtocol (
- IN EFI_HANDLE *IHandle
- )
-{
- 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, &gEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);
- if (EFI_ERROR (Status)) {
- FreePool (EbcVmTestProtocol);
- }
-
- return Status;
-}
-
-/**
- Returns the EFI_UNSUPPORTED Status.
-
- @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
-
-**/
-EFI_STATUS
-EFIAPI
-EbcVmTestUnsupported (
- VOID
- )
-{
- return EFI_UNSUPPORTED;
-}
-
-/**
- Allocates a buffer of type EfiBootServicesCode.
-
- @param AllocationSize The number of bytes to allocate.
-
- @return A pointer to the allocated buffer or NULL if allocation fails.
-
-**/
-VOID *
-EFIAPI
-EbcAllocatePoolForThunk (
- IN UINTN AllocationSize
- )
-{
- VOID *Buffer;
- EFI_STATUS Status;
-
- Status = gBS->AllocatePool (EfiBootServicesCode, AllocationSize, &Buffer);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- return Buffer;
-}
+/** @file + Top level module for the EBC virtual machine implementation. + Provides auxiliary support routines for the VM. That is, routines + that are not particularly related to VM execution of EBC instructions. + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "EbcInt.h" +#include "EbcExecute.h" +#include "EbcDebuggerHook.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 EBC_THUNK_LIST; +struct _EBC_THUNK_LIST { + VOID *ThunkBuffer; + EBC_THUNK_LIST *Next; +}; + +typedef struct _EBC_IMAGE_LIST EBC_IMAGE_LIST; +struct _EBC_IMAGE_LIST { + EBC_IMAGE_LIST *Next; + EFI_HANDLE ImageHandle; + EBC_THUNK_LIST *ThunkList; +}; + +/** + 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. + + @param This A pointer to the EFI_EBC_PROTOCOL instance. + @param ImageHandle Handle of image for which the thunk is being + created. + + @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the + internal list of EBC image handles. + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +EFIAPI +EbcUnloadImage ( + IN EFI_EBC_PROTOCOL *This, + IN EFI_HANDLE ImageHandle + ); + +/** + 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(). + + @param This A pointer to the EFI_EBC_PROTOCOL instance. + @param ImageHandle Handle of image for which the thunk is being + created. The EBC interpreter may use this to + keep track of any resource allocations + performed in loading and executing the image. + @param EbcEntryPoint Address of the actual EBC entry point or + protocol service the thunk should call. + @param Thunk Returned pointer to a thunk created. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned. + @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk. + +**/ +EFI_STATUS +EFIAPI +EbcCreateThunk ( + IN EFI_EBC_PROTOCOL *This, + IN EFI_HANDLE ImageHandle, + IN VOID *EbcEntryPoint, + OUT VOID **Thunk + ); + +/** + Called to get the version of the interpreter. + + @param This A pointer to the EFI_EBC_PROTOCOL instance. + @param Version Pointer to where to store the returned version + of the interpreter. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Version pointer is NULL. + +**/ +EFI_STATUS +EFIAPI +EbcGetVersion ( + IN EFI_EBC_PROTOCOL *This, + IN OUT UINT64 *Version + ); + +/** + To install default Callback function for the VM interpreter. + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL + instance. + + @retval EFI_SUCCESS The function completed successfully. + @retval Others Some error occurs when creating periodic event. + +**/ +EFI_STATUS +EFIAPI +InitializeEbcCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This + ); + +/** + 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. + + @param InterruptType Interrupt type. + @param SystemContext EBC system context. + +**/ +VOID +EFIAPI +CommonEbcExceptionHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ); + +/** + The periodic callback function for EBC VM interpreter, which is used + to support the EFI debug support protocol. + + @param Event The Periodic Callback Event. + @param Context It should be the address of VM_CONTEXT pointer. + +**/ +VOID +EFIAPI +EbcPeriodicNotifyFunction ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + The VM interpreter calls this function on a periodic basis to support + the EFI debug support protocol. + + @param VmPtr Pointer to a VM context for passing info to the + debugger. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +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. +// + +/** + Produces an EBC VM test protocol that can be used for regression tests. + + @param IHandle Handle on which to install the protocol. + + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +InitEbcVmTestProtocol ( + IN EFI_HANDLE *IHandle + ); + +/** + Returns the EFI_UNSUPPORTED Status. + + @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status. + +**/ +EFI_STATUS +EFIAPI +EbcVmTestUnsupported ( + VOID + ); + +/** + Registers a callback function that the EBC interpreter calls to flush the + processor instruction cache following creation of thunks. + + @param This A pointer to the EFI_EBC_PROTOCOL instance. + @param Flush Pointer to a function of type EBC_ICACH_FLUSH. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +EFIAPI +EbcRegisterICacheFlush ( + IN EFI_EBC_PROTOCOL *This, + IN EBC_ICACHE_FLUSH Flush + ); + +/** + This EBC debugger protocol service is called by the debug agent + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL + instance. + @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the + maximum supported processor index is returned. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +EFIAPI +EbcDebugGetMaximumProcessorIndex ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + OUT UINTN *MaxProcessorIndex + ); + +/** + This protocol service is called by the debug agent to register a function + for us to call on a periodic basis. + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL + instance. + @param ProcessorIndex Specifies which processor the callback function + applies to. + @param PeriodicCallback A pointer to a function of type + PERIODIC_CALLBACK that is the main periodic + entry point of the debug agent. It receives as a + parameter a pointer to the full context of the + interrupted execution thread. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a + callback function was previously registered. + @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no + callback function was previously registered. + +**/ +EFI_STATUS +EFIAPI +EbcDebugRegisterPeriodicCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_PERIODIC_CALLBACK PeriodicCallback + ); + +/** + This protocol service is called by the debug agent to register a function + for us to call when we detect an exception. + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL + instance. + @param ProcessorIndex Specifies which processor the callback function + applies to. + @param ExceptionCallback A pointer to a function of type + EXCEPTION_CALLBACK that is called when the + processor exception specified by ExceptionType + occurs. Passing NULL unregisters any previously + registered function associated with + ExceptionType. + @param ExceptionType Specifies which processor exception to hook. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a + callback function was previously registered. + @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds + MAX_EBC_EXCEPTION. + @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no + callback function was previously registered. + +**/ +EFI_STATUS +EFIAPI +EbcDebugRegisterExceptionCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_EXCEPTION_CALLBACK ExceptionCallback, + IN EFI_EXCEPTION_TYPE ExceptionType + ); + +/** + This EBC debugger protocol service is called by the debug agent. Required + for DebugSupport compliance but is only stubbed out for EBC. + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL + instance. + @param ProcessorIndex Specifies which processor the callback function + applies to. + @param Start StartSpecifies the physical base of the memory + range to be invalidated. + @param Length Specifies the minimum number of bytes in the + processor's instruction cache to invalidate. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +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. +// +EBC_IMAGE_LIST *mEbcImageList = NULL; + +// +// Callback function to flush the icache after thunk creation +// +EBC_ICACHE_FLUSH mEbcICacheFlush; + +// +// These get set via calls by the debug agent +// +EFI_PERIODIC_CALLBACK mDebugPeriodicCallback = NULL; +EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = { NULL }; + +VOID *mStackBuffer[MAX_STACK_NUM]; +EFI_HANDLE mStackBufferIndex[MAX_STACK_NUM]; +UINTN mStackNum = 0; + +// +// Event for Periodic callback +// +EFI_EVENT mEbcPeriodicEvent; +VM_CONTEXT *mVmPtr = NULL; + +/** + Check whether the emulator supports executing a certain PE/COFF image + + @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL + structure + @param[in] ImageType Whether the image is an application, a boot time + driver or a runtime driver. + @param[in] DevicePath Path to device where the image originated + (e.g., a PCI option ROM) + + @retval TRUE The image is supported by the emulator + @retval FALSE The image is not supported by the emulator. +**/ +BOOLEAN +EFIAPI +EbcIsImageSupported ( + IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This, + IN UINT16 ImageType, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL + ) +{ + if ((ImageType != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) && + (ImageType != EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)) + { + return FALSE; + } + + return TRUE; +} + +/** + Register a supported PE/COFF image with the emulator. After this call + completes successfully, the PE/COFF image may be started as usual, and + it is the responsibility of the emulator implementation that any branch + into the code section of the image (including returns from functions called + from the foreign code) is executed as if it were running on the machine + type it was built for. + + @param[in] This This pointer for + EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL structure + @param[in] ImageBase The base address in memory of the PE/COFF image + @param[in] ImageSize The size in memory of the PE/COFF image + @param[in,out] EntryPoint The entry point of the PE/COFF image. Passed by + reference so that the emulator may modify it. + + @retval EFI_SUCCESS The image was registered with the emulator and + can be started as usual. + @retval other The image could not be registered. + + If the PE/COFF machine type or image type are not supported by the emulator, + then ASSERT(). +**/ +EFI_STATUS +EFIAPI +EbcRegisterImage ( + IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS ImageBase, + IN UINT64 ImageSize, + IN OUT EFI_IMAGE_ENTRY_POINT *EntryPoint + ) +{ + DEBUG_CODE_BEGIN (); + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + EFI_STATUS Status; + + ZeroMem (&ImageContext, sizeof (ImageContext)); + + ImageContext.Handle = (VOID *)(UINTN)ImageBase; + ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; + + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (ImageContext.Machine == EFI_IMAGE_MACHINE_EBC); + ASSERT ( + ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION || + ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER + ); + DEBUG_CODE_END (); + + EbcRegisterICacheFlush ( + NULL, + (EBC_ICACHE_FLUSH)InvalidateInstructionCacheRange + ); + + return EbcCreateThunk ( + NULL, + (VOID *)(UINTN)ImageBase, + (VOID *)(UINTN)*EntryPoint, + (VOID **)EntryPoint + ); +} + +/** + Unregister a PE/COFF image that has been registered with the emulator. + This should be done before the image is unloaded from memory. + + @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL + structure + @param[in] ImageBase The base address in memory of the PE/COFF image + + @retval EFI_SUCCESS The image was unregistered with the emulator. + @retval other Image could not be unloaded. +**/ +EFI_STATUS +EFIAPI +EbcUnregisterImage ( + IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS ImageBase + ) +{ + return EbcUnloadImage (NULL, (VOID *)(UINTN)ImageBase); +} + +STATIC EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL mPeCoffEmuProtocol = { + EbcIsImageSupported, + EbcRegisterImage, + EbcUnregisterImage, + EDKII_PECOFF_IMAGE_EMULATOR_VERSION, + EFI_IMAGE_MACHINE_EBC +}; + +/** + Initializes the VM EFI interface. Allocates memory for the VM interface + and registers the VM protocol. + + @param ImageHandle EFI image handle. + @param SystemTable Pointer to the EFI system table. + + @return Standard EFI status code. + +**/ +EFI_STATUS +EFIAPI +InitializeEbcDriver ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + 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->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiEbcProtocolGuid, + EbcProtocol, + &gEdkiiPeCoffImageEmulatorProtocolGuid, + &mPeCoffEmuProtocol, + NULL + ); + 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 (); + + EbcDebuggerHookInit (ImageHandle, EbcDebugProtocol); + + 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; +} + +/** + 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(). + + @param This A pointer to the EFI_EBC_PROTOCOL instance. + @param ImageHandle Handle of image for which the thunk is being + created. The EBC interpreter may use this to + keep track of any resource allocations + performed in loading and executing the image. + @param EbcEntryPoint Address of the actual EBC entry point or + protocol service the thunk should call. + @param Thunk Returned pointer to a thunk created. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned. + @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk. + +**/ +EFI_STATUS +EFIAPI +EbcCreateThunk ( + IN EFI_EBC_PROTOCOL *This, + IN EFI_HANDLE ImageHandle, + IN VOID *EbcEntryPoint, + OUT VOID **Thunk + ) +{ + EFI_STATUS Status; + + Status = EbcCreateThunks ( + ImageHandle, + EbcEntryPoint, + Thunk, + FLAG_THUNK_ENTRY_POINT + ); + return Status; +} + +/** + This EBC debugger protocol service is called by the debug agent + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL + instance. + @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the + maximum supported processor index is returned. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +EFIAPI +EbcDebugGetMaximumProcessorIndex ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + OUT UINTN *MaxProcessorIndex + ) +{ + *MaxProcessorIndex = 0; + return EFI_SUCCESS; +} + +/** + This protocol service is called by the debug agent to register a function + for us to call on a periodic basis. + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL + instance. + @param ProcessorIndex Specifies which processor the callback function + applies to. + @param PeriodicCallback A pointer to a function of type + PERIODIC_CALLBACK that is the main periodic + entry point of the debug agent. It receives as a + parameter a pointer to the full context of the + interrupted execution thread. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a + callback function was previously registered. + @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no + callback function was previously registered. + +**/ +EFI_STATUS +EFIAPI +EbcDebugRegisterPeriodicCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_PERIODIC_CALLBACK PeriodicCallback + ) +{ + if ((mDebugPeriodicCallback == NULL) && (PeriodicCallback == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((mDebugPeriodicCallback != NULL) && (PeriodicCallback != NULL)) { + return EFI_ALREADY_STARTED; + } + + mDebugPeriodicCallback = PeriodicCallback; + return EFI_SUCCESS; +} + +/** + This protocol service is called by the debug agent to register a function + for us to call when we detect an exception. + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL + instance. + @param ProcessorIndex Specifies which processor the callback function + applies to. + @param ExceptionCallback A pointer to a function of type + EXCEPTION_CALLBACK that is called when the + processor exception specified by ExceptionType + occurs. Passing NULL unregisters any previously + registered function associated with + ExceptionType. + @param ExceptionType Specifies which processor exception to hook. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a + callback function was previously registered. + @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds + MAX_EBC_EXCEPTION. + @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no + callback function was previously registered. + +**/ +EFI_STATUS +EFIAPI +EbcDebugRegisterExceptionCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_EXCEPTION_CALLBACK ExceptionCallback, + IN EFI_EXCEPTION_TYPE ExceptionType + ) +{ + 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; +} + +/** + This EBC debugger protocol service is called by the debug agent. Required + for DebugSupport compliance but is only stubbed out for EBC. + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL + instance. + @param ProcessorIndex Specifies which processor the callback function + applies to. + @param Start StartSpecifies the physical base of the memory + range to be invalidated. + @param Length Specifies the minimum number of bytes in the + processor's instruction cache to invalidate. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +EFIAPI +EbcDebugInvalidateInstructionCache ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN VOID *Start, + IN UINT64 Length + ) +{ + return EFI_SUCCESS; +} + +/** + The VM interpreter calls this function when an exception is detected. + + @param ExceptionType Specifies the processor exception detected. + @param ExceptionFlags Specifies the exception context. + @param VmPtr Pointer to a VM context for passing info to the + EFI debugger. + + @retval EFI_SUCCESS This function completed successfully. + +**/ +EFI_STATUS +EbcDebugSignalException ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EXCEPTION_FLAGS ExceptionFlags, + IN VM_CONTEXT *VmPtr + ) +{ + 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 = (UINTN)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) != 0) { + 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 = (UINT64)VmPtr->Gpr[0]; + EbcContext.R1 = (UINT64)VmPtr->Gpr[1]; + EbcContext.R2 = (UINT64)VmPtr->Gpr[2]; + EbcContext.R3 = (UINT64)VmPtr->Gpr[3]; + EbcContext.R4 = (UINT64)VmPtr->Gpr[4]; + EbcContext.R5 = (UINT64)VmPtr->Gpr[5]; + EbcContext.R6 = (UINT64)VmPtr->Gpr[6]; + EbcContext.R7 = (UINT64)VmPtr->Gpr[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->Gpr[0] = EbcContext.R0; + VmPtr->Gpr[1] = EbcContext.R1; + VmPtr->Gpr[2] = EbcContext.R2; + VmPtr->Gpr[3] = EbcContext.R3; + VmPtr->Gpr[4] = EbcContext.R4; + VmPtr->Gpr[5] = EbcContext.R5; + VmPtr->Gpr[6] = EbcContext.R6; + VmPtr->Gpr[7] = EbcContext.R7; + VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip; + VmPtr->Flags = EbcContext.Flags; + } + + return EFI_SUCCESS; +} + +/** + To install default Callback function for the VM interpreter. + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL + instance. + + @retval EFI_SUCCESS The function completed successfully. + @retval Others Some error occurs when creating periodic event. + +**/ +EFI_STATUS +EFIAPI +InitializeEbcCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This + ) +{ + 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; +} + +/** + 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. + + @param InterruptType Interrupt type. + @param SystemContext EBC system context. + +**/ +VOID +EFIAPI +CommonEbcExceptionHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + // + // We print debug information to let user know what happen. + // + DEBUG (( + DEBUG_ERROR, + "EBC Interrupter Version - 0x%016lx\n", + (UINT64)(((VM_MAJOR_VERSION & 0xFFFF) << 16) | ((VM_MINOR_VERSION & 0xFFFF))) + )); + DEBUG (( + DEBUG_ERROR, + "Exception Type - 0x%016lx\n", + (UINT64)(UINTN)InterruptType + )); + DEBUG (( + DEBUG_ERROR, + " R0 - 0x%016lx, R1 - 0x%016lx\n", + SystemContext.SystemContextEbc->R0, + SystemContext.SystemContextEbc->R1 + )); + DEBUG (( + DEBUG_ERROR, + " R2 - 0x%016lx, R3 - 0x%016lx\n", + SystemContext.SystemContextEbc->R2, + SystemContext.SystemContextEbc->R3 + )); + DEBUG (( + DEBUG_ERROR, + " R4 - 0x%016lx, R5 - 0x%016lx\n", + SystemContext.SystemContextEbc->R4, + SystemContext.SystemContextEbc->R5 + )); + DEBUG (( + DEBUG_ERROR, + " R6 - 0x%016lx, R7 - 0x%016lx\n", + SystemContext.SystemContextEbc->R6, + SystemContext.SystemContextEbc->R7 + )); + DEBUG (( + DEBUG_ERROR, + " Flags - 0x%016lx\n", + SystemContext.SystemContextEbc->Flags + )); + DEBUG (( + DEBUG_ERROR, + " ControlFlags - 0x%016lx\n", + SystemContext.SystemContextEbc->ControlFlags + )); + DEBUG (( + DEBUG_ERROR, + " Ip - 0x%016lx\n\n", + SystemContext.SystemContextEbc->Ip + )); + + // + // We deadloop here to make it easy to debug this issue. + // + CpuDeadLoop (); + + return; +} + +/** + The periodic callback function for EBC VM interpreter, which is used + to support the EFI debug support protocol. + + @param Event The Periodic Callback Event. + @param Context It should be the address of VM_CONTEXT pointer. + +**/ +VOID +EFIAPI +EbcPeriodicNotifyFunction ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + VM_CONTEXT *VmPtr; + + VmPtr = *(VM_CONTEXT **)Context; + + if (VmPtr != NULL) { + EbcDebugPeriodic (VmPtr); + } + + return; +} + +/** + The VM interpreter calls this function on a periodic basis to support + the EFI debug support protocol. + + @param VmPtr Pointer to a VM context for passing info to the + debugger. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +EFIAPI +EbcDebugPeriodic ( + IN VM_CONTEXT *VmPtr + ) +{ + 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 = (UINT64)VmPtr->Gpr[0]; + EbcContext.R1 = (UINT64)VmPtr->Gpr[1]; + EbcContext.R2 = (UINT64)VmPtr->Gpr[2]; + EbcContext.R3 = (UINT64)VmPtr->Gpr[3]; + EbcContext.R4 = (UINT64)VmPtr->Gpr[4]; + EbcContext.R5 = (UINT64)VmPtr->Gpr[5]; + EbcContext.R6 = (UINT64)VmPtr->Gpr[6]; + EbcContext.R7 = (UINT64)VmPtr->Gpr[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->Gpr[0] = EbcContext.R0; + VmPtr->Gpr[1] = EbcContext.R1; + VmPtr->Gpr[2] = EbcContext.R2; + VmPtr->Gpr[3] = EbcContext.R3; + VmPtr->Gpr[4] = EbcContext.R4; + VmPtr->Gpr[5] = EbcContext.R5; + VmPtr->Gpr[6] = EbcContext.R6; + VmPtr->Gpr[7] = EbcContext.R7; + VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip; + VmPtr->Flags = EbcContext.Flags; + } + + return EFI_SUCCESS; +} + +/** + 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. + + @param This A pointer to the EFI_EBC_PROTOCOL instance. + @param ImageHandle Handle of image for which the thunk is being + created. + + @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the + internal list of EBC image handles. + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +EFIAPI +EbcUnloadImage ( + IN EFI_EBC_PROTOCOL *This, + IN EFI_HANDLE ImageHandle + ) +{ + 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); + + EbcDebuggerHookEbcUnloadImage (ImageHandle); + + return EFI_SUCCESS; +} + +/** + 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. + + @param ImageHandle The image handle to which the thunk is tied. + @param ThunkBuffer The buffer that has been created/allocated. + @param ThunkSize The size of the thunk memory allocated. + + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +EbcAddImageThunk ( + IN EFI_HANDLE ImageHandle, + IN VOID *ThunkBuffer, + IN UINT32 ThunkSize + ) +{ + 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; +} + +/** + Registers a callback function that the EBC interpreter calls to flush the + processor instruction cache following creation of thunks. + + @param This A pointer to the EFI_EBC_PROTOCOL instance. + @param Flush Pointer to a function of type EBC_ICACH_FLUSH. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +EFIAPI +EbcRegisterICacheFlush ( + IN EFI_EBC_PROTOCOL *This, + IN EBC_ICACHE_FLUSH Flush + ) +{ + mEbcICacheFlush = Flush; + return EFI_SUCCESS; +} + +/** + Called to get the version of the interpreter. + + @param This A pointer to the EFI_EBC_PROTOCOL instance. + @param Version Pointer to where to store the returned version + of the interpreter. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Version pointer is NULL. + +**/ +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; +} + +/** + Returns the stack index and buffer assosicated with the Handle parameter. + + @param Handle The EFI handle as the index to the EBC stack. + @param StackBuffer A pointer to hold the returned stack buffer. + @param BufferIndex A pointer to hold the returned stack index. + + @retval EFI_OUT_OF_RESOURCES The Handle parameter does not correspond to any + existing EBC stack. + @retval EFI_SUCCESS The stack index and buffer were found and + returned to the caller. + +**/ +EFI_STATUS +GetEBCStack ( + IN EFI_HANDLE Handle, + OUT VOID **StackBuffer, + OUT 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; +} + +/** + Returns from the EBC stack by stack Index. + + @param Index Specifies which EBC stack to return from. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +ReturnEBCStack ( + IN UINTN Index + ) +{ + mStackBufferIndex[Index] = NULL; + return EFI_SUCCESS; +} + +/** + Returns from the EBC stack associated with the Handle parameter. + + @param Handle Specifies the EFI handle to find the EBC stack with. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +ReturnEBCStackByHandle ( + IN 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; +} + +/** + Allocates memory to hold all the EBC stacks. + + @retval EFI_SUCCESS The EBC stacks were allocated successfully. + @retval EFI_OUT_OF_RESOURCES Not enough memory available for EBC stacks. + +**/ +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; +} + +/** + Free all EBC stacks allocated before. + + @retval EFI_SUCCESS All the EBC stacks were freed. + +**/ +EFI_STATUS +FreeEBCStack ( + VOID + ) +{ + UINTN Index; + + for (Index = 0; Index < mStackNum; Index++) { + FreePool (mStackBuffer[Index]); + } + + return EFI_SUCCESS; +} + +/** + Produces an EBC VM test protocol that can be used for regression tests. + + @param IHandle Handle on which to install the protocol. + + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +InitEbcVmTestProtocol ( + IN EFI_HANDLE *IHandle + ) +{ + 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, &gEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol); + if (EFI_ERROR (Status)) { + FreePool (EbcVmTestProtocol); + } + + return Status; +} + +/** + Returns the EFI_UNSUPPORTED Status. + + @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status. + +**/ +EFI_STATUS +EFIAPI +EbcVmTestUnsupported ( + VOID + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Allocates a buffer of type EfiBootServicesCode. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +EbcAllocatePoolForThunk ( + IN UINTN AllocationSize + ) +{ + VOID *Buffer; + EFI_STATUS Status; + + Status = gBS->AllocatePool (EfiBootServicesCode, AllocationSize, &Buffer); + if (EFI_ERROR (Status)) { + return NULL; + } + + return Buffer; +} |
