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