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