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