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