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