Home | History | Annotate | Download | only in EbcDxe
      1 /** @file
      2   Top level module for the EBC virtual machine implementation.
      3   Provides auxiliary support routines for the VM. That is, routines
      4   that are not particularly related to VM execution of EBC instructions.
      5 
      6 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions of the BSD License
      9 which accompanies this distribution.  The full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "EbcInt.h"
     18 #include "EbcExecute.h"
     19 #include "EbcDebuggerHook.h"
     20 
     21 //
     22 // We'll keep track of all thunks we create in a linked list. Each
     23 // thunk is tied to an image handle, so we have a linked list of
     24 // image handles, with each having a linked list of thunks allocated
     25 // to that image handle.
     26 //
     27 typedef struct _EBC_THUNK_LIST EBC_THUNK_LIST;
     28 struct _EBC_THUNK_LIST {
     29   VOID            *ThunkBuffer;
     30   EBC_THUNK_LIST  *Next;
     31 };
     32 
     33 typedef struct _EBC_IMAGE_LIST EBC_IMAGE_LIST;
     34 struct _EBC_IMAGE_LIST {
     35   EBC_IMAGE_LIST  *Next;
     36   EFI_HANDLE      ImageHandle;
     37   EBC_THUNK_LIST  *ThunkList;
     38 };
     39 
     40 /**
     41   This routine is called by the core when an image is being unloaded from
     42   memory. Basically we now have the opportunity to do any necessary cleanup.
     43   Typically this will include freeing any memory allocated for thunk-creation.
     44 
     45   @param  This                  A pointer to the EFI_EBC_PROTOCOL instance.
     46   @param  ImageHandle           Handle of image for which the thunk is being
     47                                 created.
     48 
     49   @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
     50                                 internal list of EBC image handles.
     51   @retval EFI_SUCCESS           The function completed successfully.
     52 
     53 **/
     54 EFI_STATUS
     55 EFIAPI
     56 EbcUnloadImage (
     57   IN EFI_EBC_PROTOCOL   *This,
     58   IN EFI_HANDLE         ImageHandle
     59   );
     60 
     61 /**
     62   This is the top-level routine plugged into the EBC protocol. Since thunks
     63   are very processor-specific, from here we dispatch directly to the very
     64   processor-specific routine EbcCreateThunks().
     65 
     66   @param  This                  A pointer to the EFI_EBC_PROTOCOL instance.
     67   @param  ImageHandle           Handle of image for which the thunk is being
     68                                 created. The EBC interpreter may use this to
     69                                 keep track of any resource allocations
     70                                 performed in loading and executing the image.
     71   @param  EbcEntryPoint         Address of the actual EBC entry point or
     72                                 protocol service the thunk should call.
     73   @param  Thunk                 Returned pointer to a thunk created.
     74 
     75   @retval EFI_SUCCESS           The function completed successfully.
     76   @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
     77   @retval EFI_OUT_OF_RESOURCES  Memory could not be allocated for the thunk.
     78 
     79 **/
     80 EFI_STATUS
     81 EFIAPI
     82 EbcCreateThunk (
     83   IN EFI_EBC_PROTOCOL   *This,
     84   IN EFI_HANDLE         ImageHandle,
     85   IN VOID               *EbcEntryPoint,
     86   OUT VOID              **Thunk
     87   );
     88 
     89 /**
     90   Called to get the version of the interpreter.
     91 
     92   @param  This                  A pointer to the EFI_EBC_PROTOCOL instance.
     93   @param  Version               Pointer to where to store the returned version
     94                                 of the interpreter.
     95 
     96   @retval EFI_SUCCESS           The function completed successfully.
     97   @retval EFI_INVALID_PARAMETER Version pointer is NULL.
     98 
     99 **/
    100 EFI_STATUS
    101 EFIAPI
    102 EbcGetVersion (
    103   IN EFI_EBC_PROTOCOL   *This,
    104   IN OUT UINT64         *Version
    105   );
    106 
    107 /**
    108   To install default Callback function for the VM interpreter.
    109 
    110   @param  This                  A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
    111                                 instance.
    112 
    113   @retval EFI_SUCCESS           The function completed successfully.
    114   @retval Others                Some error occurs when creating periodic event.
    115 
    116 **/
    117 EFI_STATUS
    118 EFIAPI
    119 InitializeEbcCallback (
    120   IN EFI_DEBUG_SUPPORT_PROTOCOL  *This
    121   );
    122 
    123 /**
    124   The default Exception Callback for the VM interpreter.
    125   In this function, we report status code, and print debug information
    126   about EBC_CONTEXT, then dead loop.
    127 
    128   @param  InterruptType          Interrupt type.
    129   @param  SystemContext          EBC system context.
    130 
    131 **/
    132 VOID
    133 EFIAPI
    134 CommonEbcExceptionHandler (
    135   IN EFI_EXCEPTION_TYPE   InterruptType,
    136   IN EFI_SYSTEM_CONTEXT   SystemContext
    137   );
    138 
    139 /**
    140   The periodic callback function for EBC VM interpreter, which is used
    141   to support the EFI debug support protocol.
    142 
    143   @param  Event                  The Periodic Callback Event.
    144   @param  Context                It should be the address of VM_CONTEXT pointer.
    145 
    146 **/
    147 VOID
    148 EFIAPI
    149 EbcPeriodicNotifyFunction (
    150   IN EFI_EVENT     Event,
    151   IN VOID          *Context
    152   );
    153 
    154 /**
    155   The VM interpreter calls this function on a periodic basis to support
    156   the EFI debug support protocol.
    157 
    158   @param  VmPtr                  Pointer to a VM context for passing info to the
    159                                  debugger.
    160 
    161   @retval EFI_SUCCESS            The function completed successfully.
    162 
    163 **/
    164 EFI_STATUS
    165 EFIAPI
    166 EbcDebugPeriodic (
    167   IN VM_CONTEXT *VmPtr
    168   );
    169 
    170 //
    171 // These two functions and the  GUID are used to produce an EBC test protocol.
    172 // This functionality is definitely not required for execution.
    173 //
    174 /**
    175   Produces an EBC VM test protocol that can be used for regression tests.
    176 
    177   @param  IHandle                Handle on which to install the protocol.
    178 
    179   @retval EFI_OUT_OF_RESOURCES   Memory allocation failed.
    180   @retval EFI_SUCCESS            The function completed successfully.
    181 
    182 **/
    183 EFI_STATUS
    184 InitEbcVmTestProtocol (
    185   IN EFI_HANDLE     *IHandle
    186   );
    187 
    188 /**
    189   Returns the EFI_UNSUPPORTED Status.
    190 
    191   @return EFI_UNSUPPORTED  This function always return EFI_UNSUPPORTED status.
    192 
    193 **/
    194 EFI_STATUS
    195 EFIAPI
    196 EbcVmTestUnsupported (
    197   VOID
    198   );
    199 
    200 /**
    201   Registers a callback function that the EBC interpreter calls to flush the
    202   processor instruction cache following creation of thunks.
    203 
    204   @param  This        A pointer to the EFI_EBC_PROTOCOL instance.
    205   @param  Flush       Pointer to a function of type EBC_ICACH_FLUSH.
    206 
    207   @retval EFI_SUCCESS The function completed successfully.
    208 
    209 **/
    210 EFI_STATUS
    211 EFIAPI
    212 EbcRegisterICacheFlush (
    213   IN EFI_EBC_PROTOCOL   *This,
    214   IN EBC_ICACHE_FLUSH   Flush
    215   );
    216 
    217 /**
    218   This EBC debugger protocol service is called by the debug agent
    219 
    220   @param  This                  A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
    221                                 instance.
    222   @param  MaxProcessorIndex     Pointer to a caller-allocated UINTN in which the
    223                                 maximum supported processor index is returned.
    224 
    225   @retval EFI_SUCCESS           The function completed successfully.
    226 
    227 **/
    228 EFI_STATUS
    229 EFIAPI
    230 EbcDebugGetMaximumProcessorIndex (
    231   IN EFI_DEBUG_SUPPORT_PROTOCOL          *This,
    232   OUT UINTN                              *MaxProcessorIndex
    233   );
    234 
    235 /**
    236   This protocol service is called by the debug agent to register a function
    237   for us to call on a periodic basis.
    238 
    239   @param  This                  A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
    240                                 instance.
    241   @param  ProcessorIndex        Specifies which processor the callback function
    242                                 applies to.
    243   @param  PeriodicCallback      A pointer to a function of type
    244                                 PERIODIC_CALLBACK that is the main periodic
    245                                 entry point of the debug agent. It receives as a
    246                                 parameter a pointer to the full context of the
    247                                 interrupted execution thread.
    248 
    249   @retval EFI_SUCCESS           The function completed successfully.
    250   @retval EFI_ALREADY_STARTED   Non-NULL PeriodicCallback parameter when a
    251                                 callback function was previously registered.
    252   @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
    253                                 callback function was previously registered.
    254 
    255 **/
    256 EFI_STATUS
    257 EFIAPI
    258 EbcDebugRegisterPeriodicCallback (
    259   IN EFI_DEBUG_SUPPORT_PROTOCOL  *This,
    260   IN UINTN                       ProcessorIndex,
    261   IN EFI_PERIODIC_CALLBACK       PeriodicCallback
    262   );
    263 
    264 /**
    265   This protocol service is called by the debug agent to register a function
    266   for us to call when we detect an exception.
    267 
    268   @param  This                  A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
    269                                 instance.
    270   @param  ProcessorIndex        Specifies which processor the callback function
    271                                 applies to.
    272   @param  ExceptionCallback     A pointer to a function of type
    273                                 EXCEPTION_CALLBACK that is called when the
    274                                 processor exception specified by ExceptionType
    275                                 occurs. Passing NULL unregisters any previously
    276                                 registered function associated with
    277                                 ExceptionType.
    278   @param  ExceptionType         Specifies which processor exception to hook.
    279 
    280   @retval EFI_SUCCESS           The function completed successfully.
    281   @retval EFI_ALREADY_STARTED   Non-NULL ExceptionCallback parameter when a
    282                                 callback function was previously registered.
    283   @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
    284                                 MAX_EBC_EXCEPTION.
    285   @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
    286                                 callback function was previously registered.
    287 
    288 **/
    289 EFI_STATUS
    290 EFIAPI
    291 EbcDebugRegisterExceptionCallback (
    292   IN EFI_DEBUG_SUPPORT_PROTOCOL  *This,
    293   IN UINTN                       ProcessorIndex,
    294   IN EFI_EXCEPTION_CALLBACK      ExceptionCallback,
    295   IN EFI_EXCEPTION_TYPE          ExceptionType
    296   );
    297 
    298 /**
    299   This EBC debugger protocol service is called by the debug agent.  Required
    300   for DebugSupport compliance but is only stubbed out for EBC.
    301 
    302   @param  This                  A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
    303                                 instance.
    304   @param  ProcessorIndex        Specifies which processor the callback function
    305                                 applies to.
    306   @param  Start                 StartSpecifies the physical base of the memory
    307                                 range to be invalidated.
    308   @param  Length                Specifies the minimum number of bytes in the
    309                                 processor's instruction cache to invalidate.
    310 
    311   @retval EFI_SUCCESS           The function completed successfully.
    312 
    313 **/
    314 EFI_STATUS
    315 EFIAPI
    316 EbcDebugInvalidateInstructionCache (
    317   IN EFI_DEBUG_SUPPORT_PROTOCOL          *This,
    318   IN UINTN                               ProcessorIndex,
    319   IN VOID                                *Start,
    320   IN UINT64                              Length
    321   );
    322 
    323 //
    324 // We have one linked list of image handles for the whole world. Since
    325 // there should only be one interpreter, make them global. They must
    326 // also be global since the execution of an EBC image does not provide
    327 // a This pointer.
    328 //
    329 EBC_IMAGE_LIST         *mEbcImageList = NULL;
    330 
    331 //
    332 // Callback function to flush the icache after thunk creation
    333 //
    334 EBC_ICACHE_FLUSH       mEbcICacheFlush;
    335 
    336 //
    337 // These get set via calls by the debug agent
    338 //
    339 EFI_PERIODIC_CALLBACK  mDebugPeriodicCallback = NULL;
    340 EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = {NULL};
    341 
    342 VOID                   *mStackBuffer[MAX_STACK_NUM];
    343 EFI_HANDLE             mStackBufferIndex[MAX_STACK_NUM];
    344 UINTN                  mStackNum = 0;
    345 
    346 //
    347 // Event for Periodic callback
    348 //
    349 EFI_EVENT              mEbcPeriodicEvent;
    350 VM_CONTEXT             *mVmPtr = NULL;
    351 
    352 
    353 /**
    354   Initializes the VM EFI interface.  Allocates memory for the VM interface
    355   and registers the VM protocol.
    356 
    357   @param  ImageHandle            EFI image handle.
    358   @param  SystemTable            Pointer to the EFI system table.
    359 
    360   @return Standard EFI status code.
    361 
    362 **/
    363 EFI_STATUS
    364 EFIAPI
    365 InitializeEbcDriver (
    366   IN EFI_HANDLE           ImageHandle,
    367   IN EFI_SYSTEM_TABLE     *SystemTable
    368   )
    369 {
    370   EFI_EBC_PROTOCOL            *EbcProtocol;
    371   EFI_EBC_PROTOCOL            *OldEbcProtocol;
    372   EFI_STATUS                  Status;
    373   EFI_DEBUG_SUPPORT_PROTOCOL  *EbcDebugProtocol;
    374   EFI_HANDLE                  *HandleBuffer;
    375   UINTN                       NumHandles;
    376   UINTN                       Index;
    377   BOOLEAN                     Installed;
    378 
    379   EbcProtocol      = NULL;
    380   EbcDebugProtocol = NULL;
    381 
    382   //
    383   // Allocate memory for our protocol. Then fill in the blanks.
    384   //
    385   EbcProtocol = AllocatePool (sizeof (EFI_EBC_PROTOCOL));
    386 
    387   if (EbcProtocol == NULL) {
    388     return EFI_OUT_OF_RESOURCES;
    389   }
    390 
    391   EbcProtocol->CreateThunk          = EbcCreateThunk;
    392   EbcProtocol->UnloadImage          = EbcUnloadImage;
    393   EbcProtocol->RegisterICacheFlush  = EbcRegisterICacheFlush;
    394   EbcProtocol->GetVersion           = EbcGetVersion;
    395   mEbcICacheFlush                   = NULL;
    396 
    397   //
    398   // Find any already-installed EBC protocols and uninstall them
    399   //
    400   Installed     = FALSE;
    401   HandleBuffer  = NULL;
    402   Status = gBS->LocateHandleBuffer (
    403                   ByProtocol,
    404                   &gEfiEbcProtocolGuid,
    405                   NULL,
    406                   &NumHandles,
    407                   &HandleBuffer
    408                   );
    409   if (Status == EFI_SUCCESS) {
    410     //
    411     // Loop through the handles
    412     //
    413     for (Index = 0; Index < NumHandles; Index++) {
    414       Status = gBS->HandleProtocol (
    415                       HandleBuffer[Index],
    416                       &gEfiEbcProtocolGuid,
    417                       (VOID **) &OldEbcProtocol
    418                       );
    419       if (Status == EFI_SUCCESS) {
    420         if (gBS->ReinstallProtocolInterface (
    421                   HandleBuffer[Index],
    422                   &gEfiEbcProtocolGuid,
    423                   OldEbcProtocol,
    424                   EbcProtocol
    425                   ) == EFI_SUCCESS) {
    426           Installed = TRUE;
    427         }
    428       }
    429     }
    430   }
    431 
    432   if (HandleBuffer != NULL) {
    433     FreePool (HandleBuffer);
    434     HandleBuffer = NULL;
    435   }
    436   //
    437   // Add the protocol so someone can locate us if we haven't already.
    438   //
    439   if (!Installed) {
    440     Status = gBS->InstallProtocolInterface (
    441                     &ImageHandle,
    442                     &gEfiEbcProtocolGuid,
    443                     EFI_NATIVE_INTERFACE,
    444                     EbcProtocol
    445                     );
    446     if (EFI_ERROR (Status)) {
    447       FreePool (EbcProtocol);
    448       return Status;
    449     }
    450   }
    451 
    452   Status = InitEBCStack();
    453   if (EFI_ERROR(Status)) {
    454     goto ErrorExit;
    455   }
    456 
    457   //
    458   // Allocate memory for our debug protocol. Then fill in the blanks.
    459   //
    460   EbcDebugProtocol = AllocatePool (sizeof (EFI_DEBUG_SUPPORT_PROTOCOL));
    461 
    462   if (EbcDebugProtocol == NULL) {
    463     goto ErrorExit;
    464   }
    465 
    466   EbcDebugProtocol->Isa                         = IsaEbc;
    467   EbcDebugProtocol->GetMaximumProcessorIndex    = EbcDebugGetMaximumProcessorIndex;
    468   EbcDebugProtocol->RegisterPeriodicCallback    = EbcDebugRegisterPeriodicCallback;
    469   EbcDebugProtocol->RegisterExceptionCallback   = EbcDebugRegisterExceptionCallback;
    470   EbcDebugProtocol->InvalidateInstructionCache  = EbcDebugInvalidateInstructionCache;
    471 
    472   //
    473   // Add the protocol so the debug agent can find us
    474   //
    475   Status = gBS->InstallProtocolInterface (
    476                   &ImageHandle,
    477                   &gEfiDebugSupportProtocolGuid,
    478                   EFI_NATIVE_INTERFACE,
    479                   EbcDebugProtocol
    480                   );
    481   //
    482   // This is recoverable, so free the memory and continue.
    483   //
    484   if (EFI_ERROR (Status)) {
    485     FreePool (EbcDebugProtocol);
    486     goto ErrorExit;
    487   }
    488   //
    489   // Install EbcDebugSupport Protocol Successfully
    490   // Now we need to initialize the Ebc default Callback
    491   //
    492   Status = InitializeEbcCallback (EbcDebugProtocol);
    493 
    494   //
    495   // Produce a VM test interface protocol. Not required for execution.
    496   //
    497   DEBUG_CODE_BEGIN ();
    498     InitEbcVmTestProtocol (&ImageHandle);
    499   DEBUG_CODE_END ();
    500 
    501   EbcDebuggerHookInit (ImageHandle, EbcDebugProtocol);
    502 
    503   return EFI_SUCCESS;
    504 
    505 ErrorExit:
    506   FreeEBCStack();
    507   HandleBuffer  = NULL;
    508   Status = gBS->LocateHandleBuffer (
    509                   ByProtocol,
    510                   &gEfiEbcProtocolGuid,
    511                   NULL,
    512                   &NumHandles,
    513                   &HandleBuffer
    514                   );
    515   if (Status == EFI_SUCCESS) {
    516     //
    517     // Loop through the handles
    518     //
    519     for (Index = 0; Index < NumHandles; Index++) {
    520       Status = gBS->HandleProtocol (
    521                       HandleBuffer[Index],
    522                       &gEfiEbcProtocolGuid,
    523                       (VOID **) &OldEbcProtocol
    524                       );
    525       if (Status == EFI_SUCCESS) {
    526         gBS->UninstallProtocolInterface (
    527                HandleBuffer[Index],
    528                &gEfiEbcProtocolGuid,
    529                OldEbcProtocol
    530                );
    531       }
    532     }
    533   }
    534 
    535   if (HandleBuffer != NULL) {
    536     FreePool (HandleBuffer);
    537     HandleBuffer = NULL;
    538   }
    539 
    540   FreePool (EbcProtocol);
    541 
    542   return Status;
    543 }
    544 
    545 
    546 /**
    547   This is the top-level routine plugged into the EBC protocol. Since thunks
    548   are very processor-specific, from here we dispatch directly to the very
    549   processor-specific routine EbcCreateThunks().
    550 
    551   @param  This                  A pointer to the EFI_EBC_PROTOCOL instance.
    552   @param  ImageHandle           Handle of image for which the thunk is being
    553                                 created. The EBC interpreter may use this to
    554                                 keep track of any resource allocations
    555                                 performed in loading and executing the image.
    556   @param  EbcEntryPoint         Address of the actual EBC entry point or
    557                                 protocol service the thunk should call.
    558   @param  Thunk                 Returned pointer to a thunk created.
    559 
    560   @retval EFI_SUCCESS           The function completed successfully.
    561   @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
    562   @retval EFI_OUT_OF_RESOURCES  Memory could not be allocated for the thunk.
    563 
    564 **/
    565 EFI_STATUS
    566 EFIAPI
    567 EbcCreateThunk (
    568   IN EFI_EBC_PROTOCOL   *This,
    569   IN EFI_HANDLE         ImageHandle,
    570   IN VOID               *EbcEntryPoint,
    571   OUT VOID              **Thunk
    572   )
    573 {
    574   EFI_STATUS  Status;
    575 
    576   Status = EbcCreateThunks (
    577             ImageHandle,
    578             EbcEntryPoint,
    579             Thunk,
    580             FLAG_THUNK_ENTRY_POINT
    581             );
    582   return Status;
    583 }
    584 
    585 
    586 /**
    587   This EBC debugger protocol service is called by the debug agent
    588 
    589   @param  This                  A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
    590                                 instance.
    591   @param  MaxProcessorIndex     Pointer to a caller-allocated UINTN in which the
    592                                 maximum supported processor index is returned.
    593 
    594   @retval EFI_SUCCESS           The function completed successfully.
    595 
    596 **/
    597 EFI_STATUS
    598 EFIAPI
    599 EbcDebugGetMaximumProcessorIndex (
    600   IN EFI_DEBUG_SUPPORT_PROTOCOL          *This,
    601   OUT UINTN                              *MaxProcessorIndex
    602   )
    603 {
    604   *MaxProcessorIndex = 0;
    605   return EFI_SUCCESS;
    606 }
    607 
    608 
    609 /**
    610   This protocol service is called by the debug agent to register a function
    611   for us to call on a periodic basis.
    612 
    613   @param  This                  A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
    614                                 instance.
    615   @param  ProcessorIndex        Specifies which processor the callback function
    616                                 applies to.
    617   @param  PeriodicCallback      A pointer to a function of type
    618                                 PERIODIC_CALLBACK that is the main periodic
    619                                 entry point of the debug agent. It receives as a
    620                                 parameter a pointer to the full context of the
    621                                 interrupted execution thread.
    622 
    623   @retval EFI_SUCCESS           The function completed successfully.
    624   @retval EFI_ALREADY_STARTED   Non-NULL PeriodicCallback parameter when a
    625                                 callback function was previously registered.
    626   @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
    627                                 callback function was previously registered.
    628 
    629 **/
    630 EFI_STATUS
    631 EFIAPI
    632 EbcDebugRegisterPeriodicCallback (
    633   IN EFI_DEBUG_SUPPORT_PROTOCOL  *This,
    634   IN UINTN                       ProcessorIndex,
    635   IN EFI_PERIODIC_CALLBACK       PeriodicCallback
    636   )
    637 {
    638   if ((mDebugPeriodicCallback == NULL) && (PeriodicCallback == NULL)) {
    639     return EFI_INVALID_PARAMETER;
    640   }
    641   if ((mDebugPeriodicCallback != NULL) && (PeriodicCallback != NULL)) {
    642     return EFI_ALREADY_STARTED;
    643   }
    644 
    645   mDebugPeriodicCallback = PeriodicCallback;
    646   return EFI_SUCCESS;
    647 }
    648 
    649 
    650 /**
    651   This protocol service is called by the debug agent to register a function
    652   for us to call when we detect an exception.
    653 
    654   @param  This                  A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
    655                                 instance.
    656   @param  ProcessorIndex        Specifies which processor the callback function
    657                                 applies to.
    658   @param  ExceptionCallback     A pointer to a function of type
    659                                 EXCEPTION_CALLBACK that is called when the
    660                                 processor exception specified by ExceptionType
    661                                 occurs. Passing NULL unregisters any previously
    662                                 registered function associated with
    663                                 ExceptionType.
    664   @param  ExceptionType         Specifies which processor exception to hook.
    665 
    666   @retval EFI_SUCCESS           The function completed successfully.
    667   @retval EFI_ALREADY_STARTED   Non-NULL ExceptionCallback parameter when a
    668                                 callback function was previously registered.
    669   @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
    670                                 MAX_EBC_EXCEPTION.
    671   @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
    672                                 callback function was previously registered.
    673 
    674 **/
    675 EFI_STATUS
    676 EFIAPI
    677 EbcDebugRegisterExceptionCallback (
    678   IN EFI_DEBUG_SUPPORT_PROTOCOL  *This,
    679   IN UINTN                       ProcessorIndex,
    680   IN EFI_EXCEPTION_CALLBACK      ExceptionCallback,
    681   IN EFI_EXCEPTION_TYPE          ExceptionType
    682   )
    683 {
    684   if ((ExceptionType < 0) || (ExceptionType > MAX_EBC_EXCEPTION)) {
    685     return EFI_INVALID_PARAMETER;
    686   }
    687   if ((mDebugExceptionCallback[ExceptionType] == NULL) && (ExceptionCallback == NULL)) {
    688     return EFI_INVALID_PARAMETER;
    689   }
    690   if ((mDebugExceptionCallback[ExceptionType] != NULL) && (ExceptionCallback != NULL)) {
    691     return EFI_ALREADY_STARTED;
    692   }
    693   mDebugExceptionCallback[ExceptionType] = ExceptionCallback;
    694   return EFI_SUCCESS;
    695 }
    696 
    697 
    698 /**
    699   This EBC debugger protocol service is called by the debug agent.  Required
    700   for DebugSupport compliance but is only stubbed out for EBC.
    701 
    702   @param  This                  A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
    703                                 instance.
    704   @param  ProcessorIndex        Specifies which processor the callback function
    705                                 applies to.
    706   @param  Start                 StartSpecifies the physical base of the memory
    707                                 range to be invalidated.
    708   @param  Length                Specifies the minimum number of bytes in the
    709                                 processor's instruction cache to invalidate.
    710 
    711   @retval EFI_SUCCESS           The function completed successfully.
    712 
    713 **/
    714 EFI_STATUS
    715 EFIAPI
    716 EbcDebugInvalidateInstructionCache (
    717   IN EFI_DEBUG_SUPPORT_PROTOCOL          *This,
    718   IN UINTN                               ProcessorIndex,
    719   IN VOID                                *Start,
    720   IN UINT64                              Length
    721   )
    722 {
    723   return EFI_SUCCESS;
    724 }
    725 
    726 
    727 /**
    728   The VM interpreter calls this function when an exception is detected.
    729 
    730   @param  ExceptionType          Specifies the processor exception detected.
    731   @param  ExceptionFlags         Specifies the exception context.
    732   @param  VmPtr                  Pointer to a VM context for passing info to the
    733                                  EFI debugger.
    734 
    735   @retval EFI_SUCCESS            This function completed successfully.
    736 
    737 **/
    738 EFI_STATUS
    739 EbcDebugSignalException (
    740   IN EFI_EXCEPTION_TYPE                   ExceptionType,
    741   IN EXCEPTION_FLAGS                      ExceptionFlags,
    742   IN VM_CONTEXT                           *VmPtr
    743   )
    744 {
    745   EFI_SYSTEM_CONTEXT_EBC  EbcContext;
    746   EFI_SYSTEM_CONTEXT      SystemContext;
    747 
    748   ASSERT ((ExceptionType >= 0) && (ExceptionType <= MAX_EBC_EXCEPTION));
    749   //
    750   // Save the exception in the context passed in
    751   //
    752   VmPtr->ExceptionFlags |= ExceptionFlags;
    753   VmPtr->LastException = (UINTN) ExceptionType;
    754   //
    755   // If it's a fatal exception, then flag it in the VM context in case an
    756   // attached debugger tries to return from it.
    757   //
    758   if ((ExceptionFlags & EXCEPTION_FLAG_FATAL) != 0) {
    759     VmPtr->StopFlags |= STOPFLAG_APP_DONE;
    760   }
    761 
    762   //
    763   // If someone's registered for exception callbacks, then call them.
    764   //
    765   // EBC driver will register default exception callback to report the
    766   // status code via the status code API
    767   //
    768   if (mDebugExceptionCallback[ExceptionType] != NULL) {
    769 
    770     //
    771     // Initialize the context structure
    772     //
    773     EbcContext.R0                   = (UINT64) VmPtr->Gpr[0];
    774     EbcContext.R1                   = (UINT64) VmPtr->Gpr[1];
    775     EbcContext.R2                   = (UINT64) VmPtr->Gpr[2];
    776     EbcContext.R3                   = (UINT64) VmPtr->Gpr[3];
    777     EbcContext.R4                   = (UINT64) VmPtr->Gpr[4];
    778     EbcContext.R5                   = (UINT64) VmPtr->Gpr[5];
    779     EbcContext.R6                   = (UINT64) VmPtr->Gpr[6];
    780     EbcContext.R7                   = (UINT64) VmPtr->Gpr[7];
    781     EbcContext.Ip                   = (UINT64)(UINTN)VmPtr->Ip;
    782     EbcContext.Flags                = VmPtr->Flags;
    783     EbcContext.ControlFlags         = 0;
    784     SystemContext.SystemContextEbc  = &EbcContext;
    785 
    786     mDebugExceptionCallback[ExceptionType] (ExceptionType, SystemContext);
    787     //
    788     // Restore the context structure and continue to execute
    789     //
    790     VmPtr->Gpr[0]  = EbcContext.R0;
    791     VmPtr->Gpr[1]  = EbcContext.R1;
    792     VmPtr->Gpr[2]  = EbcContext.R2;
    793     VmPtr->Gpr[3]  = EbcContext.R3;
    794     VmPtr->Gpr[4]  = EbcContext.R4;
    795     VmPtr->Gpr[5]  = EbcContext.R5;
    796     VmPtr->Gpr[6]  = EbcContext.R6;
    797     VmPtr->Gpr[7]  = EbcContext.R7;
    798     VmPtr->Ip    = (VMIP)(UINTN)EbcContext.Ip;
    799     VmPtr->Flags = EbcContext.Flags;
    800   }
    801 
    802   return EFI_SUCCESS;
    803 }
    804 
    805 
    806 /**
    807   To install default Callback function for the VM interpreter.
    808 
    809   @param  This                  A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
    810                                 instance.
    811 
    812   @retval EFI_SUCCESS           The function completed successfully.
    813   @retval Others                Some error occurs when creating periodic event.
    814 
    815 **/
    816 EFI_STATUS
    817 EFIAPI
    818 InitializeEbcCallback (
    819   IN EFI_DEBUG_SUPPORT_PROTOCOL  *This
    820   )
    821 {
    822   INTN       Index;
    823   EFI_STATUS Status;
    824 
    825   //
    826   // For ExceptionCallback
    827   //
    828   for (Index = 0; Index <= MAX_EBC_EXCEPTION; Index++) {
    829     EbcDebugRegisterExceptionCallback (
    830       This,
    831       0,
    832       CommonEbcExceptionHandler,
    833       Index
    834       );
    835   }
    836 
    837   //
    838   // For PeriodicCallback
    839   //
    840   Status = gBS->CreateEvent (
    841                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
    842                   TPL_NOTIFY,
    843                   EbcPeriodicNotifyFunction,
    844                   &mVmPtr,
    845                   &mEbcPeriodicEvent
    846                   );
    847   if (EFI_ERROR(Status)) {
    848     return Status;
    849   }
    850 
    851   Status = gBS->SetTimer (
    852                   mEbcPeriodicEvent,
    853                   TimerPeriodic,
    854                   EBC_VM_PERIODIC_CALLBACK_RATE
    855                   );
    856   if (EFI_ERROR(Status)) {
    857     return Status;
    858   }
    859 
    860   return EFI_SUCCESS;
    861 }
    862 
    863 
    864 /**
    865   The default Exception Callback for the VM interpreter.
    866   In this function, we report status code, and print debug information
    867   about EBC_CONTEXT, then dead loop.
    868 
    869   @param  InterruptType          Interrupt type.
    870   @param  SystemContext          EBC system context.
    871 
    872 **/
    873 VOID
    874 EFIAPI
    875 CommonEbcExceptionHandler (
    876   IN EFI_EXCEPTION_TYPE   InterruptType,
    877   IN EFI_SYSTEM_CONTEXT   SystemContext
    878   )
    879 {
    880   //
    881   // We print debug information to let user know what happen.
    882   //
    883   DEBUG ((
    884     EFI_D_ERROR,
    885     "EBC Interrupter Version - 0x%016lx\n",
    886     (UINT64) (((VM_MAJOR_VERSION & 0xFFFF) << 16) | ((VM_MINOR_VERSION & 0xFFFF)))
    887     ));
    888   DEBUG ((
    889     EFI_D_ERROR,
    890     "Exception Type - 0x%016lx\n",
    891     (UINT64)(UINTN)InterruptType
    892     ));
    893   DEBUG ((
    894     EFI_D_ERROR,
    895     "  R0 - 0x%016lx, R1 - 0x%016lx\n",
    896     SystemContext.SystemContextEbc->R0,
    897     SystemContext.SystemContextEbc->R1
    898     ));
    899   DEBUG ((
    900     EFI_D_ERROR,
    901     "  R2 - 0x%016lx, R3 - 0x%016lx\n",
    902     SystemContext.SystemContextEbc->R2,
    903     SystemContext.SystemContextEbc->R3
    904     ));
    905   DEBUG ((
    906     EFI_D_ERROR,
    907     "  R4 - 0x%016lx, R5 - 0x%016lx\n",
    908     SystemContext.SystemContextEbc->R4,
    909     SystemContext.SystemContextEbc->R5
    910     ));
    911   DEBUG ((
    912     EFI_D_ERROR,
    913     "  R6 - 0x%016lx, R7 - 0x%016lx\n",
    914     SystemContext.SystemContextEbc->R6,
    915     SystemContext.SystemContextEbc->R7
    916     ));
    917   DEBUG ((
    918     EFI_D_ERROR,
    919     "  Flags - 0x%016lx\n",
    920     SystemContext.SystemContextEbc->Flags
    921     ));
    922   DEBUG ((
    923     EFI_D_ERROR,
    924     "  ControlFlags - 0x%016lx\n",
    925     SystemContext.SystemContextEbc->ControlFlags
    926     ));
    927   DEBUG ((
    928     EFI_D_ERROR,
    929     "  Ip - 0x%016lx\n\n",
    930     SystemContext.SystemContextEbc->Ip
    931     ));
    932 
    933   //
    934   // We deadloop here to make it easy to debug this issue.
    935   //
    936   CpuDeadLoop ();
    937 
    938   return ;
    939 }
    940 
    941 
    942 /**
    943   The periodic callback function for EBC VM interpreter, which is used
    944   to support the EFI debug support protocol.
    945 
    946   @param  Event                  The Periodic Callback Event.
    947   @param  Context                It should be the address of VM_CONTEXT pointer.
    948 
    949 **/
    950 VOID
    951 EFIAPI
    952 EbcPeriodicNotifyFunction (
    953   IN EFI_EVENT     Event,
    954   IN VOID          *Context
    955   )
    956 {
    957   VM_CONTEXT *VmPtr;
    958 
    959   VmPtr = *(VM_CONTEXT **)Context;
    960 
    961   if (VmPtr != NULL) {
    962     EbcDebugPeriodic (VmPtr);
    963   }
    964 
    965   return ;
    966 }
    967 
    968 
    969 /**
    970   The VM interpreter calls this function on a periodic basis to support
    971   the EFI debug support protocol.
    972 
    973   @param  VmPtr                  Pointer to a VM context for passing info to the
    974                                  debugger.
    975 
    976   @retval EFI_SUCCESS            The function completed successfully.
    977 
    978 **/
    979 EFI_STATUS
    980 EFIAPI
    981 EbcDebugPeriodic (
    982   IN VM_CONTEXT *VmPtr
    983   )
    984 {
    985   EFI_SYSTEM_CONTEXT_EBC   EbcContext;
    986   EFI_SYSTEM_CONTEXT       SystemContext;
    987 
    988   //
    989   // If someone's registered for periodic callbacks, then call them.
    990   //
    991   if (mDebugPeriodicCallback != NULL) {
    992 
    993     //
    994     // Initialize the context structure
    995     //
    996     EbcContext.R0                   = (UINT64) VmPtr->Gpr[0];
    997     EbcContext.R1                   = (UINT64) VmPtr->Gpr[1];
    998     EbcContext.R2                   = (UINT64) VmPtr->Gpr[2];
    999     EbcContext.R3                   = (UINT64) VmPtr->Gpr[3];
   1000     EbcContext.R4                   = (UINT64) VmPtr->Gpr[4];
   1001     EbcContext.R5                   = (UINT64) VmPtr->Gpr[5];
   1002     EbcContext.R6                   = (UINT64) VmPtr->Gpr[6];
   1003     EbcContext.R7                   = (UINT64) VmPtr->Gpr[7];
   1004     EbcContext.Ip                   = (UINT64)(UINTN)VmPtr->Ip;
   1005     EbcContext.Flags                = VmPtr->Flags;
   1006     EbcContext.ControlFlags         = 0;
   1007     SystemContext.SystemContextEbc  = &EbcContext;
   1008 
   1009     mDebugPeriodicCallback (SystemContext);
   1010 
   1011     //
   1012     // Restore the context structure and continue to execute
   1013     //
   1014     VmPtr->Gpr[0]  = EbcContext.R0;
   1015     VmPtr->Gpr[1]  = EbcContext.R1;
   1016     VmPtr->Gpr[2]  = EbcContext.R2;
   1017     VmPtr->Gpr[3]  = EbcContext.R3;
   1018     VmPtr->Gpr[4]  = EbcContext.R4;
   1019     VmPtr->Gpr[5]  = EbcContext.R5;
   1020     VmPtr->Gpr[6]  = EbcContext.R6;
   1021     VmPtr->Gpr[7]  = EbcContext.R7;
   1022     VmPtr->Ip    = (VMIP)(UINTN)EbcContext.Ip;
   1023     VmPtr->Flags = EbcContext.Flags;
   1024   }
   1025 
   1026   return EFI_SUCCESS;
   1027 }
   1028 
   1029 
   1030 /**
   1031   This routine is called by the core when an image is being unloaded from
   1032   memory. Basically we now have the opportunity to do any necessary cleanup.
   1033   Typically this will include freeing any memory allocated for thunk-creation.
   1034 
   1035   @param  This                  A pointer to the EFI_EBC_PROTOCOL instance.
   1036   @param  ImageHandle           Handle of image for which the thunk is being
   1037                                 created.
   1038 
   1039   @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
   1040                                 internal list of EBC image handles.
   1041   @retval EFI_SUCCESS           The function completed successfully.
   1042 
   1043 **/
   1044 EFI_STATUS
   1045 EFIAPI
   1046 EbcUnloadImage (
   1047   IN EFI_EBC_PROTOCOL   *This,
   1048   IN EFI_HANDLE         ImageHandle
   1049   )
   1050 {
   1051   EBC_THUNK_LIST  *ThunkList;
   1052   EBC_THUNK_LIST  *NextThunkList;
   1053   EBC_IMAGE_LIST  *ImageList;
   1054   EBC_IMAGE_LIST  *PrevImageList;
   1055   //
   1056   // First go through our list of known image handles and see if we've already
   1057   // created an image list element for this image handle.
   1058   //
   1059   ReturnEBCStackByHandle(ImageHandle);
   1060   PrevImageList = NULL;
   1061   for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
   1062     if (ImageList->ImageHandle == ImageHandle) {
   1063       break;
   1064     }
   1065     //
   1066     // Save the previous so we can connect the lists when we remove this one
   1067     //
   1068     PrevImageList = ImageList;
   1069   }
   1070 
   1071   if (ImageList == NULL) {
   1072     return EFI_INVALID_PARAMETER;
   1073   }
   1074   //
   1075   // Free up all the thunk buffers and thunks list elements for this image
   1076   // handle.
   1077   //
   1078   ThunkList = ImageList->ThunkList;
   1079   while (ThunkList != NULL) {
   1080     NextThunkList = ThunkList->Next;
   1081     FreePool (ThunkList->ThunkBuffer);
   1082     FreePool (ThunkList);
   1083     ThunkList = NextThunkList;
   1084   }
   1085   //
   1086   // Now remove this image list element from the chain
   1087   //
   1088   if (PrevImageList == NULL) {
   1089     //
   1090     // Remove from head
   1091     //
   1092     mEbcImageList = ImageList->Next;
   1093   } else {
   1094     PrevImageList->Next = ImageList->Next;
   1095   }
   1096   //
   1097   // Now free up the image list element
   1098   //
   1099   FreePool (ImageList);
   1100 
   1101   EbcDebuggerHookEbcUnloadImage (ImageHandle);
   1102 
   1103   return EFI_SUCCESS;
   1104 }
   1105 
   1106 
   1107 /**
   1108   Add a thunk to our list of thunks for a given image handle.
   1109   Also flush the instruction cache since we've written thunk code
   1110   to memory that will be executed eventually.
   1111 
   1112   @param  ImageHandle            The image handle to which the thunk is tied.
   1113   @param  ThunkBuffer            The buffer that has been created/allocated.
   1114   @param  ThunkSize              The size of the thunk memory allocated.
   1115 
   1116   @retval EFI_OUT_OF_RESOURCES   Memory allocation failed.
   1117   @retval EFI_SUCCESS            The function completed successfully.
   1118 
   1119 **/
   1120 EFI_STATUS
   1121 EbcAddImageThunk (
   1122   IN EFI_HANDLE      ImageHandle,
   1123   IN VOID            *ThunkBuffer,
   1124   IN UINT32          ThunkSize
   1125   )
   1126 {
   1127   EBC_THUNK_LIST  *ThunkList;
   1128   EBC_IMAGE_LIST  *ImageList;
   1129   EFI_STATUS      Status;
   1130 
   1131   //
   1132   // It so far so good, then flush the instruction cache
   1133   //
   1134   if (mEbcICacheFlush != NULL) {
   1135     Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS) (UINTN) ThunkBuffer, ThunkSize);
   1136     if (EFI_ERROR (Status)) {
   1137       return Status;
   1138     }
   1139   }
   1140   //
   1141   // Go through our list of known image handles and see if we've already
   1142   // created a image list element for this image handle.
   1143   //
   1144   for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
   1145     if (ImageList->ImageHandle == ImageHandle) {
   1146       break;
   1147     }
   1148   }
   1149 
   1150   if (ImageList == NULL) {
   1151     //
   1152     // Allocate a new one
   1153     //
   1154     ImageList = AllocatePool (sizeof (EBC_IMAGE_LIST));
   1155 
   1156     if (ImageList == NULL) {
   1157       return EFI_OUT_OF_RESOURCES;
   1158     }
   1159 
   1160     ImageList->ThunkList    = NULL;
   1161     ImageList->ImageHandle  = ImageHandle;
   1162     ImageList->Next         = mEbcImageList;
   1163     mEbcImageList           = ImageList;
   1164   }
   1165   //
   1166   // Ok, now create a new thunk element to add to the list
   1167   //
   1168   ThunkList = AllocatePool (sizeof (EBC_THUNK_LIST));
   1169 
   1170   if (ThunkList == NULL) {
   1171     return EFI_OUT_OF_RESOURCES;
   1172   }
   1173   //
   1174   // Add it to the head of the list
   1175   //
   1176   ThunkList->Next         = ImageList->ThunkList;
   1177   ThunkList->ThunkBuffer  = ThunkBuffer;
   1178   ImageList->ThunkList    = ThunkList;
   1179   return EFI_SUCCESS;
   1180 }
   1181 
   1182 /**
   1183   Registers a callback function that the EBC interpreter calls to flush the
   1184   processor instruction cache following creation of thunks.
   1185 
   1186   @param  This        A pointer to the EFI_EBC_PROTOCOL instance.
   1187   @param  Flush       Pointer to a function of type EBC_ICACH_FLUSH.
   1188 
   1189   @retval EFI_SUCCESS The function completed successfully.
   1190 
   1191 **/
   1192 EFI_STATUS
   1193 EFIAPI
   1194 EbcRegisterICacheFlush (
   1195   IN EFI_EBC_PROTOCOL   *This,
   1196   IN EBC_ICACHE_FLUSH   Flush
   1197   )
   1198 {
   1199   mEbcICacheFlush = Flush;
   1200   return EFI_SUCCESS;
   1201 }
   1202 
   1203 /**
   1204   Called to get the version of the interpreter.
   1205 
   1206   @param  This                  A pointer to the EFI_EBC_PROTOCOL instance.
   1207   @param  Version               Pointer to where to store the returned version
   1208                                 of the interpreter.
   1209 
   1210   @retval EFI_SUCCESS           The function completed successfully.
   1211   @retval EFI_INVALID_PARAMETER Version pointer is NULL.
   1212 
   1213 **/
   1214 EFI_STATUS
   1215 EFIAPI
   1216 EbcGetVersion (
   1217   IN EFI_EBC_PROTOCOL   *This,
   1218   IN OUT UINT64         *Version
   1219   )
   1220 {
   1221   if (Version == NULL) {
   1222     return EFI_INVALID_PARAMETER;
   1223   }
   1224 
   1225   *Version = GetVmVersion ();
   1226   return EFI_SUCCESS;
   1227 }
   1228 
   1229 /**
   1230   Returns the stack index and buffer assosicated with the Handle parameter.
   1231 
   1232   @param  Handle                The EFI handle as the index to the EBC stack.
   1233   @param  StackBuffer           A pointer to hold the returned stack buffer.
   1234   @param  BufferIndex           A pointer to hold the returned stack index.
   1235 
   1236   @retval EFI_OUT_OF_RESOURCES  The Handle parameter does not correspond to any
   1237                                 existing EBC stack.
   1238   @retval EFI_SUCCESS           The stack index and buffer were found and
   1239                                 returned to the caller.
   1240 
   1241 **/
   1242 EFI_STATUS
   1243 GetEBCStack(
   1244   IN  EFI_HANDLE Handle,
   1245   OUT VOID       **StackBuffer,
   1246   OUT UINTN      *BufferIndex
   1247   )
   1248 {
   1249   UINTN   Index;
   1250   EFI_TPL OldTpl;
   1251   OldTpl = gBS->RaiseTPL(TPL_HIGH_LEVEL);
   1252   for (Index = 0; Index < mStackNum; Index ++) {
   1253     if (mStackBufferIndex[Index] == NULL) {
   1254       mStackBufferIndex[Index] = Handle;
   1255       break;
   1256     }
   1257   }
   1258   gBS->RestoreTPL(OldTpl);
   1259   if (Index == mStackNum) {
   1260     return EFI_OUT_OF_RESOURCES;
   1261   }
   1262   *BufferIndex = Index;
   1263   *StackBuffer = mStackBuffer[Index];
   1264   return EFI_SUCCESS;
   1265 }
   1266 
   1267 /**
   1268   Returns from the EBC stack by stack Index.
   1269 
   1270   @param  Index        Specifies which EBC stack to return from.
   1271 
   1272   @retval EFI_SUCCESS  The function completed successfully.
   1273 
   1274 **/
   1275 EFI_STATUS
   1276 ReturnEBCStack(
   1277   IN UINTN Index
   1278   )
   1279 {
   1280   mStackBufferIndex[Index] = NULL;
   1281   return EFI_SUCCESS;
   1282 }
   1283 
   1284 /**
   1285   Returns from the EBC stack associated with the Handle parameter.
   1286 
   1287   @param  Handle      Specifies the EFI handle to find the EBC stack with.
   1288 
   1289   @retval EFI_SUCCESS The function completed successfully.
   1290 
   1291 **/
   1292 EFI_STATUS
   1293 ReturnEBCStackByHandle(
   1294   IN EFI_HANDLE Handle
   1295   )
   1296 {
   1297   UINTN Index;
   1298   for (Index = 0; Index < mStackNum; Index ++) {
   1299     if (mStackBufferIndex[Index] == Handle) {
   1300       break;
   1301     }
   1302   }
   1303   if (Index == mStackNum) {
   1304     return EFI_NOT_FOUND;
   1305   }
   1306   mStackBufferIndex[Index] = NULL;
   1307   return EFI_SUCCESS;
   1308 }
   1309 
   1310 /**
   1311   Allocates memory to hold all the EBC stacks.
   1312 
   1313   @retval EFI_SUCCESS          The EBC stacks were allocated successfully.
   1314   @retval EFI_OUT_OF_RESOURCES Not enough memory available for EBC stacks.
   1315 
   1316 **/
   1317 EFI_STATUS
   1318 InitEBCStack (
   1319   VOID
   1320   )
   1321 {
   1322   for (mStackNum = 0; mStackNum < MAX_STACK_NUM; mStackNum ++) {
   1323     mStackBuffer[mStackNum] = AllocatePool(STACK_POOL_SIZE);
   1324     mStackBufferIndex[mStackNum] = NULL;
   1325     if (mStackBuffer[mStackNum] == NULL) {
   1326       break;
   1327     }
   1328   }
   1329   if (mStackNum == 0) {
   1330     return EFI_OUT_OF_RESOURCES;
   1331   }
   1332   return EFI_SUCCESS;
   1333 }
   1334 
   1335 
   1336 /**
   1337   Free all EBC stacks allocated before.
   1338 
   1339   @retval EFI_SUCCESS   All the EBC stacks were freed.
   1340 
   1341 **/
   1342 EFI_STATUS
   1343 FreeEBCStack(
   1344   VOID
   1345   )
   1346 {
   1347   UINTN Index;
   1348   for (Index = 0; Index < mStackNum; Index ++) {
   1349     FreePool(mStackBuffer[Index]);
   1350   }
   1351   return EFI_SUCCESS;
   1352 }
   1353 
   1354 /**
   1355   Produces an EBC VM test protocol that can be used for regression tests.
   1356 
   1357   @param  IHandle                Handle on which to install the protocol.
   1358 
   1359   @retval EFI_OUT_OF_RESOURCES   Memory allocation failed.
   1360   @retval EFI_SUCCESS            The function completed successfully.
   1361 
   1362 **/
   1363 EFI_STATUS
   1364 InitEbcVmTestProtocol (
   1365   IN EFI_HANDLE     *IHandle
   1366   )
   1367 {
   1368   EFI_HANDLE Handle;
   1369   EFI_STATUS Status;
   1370   EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;
   1371 
   1372   //
   1373   // Allocate memory for the protocol, then fill in the fields
   1374   //
   1375   EbcVmTestProtocol = AllocatePool (sizeof (EFI_EBC_VM_TEST_PROTOCOL));
   1376   if (EbcVmTestProtocol == NULL) {
   1377     return EFI_OUT_OF_RESOURCES;
   1378   }
   1379   EbcVmTestProtocol->Execute      = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;
   1380 
   1381   DEBUG_CODE_BEGIN ();
   1382     EbcVmTestProtocol->Assemble     = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;
   1383     EbcVmTestProtocol->Disassemble  = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;
   1384   DEBUG_CODE_END ();
   1385 
   1386   //
   1387   // Publish the protocol
   1388   //
   1389   Handle  = NULL;
   1390   Status  = gBS->InstallProtocolInterface (&Handle, &gEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);
   1391   if (EFI_ERROR (Status)) {
   1392     FreePool (EbcVmTestProtocol);
   1393   }
   1394   return Status;
   1395 }
   1396 
   1397 
   1398 /**
   1399   Returns the EFI_UNSUPPORTED Status.
   1400 
   1401   @return EFI_UNSUPPORTED  This function always return EFI_UNSUPPORTED status.
   1402 
   1403 **/
   1404 EFI_STATUS
   1405 EFIAPI
   1406 EbcVmTestUnsupported (
   1407   VOID
   1408   )
   1409 {
   1410   return EFI_UNSUPPORTED;
   1411 }
   1412 
   1413