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