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