]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/EbcDxe/EbcInt.c
apply for doxgen format.
[mirror_edk2.git] / MdeModulePkg / Universal / EbcDxe / EbcInt.c
CommitLineData
fb0b259e 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
53c71d09 5\r
6Copyright (c) 2006, Intel Corporation\r
7All rights reserved. This program and the accompanying materials\r
8are licensed and made available under the terms and conditions of the BSD License\r
9which accompanies this distribution. The full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
fb0b259e 15**/\r
53c71d09 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
26typedef struct _EBC_THUNK_LIST {\r
27 VOID *ThunkBuffer;\r
28 struct _EBC_THUNK_LIST *Next;\r
29} EBC_THUNK_LIST;\r
30\r
31typedef 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
37STATIC\r
38EFI_STATUS\r
39EFIAPI\r
40EbcUnloadImage (\r
41 IN EFI_EBC_PROTOCOL *This,\r
42 IN EFI_HANDLE ImageHandle\r
43 );\r
44\r
45STATIC\r
46EFI_STATUS\r
47EFIAPI\r
48EbcCreateThunk (\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
55STATIC\r
56EFI_STATUS\r
57EFIAPI\r
58EbcGetVersion (\r
59 IN EFI_EBC_PROTOCOL *This,\r
60 IN OUT UINT64 *Version\r
61 );\r
62\r
63STATIC\r
64EFI_STATUS\r
65EFIAPI\r
66InitializeEbcCallback (\r
67 IN EFI_DEBUG_SUPPORT_PROTOCOL *This\r
68 );\r
69\r
70STATIC\r
71VOID\r
72EFIAPI\r
73CommonEbcExceptionHandler (\r
74 IN EFI_EXCEPTION_TYPE InterruptType,\r
75 IN EFI_SYSTEM_CONTEXT SystemContext\r
76 );\r
77\r
78STATIC\r
79VOID\r
80EFIAPI\r
81EbcPeriodicNotifyFunction (\r
82 IN EFI_EVENT Event,\r
83 IN VOID *Context\r
84 );\r
85\r
86STATIC\r
87EFI_STATUS\r
88EFIAPI\r
89EbcDebugPeriodic (\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
97STATIC\r
98EFI_STATUS\r
99InitEbcVmTestProtocol (\r
100 IN EFI_HANDLE *Handle\r
101 );\r
102\r
103STATIC\r
104EFI_STATUS\r
105EbcVmTestUnsupported (\r
106 VOID\r
107 );\r
108\r
109STATIC\r
110EFI_STATUS\r
111EFIAPI\r
112EbcRegisterICacheFlush (\r
113 IN EFI_EBC_PROTOCOL *This,\r
114 IN EBC_ICACHE_FLUSH Flush\r
115 );\r
116\r
117STATIC\r
118EFI_STATUS\r
119EFIAPI\r
120EbcDebugGetMaximumProcessorIndex (\r
121 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
122 OUT UINTN *MaxProcessorIndex\r
123 );\r
124\r
125STATIC\r
126EFI_STATUS\r
127EFIAPI\r
128EbcDebugRegisterPeriodicCallback (\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
134STATIC\r
135EFI_STATUS\r
136EFIAPI\r
137EbcDebugRegisterExceptionCallback (\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
144STATIC\r
145EFI_STATUS\r
146EFIAPI\r
147EbcDebugInvalidateInstructionCache (\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
160static EBC_IMAGE_LIST *mEbcImageList = NULL;\r
161\r
162//\r
163// Callback function to flush the icache after thunk creation\r
164//\r
165static EBC_ICACHE_FLUSH mEbcICacheFlush;\r
166\r
167//\r
168// These get set via calls by the debug agent\r
169//\r
170static EFI_PERIODIC_CALLBACK mDebugPeriodicCallback = NULL;\r
171static EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = {NULL};\r
172static EFI_GUID mEfiEbcVmTestProtocolGuid = EFI_EBC_VM_TEST_PROTOCOL_GUID;\r
173\r
174static VOID* mStackBuffer[MAX_STACK_NUM];\r
175static EFI_HANDLE mStackBufferIndex[MAX_STACK_NUM];\r
176static UINTN mStackNum = 0;\r
177\r
178//\r
179// Event for Periodic callback\r
180//\r
181static EFI_EVENT mEbcPeriodicEvent;\r
182VM_CONTEXT *mVmPtr = NULL;\r
183\r
53c71d09 184\r
fb0b259e 185/**\r
53c71d09 186 Initializes the VM EFI interface. Allocates memory for the VM interface\r
187 and registers the VM protocol.\r
188\r
fb0b259e 189 @param ImageHandle EFI image handle.\r
190 @param SystemTable Pointer to the EFI system table.\r
53c71d09 191\r
fb0b259e 192 @return Standard EFI status code.\r
53c71d09 193\r
fb0b259e 194**/\r
195EFI_STATUS\r
196EFIAPI\r
197InitializeEbcDriver (\r
198 IN EFI_HANDLE ImageHandle,\r
199 IN EFI_SYSTEM_TABLE *SystemTable\r
200 )\r
53c71d09 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
335ErrorExit:\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
fb0b259e 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
53c71d09 393STATIC\r
394EFI_STATUS\r
395EFIAPI\r
396EbcCreateThunk (\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
53c71d09 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
fb0b259e 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
53c71d09 426STATIC\r
427EFI_STATUS\r
428EFIAPI\r
429EbcDebugGetMaximumProcessorIndex (\r
430 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
431 OUT UINTN *MaxProcessorIndex\r
432 )\r
53c71d09 433{\r
434 *MaxProcessorIndex = 0;\r
435 return EFI_SUCCESS;\r
436}\r
437\r
fb0b259e 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
53c71d09 450STATIC\r
451EFI_STATUS\r
452EFIAPI\r
453EbcDebugRegisterPeriodicCallback (\r
454 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
455 IN UINTN ProcessorIndex,\r
456 IN EFI_PERIODIC_CALLBACK PeriodicCallback\r
457 )\r
53c71d09 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
fb0b259e 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
53c71d09 482STATIC\r
483EFI_STATUS\r
484EFIAPI\r
485EbcDebugRegisterExceptionCallback (\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
53c71d09 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
fb0b259e 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
53c71d09 514STATIC\r
515EFI_STATUS\r
516EFIAPI\r
517EbcDebugInvalidateInstructionCache (\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
fb0b259e 523{\r
524 return EFI_SUCCESS;\r
525}\r
53c71d09 526\r
53c71d09 527\r
fb0b259e 528/**\r
529 The VM interpreter calls this function when an exception is detected.\r
53c71d09 530\r
fb0b259e 531 @param VmPtr pointer to a VM context for passing info to the\r
532 EFI debugger.\r
53c71d09 533\r
fb0b259e 534 @return EFI_SUCCESS if it returns at all\r
53c71d09 535\r
fb0b259e 536**/\r
53c71d09 537EFI_STATUS\r
538EbcDebugSignalException (\r
539 IN EFI_EXCEPTION_TYPE ExceptionType,\r
540 IN EXCEPTION_FLAGS ExceptionFlags,\r
541 IN VM_CONTEXT *VmPtr\r
542 )\r
53c71d09 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
53c71d09 604\r
fb0b259e 605/**\r
53c71d09 606 To install default Callback function for the VM interpreter.\r
607\r
fb0b259e 608 @param This pointer to the instance of DebugSupport protocol\r
53c71d09 609\r
fb0b259e 610 @return None\r
53c71d09 611\r
fb0b259e 612**/\r
613STATIC\r
614EFI_STATUS\r
615InitializeEbcCallback (\r
616 IN EFI_DEBUG_SUPPORT_PROTOCOL *This\r
617 )\r
53c71d09 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
53c71d09 660\r
fb0b259e 661/**\r
53c71d09 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
fb0b259e 666 @param InterruptType Interrupt type.\r
667 @param SystemContext EBC system context.\r
53c71d09 668\r
fb0b259e 669 @return None\r
53c71d09 670\r
fb0b259e 671**/\r
672STATIC\r
673VOID\r
674CommonEbcExceptionHandler (\r
675 IN EFI_EXCEPTION_TYPE InterruptType,\r
676 IN EFI_SYSTEM_CONTEXT SystemContext\r
677 )\r
53c71d09 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
fb0b259e 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
53c71d09 698STATIC\r
699VOID\r
700EFIAPI\r
701EbcPeriodicNotifyFunction (\r
702 IN EFI_EVENT Event,\r
703 IN VOID *Context\r
704 )\r
53c71d09 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
53c71d09 717\r
fb0b259e 718/**\r
53c71d09 719 The VM interpreter calls this function on a periodic basis to support\r
720 the EFI debug support protocol.\r
721\r
fb0b259e 722 @param VmPtr pointer to a VM context for passing info to the\r
723 debugger.\r
53c71d09 724\r
fb0b259e 725 @return Standard EFI status.\r
53c71d09 726\r
fb0b259e 727**/\r
728STATIC\r
729EFI_STATUS\r
730EbcDebugPeriodic (\r
731 IN VM_CONTEXT *VmPtr\r
732 )\r
53c71d09 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
53c71d09 778\r
fb0b259e 779/**\r
53c71d09 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
fb0b259e 784 @param This protocol instance pointer\r
785 @param ImageHandle handle to the image being unloaded.\r
53c71d09 786\r
fb0b259e 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
53c71d09 790\r
fb0b259e 791**/\r
792STATIC\r
793EFI_STATUS\r
794EFIAPI\r
795EbcUnloadImage (\r
796 IN EFI_EBC_PROTOCOL *This,\r
797 IN EFI_HANDLE ImageHandle\r
798 )\r
53c71d09 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
53c71d09 852\r
fb0b259e 853/**\r
53c71d09 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
fb0b259e 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
53c71d09 861\r
fb0b259e 862 @retval EFI_OUT_OF_RESOURCES memory allocation failed\r
863 @retval EFI_SUCCESS successful completion\r
53c71d09 864\r
fb0b259e 865**/\r
866EFI_STATUS\r
867EbcAddImageThunk (\r
868 IN EFI_HANDLE ImageHandle,\r
869 IN VOID *ThunkBuffer,\r
870 IN UINT32 ThunkSize\r
871 )\r
53c71d09 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
928STATIC\r
929EFI_STATUS\r
930EFIAPI\r
931EbcRegisterICacheFlush (\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
940STATIC\r
941EFI_STATUS\r
942EFIAPI\r
943EbcGetVersion (\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
956EFI_STATUS\r
957GetEBCStack(\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
981EFI_STATUS\r
982ReturnEBCStack(\r
983 UINTN Index\r
984 )\r
985{\r
986 mStackBufferIndex[Index] =NULL;\r
987 return EFI_SUCCESS;\r
988}\r
989\r
990EFI_STATUS\r
991ReturnEBCStackByHandle(\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
1008EFI_STATUS\r
1009InitEBCStack (\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
1026EFI_STATUS\r
1027FreeEBCStack(\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
53c71d09 1037\r
fb0b259e 1038/**\r
53c71d09 1039 Produce an EBC VM test protocol that can be used for regression tests.\r
1040\r
fb0b259e 1041 @param IHandle handle on which to install the protocol.\r
53c71d09 1042\r
fb0b259e 1043 @retval EFI_OUT_OF_RESOURCES memory allocation failed\r
1044 @retval EFI_SUCCESS successful completion\r
53c71d09 1045\r
fb0b259e 1046**/\r
1047STATIC\r
1048EFI_STATUS\r
1049InitEbcVmTestProtocol (\r
1050 IN EFI_HANDLE *IHandle\r
1051 )\r
53c71d09 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
1081STATIC\r
1082EFI_STATUS\r
1083EbcVmTestUnsupported ()\r
1084{\r
1085 return EFI_UNSUPPORTED;\r
1086}\r
1087\r