]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Ebc/Dxe/EbcInt.c
Add MonotonicCounter driver, which produces MonotonicCounter arch protocols
[mirror_edk2.git] / MdeModulePkg / Universal / Ebc / Dxe / EbcInt.c
CommitLineData
d7dec593 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 EbcInt.c\r
15\r
16Abstract:\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
33typedef struct _EBC_THUNK_LIST {\r
34 VOID *ThunkBuffer;\r
35 struct _EBC_THUNK_LIST *Next;\r
36} EBC_THUNK_LIST;\r
37\r
38typedef 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
44STATIC\r
45EFI_STATUS\r
46EFIAPI\r
47EbcUnloadImage (\r
48 IN EFI_EBC_PROTOCOL *This,\r
49 IN EFI_HANDLE ImageHandle\r
50 );\r
51\r
52STATIC\r
53EFI_STATUS\r
54EFIAPI\r
55EbcCreateThunk (\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
62STATIC\r
63EFI_STATUS\r
64EFIAPI\r
65EbcGetVersion (\r
66 IN EFI_EBC_PROTOCOL *This,\r
67 IN OUT UINT64 *Version\r
68 );\r
69\r
70STATIC\r
71EFI_STATUS\r
72EFIAPI\r
73InitializeEbcCallback (\r
74 IN EFI_DEBUG_SUPPORT_PROTOCOL *This\r
75 );\r
76\r
77STATIC\r
78VOID\r
79EFIAPI\r
80CommonEbcExceptionHandler (\r
81 IN EFI_EXCEPTION_TYPE InterruptType,\r
82 IN EFI_SYSTEM_CONTEXT SystemContext\r
83 );\r
84\r
85STATIC\r
86VOID\r
87EFIAPI\r
88EbcPeriodicNotifyFunction (\r
89 IN EFI_EVENT Event,\r
90 IN VOID *Context\r
91 );\r
92\r
93STATIC\r
94EFI_STATUS\r
95EFIAPI\r
96EbcDebugPeriodic (\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
104STATIC\r
105EFI_STATUS\r
106InitEbcVmTestProtocol (\r
107 IN EFI_HANDLE *Handle\r
108 );\r
109\r
110STATIC\r
111EFI_STATUS\r
112EbcVmTestUnsupported (\r
113 VOID\r
114 );\r
115\r
116STATIC\r
117EFI_STATUS\r
118EFIAPI\r
119EbcRegisterICacheFlush (\r
120 IN EFI_EBC_PROTOCOL *This,\r
121 IN EBC_ICACHE_FLUSH Flush\r
122 );\r
123\r
124STATIC\r
125EFI_STATUS\r
126EFIAPI\r
127EbcDebugGetMaximumProcessorIndex (\r
128 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
129 OUT UINTN *MaxProcessorIndex\r
130 );\r
131\r
132STATIC\r
133EFI_STATUS\r
134EFIAPI\r
135EbcDebugRegisterPeriodicCallback (\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
141STATIC\r
142EFI_STATUS\r
143EFIAPI\r
144EbcDebugRegisterExceptionCallback (\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
151STATIC\r
152EFI_STATUS\r
153EFIAPI\r
154EbcDebugInvalidateInstructionCache (\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
167static EBC_IMAGE_LIST *mEbcImageList = NULL;\r
168\r
169//\r
170// Callback function to flush the icache after thunk creation\r
171//\r
172static EBC_ICACHE_FLUSH mEbcICacheFlush;\r
173\r
174//\r
175// These get set via calls by the debug agent\r
176//\r
177static EFI_PERIODIC_CALLBACK mDebugPeriodicCallback = NULL;\r
178static EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = {NULL};\r
179static EFI_GUID mEfiEbcVmTestProtocolGuid = EFI_EBC_VM_TEST_PROTOCOL_GUID;\r
180\r
181static VOID* mStackBuffer[MAX_STACK_NUM];\r
182static EFI_HANDLE mStackBufferIndex[MAX_STACK_NUM];\r
183static UINTN mStackNum = 0;\r
184\r
185//\r
186// Event for Periodic callback\r
187//\r
188static EFI_EVENT mEbcPeriodicEvent;\r
189VM_CONTEXT *mVmPtr = NULL;\r
190\r
191EFI_STATUS\r
192EFIAPI\r
193InitializeEbcDriver (\r
194 IN EFI_HANDLE ImageHandle,\r
195 IN EFI_SYSTEM_TABLE *SystemTable\r
196 )\r
197/*++\r
198\r
199Routine 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
204Arguments:\r
205\r
206 ImageHandle - EFI image handle.\r
207 SystemTable - Pointer to the EFI system table.\r
208\r
209Returns:\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
347ErrorExit:\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
387STATIC\r
388EFI_STATUS\r
389EFIAPI\r
390EbcCreateThunk (\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
398Routine 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
404Arguments:\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
414Returns:\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
431STATIC\r
432EFI_STATUS\r
433EFIAPI\r
434EbcDebugGetMaximumProcessorIndex (\r
435 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
436 OUT UINTN *MaxProcessorIndex\r
437 )\r
438/*++\r
439\r
440Routine Description:\r
441\r
442 This EBC debugger protocol service is called by the debug agent\r
443\r
444Arguments:\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
450Returns:\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
460STATIC\r
461EFI_STATUS\r
462EFIAPI\r
463EbcDebugRegisterPeriodicCallback (\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
470Routine 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
476Arguments:\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
481Returns:\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
498STATIC\r
499EFI_STATUS\r
500EFIAPI\r
501EbcDebugRegisterExceptionCallback (\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
509Routine 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
515Arguments:\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
520Returns:\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
539STATIC\r
540EFI_STATUS\r
541EFIAPI\r
542EbcDebugInvalidateInstructionCache (\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
550Routine 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
555Arguments:\r
556\r
557Returns:\r
558\r
559 EFI_SUCCESS\r
560\r
561--*/\r
562{\r
563 return EFI_SUCCESS;\r
564}\r
565\r
566EFI_STATUS\r
567EbcDebugSignalException (\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
574Routine Description:\r
575\r
576 The VM interpreter calls this function when an exception is detected.\r
577\r
578Arguments:\r
579\r
580 VmPtr - pointer to a VM context for passing info to the EFI debugger.\r
581\r
582Returns:\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
648STATIC\r
649EFI_STATUS\r
650InitializeEbcCallback (\r
651 IN EFI_DEBUG_SUPPORT_PROTOCOL *This\r
652 )\r
653/*++\r
654\r
655Routine Description:\r
656\r
657 To install default Callback function for the VM interpreter.\r
658\r
659Arguments:\r
660\r
661 This - pointer to the instance of DebugSupport protocol\r
662\r
663Returns:\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
710STATIC\r
711VOID\r
712CommonEbcExceptionHandler (\r
713 IN EFI_EXCEPTION_TYPE InterruptType,\r
714 IN EFI_SYSTEM_CONTEXT SystemContext\r
715 )\r
716/*++\r
717\r
718Routine 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
724Arguments:\r
725\r
726 InterruptType - Interrupt type.\r
727 SystemContext - EBC system context.\r
728\r
729Returns:\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
743STATIC\r
744VOID\r
745EFIAPI\r
746EbcPeriodicNotifyFunction (\r
747 IN EFI_EVENT Event,\r
748 IN VOID *Context\r
749 )\r
750/*++\r
751\r
752Routine 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
757Arguments:\r
758\r
759 Event - The Periodic Callback Event.\r
760 Context - It should be the address of VM_CONTEXT pointer.\r
761\r
762Returns:\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
779STATIC\r
780EFI_STATUS\r
781EbcDebugPeriodic (\r
782 IN VM_CONTEXT *VmPtr\r
783 )\r
784/*++\r
785\r
786Routine 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
791Arguments:\r
792\r
793 VmPtr - pointer to a VM context for passing info to the debugger.\r
794\r
795Returns:\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
845STATIC\r
846EFI_STATUS\r
847EFIAPI\r
848EbcUnloadImage (\r
849 IN EFI_EBC_PROTOCOL *This,\r
850 IN EFI_HANDLE ImageHandle\r
851 )\r
852/*++\r
853\r
854Routine 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
860Arguments:\r
861\r
862 This - protocol instance pointer\r
863 ImageHandle - handle to the image being unloaded.\r
864\r
865Returns:\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
925EFI_STATUS\r
926EbcAddImageThunk (\r
927 IN EFI_HANDLE ImageHandle,\r
928 IN VOID *ThunkBuffer,\r
929 IN UINT32 ThunkSize\r
930 )\r
931/*++\r
932\r
933Routine 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
939Arguments:\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
945Returns:\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
1007STATIC\r
1008EFI_STATUS\r
1009EFIAPI\r
1010EbcRegisterICacheFlush (\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
1019STATIC\r
1020EFI_STATUS\r
1021EFIAPI\r
1022EbcGetVersion (\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
1035EFI_STATUS\r
1036GetEBCStack(\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
1060EFI_STATUS\r
1061ReturnEBCStack(\r
1062 UINTN Index\r
1063 )\r
1064{\r
1065 mStackBufferIndex[Index] =NULL;\r
1066 return EFI_SUCCESS;\r
1067}\r
1068\r
1069EFI_STATUS\r
1070ReturnEBCStackByHandle(\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
1087EFI_STATUS\r
1088InitEBCStack (\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
1105EFI_STATUS\r
1106FreeEBCStack(\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
1116STATIC\r
1117EFI_STATUS\r
1118InitEbcVmTestProtocol (\r
1119 IN EFI_HANDLE *IHandle\r
1120 )\r
1121/*++\r
1122\r
1123Routine Description:\r
1124\r
1125 Produce an EBC VM test protocol that can be used for regression tests.\r
1126\r
1127Arguments:\r
1128\r
1129 IHandle - handle on which to install the protocol.\r
1130\r
1131Returns:\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
1166STATIC\r
1167EFI_STATUS\r
1168EbcVmTestUnsupported ()\r
1169{\r
1170 return EFI_UNSUPPORTED;\r
1171}\r
1172\r