apply for doxgen format.
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / EbcDxe / EbcInt.c
1 /** @file\r
2   Top level module for the EBC virtual machine implementation.\r
3   Provides auxilliary support routines for the VM. That is, routines\r
4   that are not particularly related to VM execution of EBC instructions.\r
5 \r
6 Copyright (c) 2006, Intel Corporation\r
7 All rights reserved. This program and the accompanying materials\r
8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution.  The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php\r
11 \r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14 \r
15 **/\r
16 \r
17 #include "EbcInt.h"\r
18 #include "EbcExecute.h"\r
19 \r
20 //\r
21 // We'll keep track of all thunks we create in a linked list. Each\r
22 // thunk is tied to an image handle, so we have a linked list of\r
23 // image handles, with each having a linked list of thunks allocated\r
24 // to that image handle.\r
25 //\r
26 typedef struct _EBC_THUNK_LIST {\r
27   VOID                    *ThunkBuffer;\r
28   struct _EBC_THUNK_LIST  *Next;\r
29 } EBC_THUNK_LIST;\r
30 \r
31 typedef struct _EBC_IMAGE_LIST {\r
32   struct _EBC_IMAGE_LIST  *Next;\r
33   EFI_HANDLE              ImageHandle;\r
34   EBC_THUNK_LIST          *ThunkList;\r
35 } EBC_IMAGE_LIST;\r
36 \r
37 STATIC\r
38 EFI_STATUS\r
39 EFIAPI\r
40 EbcUnloadImage (\r
41   IN EFI_EBC_PROTOCOL     *This,\r
42   IN EFI_HANDLE           ImageHandle\r
43   );\r
44 \r
45 STATIC\r
46 EFI_STATUS\r
47 EFIAPI\r
48 EbcCreateThunk (\r
49   IN EFI_EBC_PROTOCOL     *This,\r
50   IN EFI_HANDLE           ImageHandle,\r
51   IN VOID                 *EbcEntryPoint,\r
52   OUT VOID                **Thunk\r
53   );\r
54 \r
55 STATIC\r
56 EFI_STATUS\r
57 EFIAPI\r
58 EbcGetVersion (\r
59   IN EFI_EBC_PROTOCOL     *This,\r
60   IN OUT UINT64           *Version\r
61   );\r
62 \r
63 STATIC\r
64 EFI_STATUS\r
65 EFIAPI\r
66 InitializeEbcCallback (\r
67   IN EFI_DEBUG_SUPPORT_PROTOCOL  *This\r
68   );\r
69 \r
70 STATIC\r
71 VOID\r
72 EFIAPI\r
73 CommonEbcExceptionHandler (\r
74   IN EFI_EXCEPTION_TYPE   InterruptType,\r
75   IN EFI_SYSTEM_CONTEXT   SystemContext\r
76   );\r
77 \r
78 STATIC\r
79 VOID\r
80 EFIAPI\r
81 EbcPeriodicNotifyFunction (\r
82   IN EFI_EVENT     Event,\r
83   IN VOID          *Context\r
84   );\r
85 \r
86 STATIC\r
87 EFI_STATUS\r
88 EFIAPI\r
89 EbcDebugPeriodic (\r
90   IN VM_CONTEXT *VmPtr\r
91   );\r
92 \r
93 //\r
94 // These two functions and the  GUID are used to produce an EBC test protocol.\r
95 // This functionality is definitely not required for execution.\r
96 //\r
97 STATIC\r
98 EFI_STATUS\r
99 InitEbcVmTestProtocol (\r
100   IN EFI_HANDLE     *Handle\r
101   );\r
102 \r
103 STATIC\r
104 EFI_STATUS\r
105 EbcVmTestUnsupported (\r
106   VOID\r
107   );\r
108 \r
109 STATIC\r
110 EFI_STATUS\r
111 EFIAPI\r
112 EbcRegisterICacheFlush (\r
113   IN EFI_EBC_PROTOCOL               *This,\r
114   IN EBC_ICACHE_FLUSH               Flush\r
115   );\r
116 \r
117 STATIC\r
118 EFI_STATUS\r
119 EFIAPI\r
120 EbcDebugGetMaximumProcessorIndex (\r
121   IN EFI_DEBUG_SUPPORT_PROTOCOL     *This,\r
122   OUT UINTN                         *MaxProcessorIndex\r
123   );\r
124 \r
125 STATIC\r
126 EFI_STATUS\r
127 EFIAPI\r
128 EbcDebugRegisterPeriodicCallback (\r
129   IN EFI_DEBUG_SUPPORT_PROTOCOL     *This,\r
130   IN UINTN                          ProcessorIndex,\r
131   IN EFI_PERIODIC_CALLBACK          PeriodicCallback\r
132   );\r
133 \r
134 STATIC\r
135 EFI_STATUS\r
136 EFIAPI\r
137 EbcDebugRegisterExceptionCallback (\r
138   IN EFI_DEBUG_SUPPORT_PROTOCOL     *This,\r
139   IN UINTN                          ProcessorIndex,\r
140   IN EFI_EXCEPTION_CALLBACK         ExceptionCallback,\r
141   IN EFI_EXCEPTION_TYPE             ExceptionType\r
142   );\r
143 \r
144 STATIC\r
145 EFI_STATUS\r
146 EFIAPI\r
147 EbcDebugInvalidateInstructionCache (\r
148   IN EFI_DEBUG_SUPPORT_PROTOCOL     *This,\r
149   IN UINTN                          ProcessorIndex,\r
150   IN VOID                           *Start,\r
151   IN UINT64                         Length\r
152   );\r
153 \r
154 //\r
155 // We have one linked list of image handles for the whole world. Since\r
156 // there should only be one interpreter, make them global. They must\r
157 // also be global since the execution of an EBC image does not provide\r
158 // a This pointer.\r
159 //\r
160 static EBC_IMAGE_LIST         *mEbcImageList = NULL;\r
161 \r
162 //\r
163 // Callback function to flush the icache after thunk creation\r
164 //\r
165 static EBC_ICACHE_FLUSH       mEbcICacheFlush;\r
166 \r
167 //\r
168 // These get set via calls by the debug agent\r
169 //\r
170 static EFI_PERIODIC_CALLBACK  mDebugPeriodicCallback                            = NULL;\r
171 static EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = {NULL};\r
172 static EFI_GUID               mEfiEbcVmTestProtocolGuid = EFI_EBC_VM_TEST_PROTOCOL_GUID;\r
173 \r
174 static VOID*      mStackBuffer[MAX_STACK_NUM];\r
175 static EFI_HANDLE mStackBufferIndex[MAX_STACK_NUM];\r
176 static UINTN      mStackNum = 0;\r
177 \r
178 //\r
179 // Event for Periodic callback\r
180 //\r
181 static EFI_EVENT              mEbcPeriodicEvent;\r
182 VM_CONTEXT                    *mVmPtr = NULL;\r
183 \r
184 \r
185 /**\r
186   Initializes the VM EFI interface.  Allocates memory for the VM interface\r
187   and registers the VM protocol.\r
188 \r
189   @param  ImageHandle            EFI image handle.\r
190   @param  SystemTable            Pointer to the EFI system table.\r
191 \r
192   @return Standard EFI status code.\r
193 \r
194 **/\r
195 EFI_STATUS\r
196 EFIAPI\r
197 InitializeEbcDriver (\r
198   IN EFI_HANDLE           ImageHandle,\r
199   IN EFI_SYSTEM_TABLE     *SystemTable\r
200   )\r
201 {\r
202   EFI_EBC_PROTOCOL            *EbcProtocol;\r
203   EFI_EBC_PROTOCOL            *OldEbcProtocol;\r
204   EFI_STATUS                  Status;\r
205   EFI_DEBUG_SUPPORT_PROTOCOL  *EbcDebugProtocol;\r
206   EFI_HANDLE                  *HandleBuffer;\r
207   UINTN                       NumHandles;\r
208   UINTN                       Index;\r
209   BOOLEAN                     Installed;\r
210 \r
211   EbcProtocol      = NULL;\r
212   EbcDebugProtocol = NULL;\r
213 \r
214   //\r
215   // Allocate memory for our protocol. Then fill in the blanks.\r
216   //\r
217   EbcProtocol = AllocatePool (sizeof (EFI_EBC_PROTOCOL));\r
218 \r
219   if (EbcProtocol == NULL) {\r
220     return EFI_OUT_OF_RESOURCES;\r
221   }\r
222 \r
223   EbcProtocol->CreateThunk          = EbcCreateThunk;\r
224   EbcProtocol->UnloadImage          = EbcUnloadImage;\r
225   EbcProtocol->RegisterICacheFlush  = EbcRegisterICacheFlush;\r
226   EbcProtocol->GetVersion           = EbcGetVersion;\r
227   mEbcICacheFlush                   = NULL;\r
228 \r
229   //\r
230   // Find any already-installed EBC protocols and uninstall them\r
231   //\r
232   Installed     = FALSE;\r
233   HandleBuffer  = NULL;\r
234   Status = gBS->LocateHandleBuffer (\r
235                   ByProtocol,\r
236                   &gEfiEbcProtocolGuid,\r
237                   NULL,\r
238                   &NumHandles,\r
239                   &HandleBuffer\r
240                   );\r
241   if (Status == EFI_SUCCESS) {\r
242     //\r
243     // Loop through the handles\r
244     //\r
245     for (Index = 0; Index < NumHandles; Index++) {\r
246       Status = gBS->HandleProtocol (\r
247                       HandleBuffer[Index],\r
248                       &gEfiEbcProtocolGuid,\r
249                       (VOID **) &OldEbcProtocol\r
250                       );\r
251       if (Status == EFI_SUCCESS) {\r
252         if (gBS->ReinstallProtocolInterface (\r
253                   HandleBuffer[Index],\r
254                   &gEfiEbcProtocolGuid,\r
255                   OldEbcProtocol,\r
256                   EbcProtocol\r
257                   ) == EFI_SUCCESS) {\r
258           Installed = TRUE;\r
259         }\r
260       }\r
261     }\r
262   }\r
263 \r
264   if (HandleBuffer != NULL) {\r
265     FreePool (HandleBuffer);\r
266     HandleBuffer = NULL;\r
267   }\r
268   //\r
269   // Add the protocol so someone can locate us if we haven't already.\r
270   //\r
271   if (!Installed) {\r
272     Status = gBS->InstallProtocolInterface (\r
273                     &ImageHandle,\r
274                     &gEfiEbcProtocolGuid,\r
275                     EFI_NATIVE_INTERFACE,\r
276                     EbcProtocol\r
277                     );\r
278     if (EFI_ERROR (Status)) {\r
279       FreePool (EbcProtocol);\r
280       return Status;\r
281     }\r
282   }\r
283 \r
284   Status = InitEBCStack();\r
285   if (EFI_ERROR(Status)) {\r
286     goto ErrorExit;\r
287   }\r
288 \r
289   //\r
290   // Allocate memory for our debug protocol. Then fill in the blanks.\r
291   //\r
292   EbcDebugProtocol = AllocatePool (sizeof (EFI_DEBUG_SUPPORT_PROTOCOL));\r
293 \r
294   if (EbcDebugProtocol == NULL) {\r
295     goto ErrorExit;\r
296   }\r
297 \r
298   EbcDebugProtocol->Isa                         = IsaEbc;\r
299   EbcDebugProtocol->GetMaximumProcessorIndex    = EbcDebugGetMaximumProcessorIndex;\r
300   EbcDebugProtocol->RegisterPeriodicCallback    = EbcDebugRegisterPeriodicCallback;\r
301   EbcDebugProtocol->RegisterExceptionCallback   = EbcDebugRegisterExceptionCallback;\r
302   EbcDebugProtocol->InvalidateInstructionCache  = EbcDebugInvalidateInstructionCache;\r
303 \r
304   //\r
305   // Add the protocol so the debug agent can find us\r
306   //\r
307   Status = gBS->InstallProtocolInterface (\r
308                   &ImageHandle,\r
309                   &gEfiDebugSupportProtocolGuid,\r
310                   EFI_NATIVE_INTERFACE,\r
311                   EbcDebugProtocol\r
312                   );\r
313   //\r
314   // This is recoverable, so free the memory and continue.\r
315   //\r
316   if (EFI_ERROR (Status)) {\r
317     FreePool (EbcDebugProtocol);\r
318     goto ErrorExit;\r
319   }\r
320   //\r
321   // Install EbcDebugSupport Protocol Successfully\r
322   // Now we need to initialize the Ebc default Callback\r
323   //\r
324   Status = InitializeEbcCallback (EbcDebugProtocol);\r
325 \r
326   //\r
327   // Produce a VM test interface protocol. Not required for execution.\r
328   //\r
329   DEBUG_CODE_BEGIN ();\r
330     InitEbcVmTestProtocol (&ImageHandle);\r
331   DEBUG_CODE_END ();\r
332 \r
333   return EFI_SUCCESS;\r
334 \r
335 ErrorExit:\r
336   FreeEBCStack();\r
337   HandleBuffer  = NULL;\r
338   Status = gBS->LocateHandleBuffer (\r
339                   ByProtocol,\r
340                   &gEfiEbcProtocolGuid,\r
341                   NULL,\r
342                   &NumHandles,\r
343                   &HandleBuffer\r
344                   );\r
345   if (Status == EFI_SUCCESS) {\r
346     //\r
347     // Loop through the handles\r
348     //\r
349     for (Index = 0; Index < NumHandles; Index++) {\r
350       Status = gBS->HandleProtocol (\r
351                       HandleBuffer[Index],\r
352                       &gEfiEbcProtocolGuid,\r
353                       (VOID **) &OldEbcProtocol\r
354                       );\r
355       if (Status == EFI_SUCCESS) {\r
356         gBS->UninstallProtocolInterface (\r
357                HandleBuffer[Index],\r
358                &gEfiEbcProtocolGuid,\r
359                OldEbcProtocol\r
360                );\r
361       }\r
362     }\r
363   }\r
364 \r
365   if (HandleBuffer != NULL) {\r
366     FreePool (HandleBuffer);\r
367     HandleBuffer = NULL;\r
368   }\r
369 \r
370   FreePool (EbcProtocol);\r
371 \r
372   return Status;\r
373 }\r
374 \r
375 \r
376 /**\r
377   This is the top-level routine plugged into the EBC protocol. Since thunks\r
378   are very processor-specific, from here we dispatch directly to the very\r
379   processor-specific routine EbcCreateThunks().\r
380 \r
381   @param  This                   protocol instance pointer\r
382   @param  ImageHandle            handle to the image. The EBC interpreter may use\r
383                                  this to keep track of any resource allocations\r
384                                  performed in loading and executing the image.\r
385   @param  EbcEntryPoint          the entry point for the image (as defined in the\r
386                                  file header)\r
387   @param  Thunk                  pointer to thunk pointer where the address of the\r
388                                  created thunk is returned.\r
389 \r
390   @return EFI_STATUS\r
391 \r
392 **/\r
393 STATIC\r
394 EFI_STATUS\r
395 EFIAPI\r
396 EbcCreateThunk (\r
397   IN EFI_EBC_PROTOCOL   *This,\r
398   IN EFI_HANDLE         ImageHandle,\r
399   IN VOID               *EbcEntryPoint,\r
400   OUT VOID              **Thunk\r
401   )\r
402 {\r
403   EFI_STATUS  Status;\r
404 \r
405   Status = EbcCreateThunks (\r
406             ImageHandle,\r
407             EbcEntryPoint,\r
408             Thunk,\r
409             FLAG_THUNK_ENTRY_POINT\r
410             );\r
411   return Status;\r
412 }\r
413 \r
414 \r
415 /**\r
416   This EBC debugger protocol service is called by the debug agent\r
417 \r
418   @param  This                   pointer to the caller's debug support protocol\r
419                                  interface\r
420   @param  MaxProcessorIndex      pointer to a caller allocated UINTN in which the\r
421                                  maximum processor index is returned.\r
422 \r
423   @return Standard EFI_STATUS\r
424 \r
425 **/\r
426 STATIC\r
427 EFI_STATUS\r
428 EFIAPI\r
429 EbcDebugGetMaximumProcessorIndex (\r
430   IN EFI_DEBUG_SUPPORT_PROTOCOL          *This,\r
431   OUT UINTN                              *MaxProcessorIndex\r
432   )\r
433 {\r
434   *MaxProcessorIndex = 0;\r
435   return EFI_SUCCESS;\r
436 }\r
437 \r
438 \r
439 /**\r
440   This protocol service is called by the debug agent to register a function\r
441   for us to call on a periodic basis.\r
442 \r
443   @param  This                   pointer to the caller's debug support protocol\r
444                                  interface\r
445   @param  PeriodicCallback       pointer to the function to call periodically\r
446 \r
447   @return Always EFI_SUCCESS\r
448 \r
449 **/\r
450 STATIC\r
451 EFI_STATUS\r
452 EFIAPI\r
453 EbcDebugRegisterPeriodicCallback (\r
454   IN EFI_DEBUG_SUPPORT_PROTOCOL  *This,\r
455   IN UINTN                       ProcessorIndex,\r
456   IN EFI_PERIODIC_CALLBACK       PeriodicCallback\r
457   )\r
458 {\r
459   if ((mDebugPeriodicCallback == NULL) && (PeriodicCallback == NULL)) {\r
460     return EFI_INVALID_PARAMETER;\r
461   }\r
462   if ((mDebugPeriodicCallback != NULL) && (PeriodicCallback != NULL)) {\r
463     return EFI_ALREADY_STARTED;\r
464   }\r
465 \r
466   mDebugPeriodicCallback = PeriodicCallback;\r
467   return EFI_SUCCESS;\r
468 }\r
469 \r
470 \r
471 /**\r
472   This protocol service is called by the debug agent to register a function\r
473   for us to call when we detect an exception.\r
474 \r
475   @param  This                   pointer to the caller's debug support protocol\r
476                                  interface\r
477   @param  ExceptionCallback      pointer to the function to the exception\r
478 \r
479   @return Always EFI_SUCCESS\r
480 \r
481 **/\r
482 STATIC\r
483 EFI_STATUS\r
484 EFIAPI\r
485 EbcDebugRegisterExceptionCallback (\r
486   IN EFI_DEBUG_SUPPORT_PROTOCOL  *This,\r
487   IN UINTN                       ProcessorIndex,\r
488   IN EFI_EXCEPTION_CALLBACK      ExceptionCallback,\r
489   IN EFI_EXCEPTION_TYPE          ExceptionType\r
490   )\r
491 {\r
492   if ((ExceptionType < 0) || (ExceptionType > MAX_EBC_EXCEPTION)) {\r
493     return EFI_INVALID_PARAMETER;\r
494   }\r
495   if ((mDebugExceptionCallback[ExceptionType] == NULL) && (ExceptionCallback == NULL)) {\r
496     return EFI_INVALID_PARAMETER;\r
497   }\r
498   if ((mDebugExceptionCallback[ExceptionType] != NULL) && (ExceptionCallback != NULL)) {\r
499     return EFI_ALREADY_STARTED;\r
500   }\r
501   mDebugExceptionCallback[ExceptionType] = ExceptionCallback;\r
502   return EFI_SUCCESS;\r
503 }\r
504 \r
505 \r
506 /**\r
507   This EBC debugger protocol service is called by the debug agent.  Required\r
508   for DebugSupport compliance but is only stubbed out for EBC.\r
509 \r
510 \r
511   @return EFI_SUCCESS\r
512 \r
513 **/\r
514 STATIC\r
515 EFI_STATUS\r
516 EFIAPI\r
517 EbcDebugInvalidateInstructionCache (\r
518   IN EFI_DEBUG_SUPPORT_PROTOCOL          *This,\r
519   IN UINTN                               ProcessorIndex,\r
520   IN VOID                                *Start,\r
521   IN UINT64                              Length\r
522   )\r
523 {\r
524   return EFI_SUCCESS;\r
525 }\r
526 \r
527 \r
528 /**\r
529   The VM interpreter calls this function when an exception is detected.\r
530 \r
531   @param  VmPtr                  pointer to a VM context for passing info to the\r
532                                  EFI debugger.\r
533 \r
534   @return EFI_SUCCESS if it returns at all\r
535 \r
536 **/\r
537 EFI_STATUS\r
538 EbcDebugSignalException (\r
539   IN EFI_EXCEPTION_TYPE                   ExceptionType,\r
540   IN EXCEPTION_FLAGS                      ExceptionFlags,\r
541   IN VM_CONTEXT                           *VmPtr\r
542   )\r
543 {\r
544   EFI_SYSTEM_CONTEXT_EBC  EbcContext;\r
545   EFI_SYSTEM_CONTEXT      SystemContext;\r
546 \r
547   ASSERT ((ExceptionType >= 0) && (ExceptionType <= MAX_EBC_EXCEPTION));\r
548   //\r
549   // Save the exception in the context passed in\r
550   //\r
551   VmPtr->ExceptionFlags |= ExceptionFlags;\r
552   VmPtr->LastException = ExceptionType;\r
553   //\r
554   // If it's a fatal exception, then flag it in the VM context in case an\r
555   // attached debugger tries to return from it.\r
556   //\r
557   if (ExceptionFlags & EXCEPTION_FLAG_FATAL) {\r
558     VmPtr->StopFlags |= STOPFLAG_APP_DONE;\r
559   }\r
560 \r
561   //\r
562   // If someone's registered for exception callbacks, then call them.\r
563   //\r
564   // EBC driver will register default exception callback to report the\r
565   // status code via the status code API\r
566   //\r
567   if (mDebugExceptionCallback[ExceptionType] != NULL) {\r
568 \r
569     //\r
570     // Initialize the context structure\r
571     //\r
572     EbcContext.R0                   = VmPtr->R[0];\r
573     EbcContext.R1                   = VmPtr->R[1];\r
574     EbcContext.R2                   = VmPtr->R[2];\r
575     EbcContext.R3                   = VmPtr->R[3];\r
576     EbcContext.R4                   = VmPtr->R[4];\r
577     EbcContext.R5                   = VmPtr->R[5];\r
578     EbcContext.R6                   = VmPtr->R[6];\r
579     EbcContext.R7                   = VmPtr->R[7];\r
580     EbcContext.Ip                   = (UINT64)(UINTN)VmPtr->Ip;\r
581     EbcContext.Flags                = VmPtr->Flags;\r
582     EbcContext.ControlFlags         = 0;\r
583     SystemContext.SystemContextEbc  = &EbcContext;\r
584 \r
585     mDebugExceptionCallback[ExceptionType] (ExceptionType, SystemContext);\r
586     //\r
587     // Restore the context structure and continue to execute\r
588     //\r
589     VmPtr->R[0]  = EbcContext.R0;\r
590     VmPtr->R[1]  = EbcContext.R1;\r
591     VmPtr->R[2]  = EbcContext.R2;\r
592     VmPtr->R[3]  = EbcContext.R3;\r
593     VmPtr->R[4]  = EbcContext.R4;\r
594     VmPtr->R[5]  = EbcContext.R5;\r
595     VmPtr->R[6]  = EbcContext.R6;\r
596     VmPtr->R[7]  = EbcContext.R7;\r
597     VmPtr->Ip    = (VMIP)(UINTN)EbcContext.Ip;\r
598     VmPtr->Flags = EbcContext.Flags;\r
599   }\r
600 \r
601   return EFI_SUCCESS;\r
602 }\r
603 \r
604 \r
605 /**\r
606   To install default Callback function for the VM interpreter.\r
607 \r
608   @param  This                   pointer to the instance of DebugSupport protocol\r
609 \r
610   @return None\r
611 \r
612 **/\r
613 STATIC\r
614 EFI_STATUS\r
615 InitializeEbcCallback (\r
616   IN EFI_DEBUG_SUPPORT_PROTOCOL  *This\r
617   )\r
618 {\r
619   INTN       Index;\r
620   EFI_STATUS Status;\r
621 \r
622   //\r
623   // For ExceptionCallback\r
624   //\r
625   for (Index = 0; Index <= MAX_EBC_EXCEPTION; Index++) {\r
626     EbcDebugRegisterExceptionCallback (\r
627       This,\r
628       0,\r
629       CommonEbcExceptionHandler,\r
630       Index\r
631       );\r
632   }\r
633 \r
634   //\r
635   // For PeriodicCallback\r
636   //\r
637   Status = gBS->CreateEvent (\r
638                   EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
639                   TPL_NOTIFY,\r
640                   EbcPeriodicNotifyFunction,\r
641                   &mVmPtr,\r
642                   &mEbcPeriodicEvent\r
643                   );\r
644   if (EFI_ERROR(Status)) {\r
645     return Status;\r
646   }\r
647 \r
648   Status = gBS->SetTimer (\r
649                   mEbcPeriodicEvent,\r
650                   TimerPeriodic,\r
651                   EBC_VM_PERIODIC_CALLBACK_RATE\r
652                   );\r
653   if (EFI_ERROR(Status)) {\r
654     return Status;\r
655   }\r
656 \r
657   return EFI_SUCCESS;\r
658 }\r
659 \r
660 \r
661 /**\r
662   The default Exception Callback for the VM interpreter.\r
663   In this function, we report status code, and print debug information\r
664   about EBC_CONTEXT, then dead loop.\r
665 \r
666   @param  InterruptType          Interrupt type.\r
667   @param  SystemContext          EBC system context.\r
668 \r
669   @return None\r
670 \r
671 **/\r
672 STATIC\r
673 VOID\r
674 CommonEbcExceptionHandler (\r
675   IN EFI_EXCEPTION_TYPE   InterruptType,\r
676   IN EFI_SYSTEM_CONTEXT   SystemContext\r
677   )\r
678 {\r
679   //\r
680   // We deadloop here to make it easy to debug this issue.\r
681   //\r
682   ASSERT (FALSE);\r
683 \r
684   return ;\r
685 }\r
686 \r
687 \r
688 /**\r
689   The periodic callback function for EBC VM interpreter, which is used\r
690   to support the EFI debug support protocol.\r
691 \r
692   @param  Event                  The Periodic Callback Event.\r
693   @param  Context                It should be the address of VM_CONTEXT pointer.\r
694 \r
695   @return None.\r
696 \r
697 **/\r
698 STATIC\r
699 VOID\r
700 EFIAPI\r
701 EbcPeriodicNotifyFunction (\r
702   IN EFI_EVENT     Event,\r
703   IN VOID          *Context\r
704   )\r
705 {\r
706   VM_CONTEXT *VmPtr;\r
707 \r
708   VmPtr = *(VM_CONTEXT **)Context;\r
709 \r
710   if (VmPtr != NULL) {\r
711     EbcDebugPeriodic (VmPtr);\r
712   }\r
713 \r
714   return ;\r
715 }\r
716 \r
717 \r
718 /**\r
719   The VM interpreter calls this function on a periodic basis to support\r
720   the EFI debug support protocol.\r
721 \r
722   @param  VmPtr                  pointer to a VM context for passing info to the\r
723                                  debugger.\r
724 \r
725   @return Standard EFI status.\r
726 \r
727 **/\r
728 STATIC\r
729 EFI_STATUS\r
730 EbcDebugPeriodic (\r
731   IN VM_CONTEXT *VmPtr\r
732   )\r
733 {\r
734   EFI_SYSTEM_CONTEXT_EBC   EbcContext;\r
735   EFI_SYSTEM_CONTEXT       SystemContext;\r
736 \r
737   //\r
738   // If someone's registered for periodic callbacks, then call them.\r
739   //\r
740   if (mDebugPeriodicCallback != NULL) {\r
741 \r
742     //\r
743     // Initialize the context structure\r
744     //\r
745     EbcContext.R0                   = VmPtr->R[0];\r
746     EbcContext.R1                   = VmPtr->R[1];\r
747     EbcContext.R2                   = VmPtr->R[2];\r
748     EbcContext.R3                   = VmPtr->R[3];\r
749     EbcContext.R4                   = VmPtr->R[4];\r
750     EbcContext.R5                   = VmPtr->R[5];\r
751     EbcContext.R6                   = VmPtr->R[6];\r
752     EbcContext.R7                   = VmPtr->R[7];\r
753     EbcContext.Ip                   = (UINT64)(UINTN)VmPtr->Ip;\r
754     EbcContext.Flags                = VmPtr->Flags;\r
755     EbcContext.ControlFlags         = 0;\r
756     SystemContext.SystemContextEbc  = &EbcContext;\r
757 \r
758     mDebugPeriodicCallback (SystemContext);\r
759 \r
760     //\r
761     // Restore the context structure and continue to execute\r
762     //\r
763     VmPtr->R[0]  = EbcContext.R0;\r
764     VmPtr->R[1]  = EbcContext.R1;\r
765     VmPtr->R[2]  = EbcContext.R2;\r
766     VmPtr->R[3]  = EbcContext.R3;\r
767     VmPtr->R[4]  = EbcContext.R4;\r
768     VmPtr->R[5]  = EbcContext.R5;\r
769     VmPtr->R[6]  = EbcContext.R6;\r
770     VmPtr->R[7]  = EbcContext.R7;\r
771     VmPtr->Ip    = (VMIP)(UINTN)EbcContext.Ip;\r
772     VmPtr->Flags = EbcContext.Flags;\r
773   }\r
774 \r
775   return EFI_SUCCESS;\r
776 }\r
777 \r
778 \r
779 /**\r
780   This routine is called by the core when an image is being unloaded from\r
781   memory. Basically we now have the opportunity to do any necessary cleanup.\r
782   Typically this will include freeing any memory allocated for thunk-creation.\r
783 \r
784   @param  This                   protocol instance pointer\r
785   @param  ImageHandle            handle to the image being unloaded.\r
786 \r
787   @retval EFI_INVALID_PARAMETER  the ImageHandle passed in was not found in the\r
788                                  internal list of EBC image handles.\r
789   @retval EFI_STATUS             completed successfully\r
790 \r
791 **/\r
792 STATIC\r
793 EFI_STATUS\r
794 EFIAPI\r
795 EbcUnloadImage (\r
796   IN EFI_EBC_PROTOCOL   *This,\r
797   IN EFI_HANDLE         ImageHandle\r
798   )\r
799 {\r
800   EBC_THUNK_LIST  *ThunkList;\r
801   EBC_THUNK_LIST  *NextThunkList;\r
802   EBC_IMAGE_LIST  *ImageList;\r
803   EBC_IMAGE_LIST  *PrevImageList;\r
804   //\r
805   // First go through our list of known image handles and see if we've already\r
806   // created an image list element for this image handle.\r
807   //\r
808   ReturnEBCStackByHandle(ImageHandle);\r
809   PrevImageList = NULL;\r
810   for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {\r
811     if (ImageList->ImageHandle == ImageHandle) {\r
812       break;\r
813     }\r
814     //\r
815     // Save the previous so we can connect the lists when we remove this one\r
816     //\r
817     PrevImageList = ImageList;\r
818   }\r
819 \r
820   if (ImageList == NULL) {\r
821     return EFI_INVALID_PARAMETER;\r
822   }\r
823   //\r
824   // Free up all the thunk buffers and thunks list elements for this image\r
825   // handle.\r
826   //\r
827   ThunkList = ImageList->ThunkList;\r
828   while (ThunkList != NULL) {\r
829     NextThunkList = ThunkList->Next;\r
830     FreePool (ThunkList->ThunkBuffer);\r
831     FreePool (ThunkList);\r
832     ThunkList = NextThunkList;\r
833   }\r
834   //\r
835   // Now remove this image list element from the chain\r
836   //\r
837   if (PrevImageList == NULL) {\r
838     //\r
839     // Remove from head\r
840     //\r
841     mEbcImageList = ImageList->Next;\r
842   } else {\r
843     PrevImageList->Next = ImageList->Next;\r
844   }\r
845   //\r
846   // Now free up the image list element\r
847   //\r
848   FreePool (ImageList);\r
849   return EFI_SUCCESS;\r
850 }\r
851 \r
852 \r
853 /**\r
854   Add a thunk to our list of thunks for a given image handle.\r
855   Also flush the instruction cache since we've written thunk code\r
856   to memory that will be executed eventually.\r
857 \r
858   @param  ImageHandle            the image handle to which the thunk is tied\r
859   @param  ThunkBuffer            the buffer we've created/allocated\r
860   @param  ThunkSize              the size of the thunk memory allocated\r
861 \r
862   @retval EFI_OUT_OF_RESOURCES   memory allocation failed\r
863   @retval EFI_SUCCESS            successful completion\r
864 \r
865 **/\r
866 EFI_STATUS\r
867 EbcAddImageThunk (\r
868   IN EFI_HANDLE      ImageHandle,\r
869   IN VOID            *ThunkBuffer,\r
870   IN UINT32          ThunkSize\r
871   )\r
872 {\r
873   EBC_THUNK_LIST  *ThunkList;\r
874   EBC_IMAGE_LIST  *ImageList;\r
875   EFI_STATUS      Status;\r
876 \r
877   //\r
878   // It so far so good, then flush the instruction cache\r
879   //\r
880   if (mEbcICacheFlush != NULL) {\r
881     Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS) (UINTN) ThunkBuffer, ThunkSize);\r
882     if (EFI_ERROR (Status)) {\r
883       return Status;\r
884     }\r
885   }\r
886   //\r
887   // Go through our list of known image handles and see if we've already\r
888   // created a image list element for this image handle.\r
889   //\r
890   for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {\r
891     if (ImageList->ImageHandle == ImageHandle) {\r
892       break;\r
893     }\r
894   }\r
895 \r
896   if (ImageList == NULL) {\r
897     //\r
898     // Allocate a new one\r
899     //\r
900     ImageList = AllocatePool (sizeof (EBC_IMAGE_LIST));\r
901 \r
902     if (ImageList == NULL) {\r
903       return EFI_OUT_OF_RESOURCES;\r
904     }\r
905 \r
906     ImageList->ThunkList    = NULL;\r
907     ImageList->ImageHandle  = ImageHandle;\r
908     ImageList->Next         = mEbcImageList;\r
909     mEbcImageList           = ImageList;\r
910   }\r
911   //\r
912   // Ok, now create a new thunk element to add to the list\r
913   //\r
914   ThunkList = AllocatePool (sizeof (EBC_THUNK_LIST));\r
915 \r
916   if (ThunkList == NULL) {\r
917     return EFI_OUT_OF_RESOURCES;\r
918   }\r
919   //\r
920   // Add it to the head of the list\r
921   //\r
922   ThunkList->Next         = ImageList->ThunkList;\r
923   ThunkList->ThunkBuffer  = ThunkBuffer;\r
924   ImageList->ThunkList    = ThunkList;\r
925   return EFI_SUCCESS;\r
926 }\r
927 \r
928 STATIC\r
929 EFI_STATUS\r
930 EFIAPI\r
931 EbcRegisterICacheFlush (\r
932   IN EFI_EBC_PROTOCOL   *This,\r
933   IN EBC_ICACHE_FLUSH   Flush\r
934   )\r
935 {\r
936   mEbcICacheFlush = Flush;\r
937   return EFI_SUCCESS;\r
938 }\r
939 \r
940 STATIC\r
941 EFI_STATUS\r
942 EFIAPI\r
943 EbcGetVersion (\r
944   IN EFI_EBC_PROTOCOL   *This,\r
945   IN OUT UINT64         *Version\r
946   )\r
947 {\r
948   if (Version == NULL) {\r
949     return EFI_INVALID_PARAMETER;\r
950   }\r
951 \r
952   *Version = GetVmVersion ();\r
953   return EFI_SUCCESS;\r
954 }\r
955 \r
956 EFI_STATUS\r
957 GetEBCStack(\r
958   EFI_HANDLE Handle,\r
959   VOID       **StackBuffer,\r
960   UINTN      *BufferIndex\r
961   )\r
962 {\r
963   UINTN   Index;\r
964   EFI_TPL OldTpl;\r
965   OldTpl = gBS->RaiseTPL(TPL_HIGH_LEVEL);\r
966   for (Index = 0; Index < mStackNum; Index ++) {\r
967     if (mStackBufferIndex[Index] == NULL) {\r
968       mStackBufferIndex[Index] = Handle;\r
969       break;\r
970     }\r
971   }\r
972   gBS->RestoreTPL(OldTpl);\r
973   if (Index == mStackNum) {\r
974     return EFI_OUT_OF_RESOURCES;\r
975   }\r
976   *BufferIndex = Index;\r
977   *StackBuffer = mStackBuffer[Index];\r
978   return EFI_SUCCESS;\r
979 }\r
980 \r
981 EFI_STATUS\r
982 ReturnEBCStack(\r
983   UINTN Index\r
984   )\r
985 {\r
986   mStackBufferIndex[Index] =NULL;\r
987   return EFI_SUCCESS;\r
988 }\r
989 \r
990 EFI_STATUS\r
991 ReturnEBCStackByHandle(\r
992   EFI_HANDLE Handle\r
993   )\r
994 {\r
995   UINTN Index;\r
996   for (Index = 0; Index < mStackNum; Index ++) {\r
997     if (mStackBufferIndex[Index] == Handle) {\r
998       break;\r
999     }\r
1000   }\r
1001   if (Index == mStackNum) {\r
1002     return EFI_NOT_FOUND;\r
1003   }\r
1004   mStackBufferIndex[Index] = NULL;\r
1005   return EFI_SUCCESS;\r
1006 }\r
1007 \r
1008 EFI_STATUS\r
1009 InitEBCStack (\r
1010   VOID\r
1011   )\r
1012 {\r
1013   for (mStackNum = 0; mStackNum < MAX_STACK_NUM; mStackNum ++) {\r
1014     mStackBuffer[mStackNum] = AllocatePool(STACK_POOL_SIZE);\r
1015     mStackBufferIndex[mStackNum] = NULL;\r
1016     if (mStackBuffer[mStackNum] == NULL) {\r
1017       break;\r
1018     }\r
1019   }\r
1020   if (mStackNum == 0) {\r
1021     return EFI_OUT_OF_RESOURCES;\r
1022   }\r
1023   return EFI_SUCCESS;\r
1024 }\r
1025 \r
1026 EFI_STATUS\r
1027 FreeEBCStack(\r
1028   VOID\r
1029   )\r
1030 {\r
1031   UINTN Index;\r
1032   for (Index = 0; Index < mStackNum; Index ++) {\r
1033     FreePool(mStackBuffer[Index]);\r
1034   }\r
1035   return EFI_SUCCESS;\r
1036 }\r
1037 \r
1038 /**\r
1039   Produce an EBC VM test protocol that can be used for regression tests.\r
1040 \r
1041   @param  IHandle                handle on which to install the protocol.\r
1042 \r
1043   @retval EFI_OUT_OF_RESOURCES   memory allocation failed\r
1044   @retval EFI_SUCCESS            successful completion\r
1045 \r
1046 **/\r
1047 STATIC\r
1048 EFI_STATUS\r
1049 InitEbcVmTestProtocol (\r
1050   IN EFI_HANDLE     *IHandle\r
1051   )\r
1052 {\r
1053   EFI_HANDLE Handle;\r
1054   EFI_STATUS Status;\r
1055   EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;\r
1056 \r
1057   //\r
1058   // Allocate memory for the protocol, then fill in the fields\r
1059   //\r
1060   EbcVmTestProtocol = AllocatePool (sizeof (EFI_EBC_VM_TEST_PROTOCOL));\r
1061   if (EbcVmTestProtocol == NULL) {\r
1062     return EFI_OUT_OF_RESOURCES;\r
1063   }\r
1064   EbcVmTestProtocol->Execute      = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;\r
1065 \r
1066   DEBUG_CODE_BEGIN ();\r
1067     EbcVmTestProtocol->Assemble     = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;\r
1068     EbcVmTestProtocol->Disassemble  = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;\r
1069   DEBUG_CODE_END ();\r
1070 \r
1071   //\r
1072   // Publish the protocol\r
1073   //\r
1074   Handle  = NULL;\r
1075   Status  = gBS->InstallProtocolInterface (&Handle, &mEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);\r
1076   if (EFI_ERROR (Status)) {\r
1077     FreePool (EbcVmTestProtocol);\r
1078   }\r
1079   return Status;\r
1080 }\r
1081 STATIC\r
1082 EFI_STATUS\r
1083 EbcVmTestUnsupported ()\r
1084 {\r
1085   return EFI_UNSUPPORTED;\r
1086 }\r
1087 \r