2 Top level module for the EBC virtual machine implementation.
3 Provides auxiliary support routines for the VM. That is, routines
4 that are not particularly related to VM execution of EBC instructions.
6 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include "EbcExecute.h"
13 #include "EbcDebuggerHook.h"
16 // We'll keep track of all thunks we create in a linked list. Each
17 // thunk is tied to an image handle, so we have a linked list of
18 // image handles, with each having a linked list of thunks allocated
19 // to that image handle.
21 typedef struct _EBC_THUNK_LIST EBC_THUNK_LIST
;
22 struct _EBC_THUNK_LIST
{
27 typedef struct _EBC_IMAGE_LIST EBC_IMAGE_LIST
;
28 struct _EBC_IMAGE_LIST
{
30 EFI_HANDLE ImageHandle
;
31 EBC_THUNK_LIST
*ThunkList
;
35 This routine is called by the core when an image is being unloaded from
36 memory. Basically we now have the opportunity to do any necessary cleanup.
37 Typically this will include freeing any memory allocated for thunk-creation.
39 @param This A pointer to the EFI_EBC_PROTOCOL instance.
40 @param ImageHandle Handle of image for which the thunk is being
43 @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
44 internal list of EBC image handles.
45 @retval EFI_SUCCESS The function completed successfully.
51 IN EFI_EBC_PROTOCOL
*This
,
52 IN EFI_HANDLE ImageHandle
56 This is the top-level routine plugged into the EBC protocol. Since thunks
57 are very processor-specific, from here we dispatch directly to the very
58 processor-specific routine EbcCreateThunks().
60 @param This A pointer to the EFI_EBC_PROTOCOL instance.
61 @param ImageHandle Handle of image for which the thunk is being
62 created. The EBC interpreter may use this to
63 keep track of any resource allocations
64 performed in loading and executing the image.
65 @param EbcEntryPoint Address of the actual EBC entry point or
66 protocol service the thunk should call.
67 @param Thunk Returned pointer to a thunk created.
69 @retval EFI_SUCCESS The function completed successfully.
70 @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
71 @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk.
77 IN EFI_EBC_PROTOCOL
*This
,
78 IN EFI_HANDLE ImageHandle
,
79 IN VOID
*EbcEntryPoint
,
84 Called to get the version of the interpreter.
86 @param This A pointer to the EFI_EBC_PROTOCOL instance.
87 @param Version Pointer to where to store the returned version
90 @retval EFI_SUCCESS The function completed successfully.
91 @retval EFI_INVALID_PARAMETER Version pointer is NULL.
97 IN EFI_EBC_PROTOCOL
*This
,
98 IN OUT UINT64
*Version
102 To install default Callback function for the VM interpreter.
104 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
107 @retval EFI_SUCCESS The function completed successfully.
108 @retval Others Some error occurs when creating periodic event.
113 InitializeEbcCallback (
114 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
118 The default Exception Callback for the VM interpreter.
119 In this function, we report status code, and print debug information
120 about EBC_CONTEXT, then dead loop.
122 @param InterruptType Interrupt type.
123 @param SystemContext EBC system context.
128 CommonEbcExceptionHandler (
129 IN EFI_EXCEPTION_TYPE InterruptType
,
130 IN EFI_SYSTEM_CONTEXT SystemContext
134 The periodic callback function for EBC VM interpreter, which is used
135 to support the EFI debug support protocol.
137 @param Event The Periodic Callback Event.
138 @param Context It should be the address of VM_CONTEXT pointer.
143 EbcPeriodicNotifyFunction (
149 The VM interpreter calls this function on a periodic basis to support
150 the EFI debug support protocol.
152 @param VmPtr Pointer to a VM context for passing info to the
155 @retval EFI_SUCCESS The function completed successfully.
165 // These two functions and the GUID are used to produce an EBC test protocol.
166 // This functionality is definitely not required for execution.
170 Produces an EBC VM test protocol that can be used for regression tests.
172 @param IHandle Handle on which to install the protocol.
174 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
175 @retval EFI_SUCCESS The function completed successfully.
179 InitEbcVmTestProtocol (
180 IN EFI_HANDLE
*IHandle
184 Returns the EFI_UNSUPPORTED Status.
186 @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
191 EbcVmTestUnsupported (
196 Registers a callback function that the EBC interpreter calls to flush the
197 processor instruction cache following creation of thunks.
199 @param This A pointer to the EFI_EBC_PROTOCOL instance.
200 @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
202 @retval EFI_SUCCESS The function completed successfully.
207 EbcRegisterICacheFlush (
208 IN EFI_EBC_PROTOCOL
*This
,
209 IN EBC_ICACHE_FLUSH Flush
213 This EBC debugger protocol service is called by the debug agent
215 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
217 @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
218 maximum supported processor index is returned.
220 @retval EFI_SUCCESS The function completed successfully.
225 EbcDebugGetMaximumProcessorIndex (
226 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
227 OUT UINTN
*MaxProcessorIndex
231 This protocol service is called by the debug agent to register a function
232 for us to call on a periodic basis.
234 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
236 @param ProcessorIndex Specifies which processor the callback function
238 @param PeriodicCallback A pointer to a function of type
239 PERIODIC_CALLBACK that is the main periodic
240 entry point of the debug agent. It receives as a
241 parameter a pointer to the full context of the
242 interrupted execution thread.
244 @retval EFI_SUCCESS The function completed successfully.
245 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
246 callback function was previously registered.
247 @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
248 callback function was previously registered.
253 EbcDebugRegisterPeriodicCallback (
254 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
255 IN UINTN ProcessorIndex
,
256 IN EFI_PERIODIC_CALLBACK PeriodicCallback
260 This protocol service is called by the debug agent to register a function
261 for us to call when we detect an exception.
263 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
265 @param ProcessorIndex Specifies which processor the callback function
267 @param ExceptionCallback A pointer to a function of type
268 EXCEPTION_CALLBACK that is called when the
269 processor exception specified by ExceptionType
270 occurs. Passing NULL unregisters any previously
271 registered function associated with
273 @param ExceptionType Specifies which processor exception to hook.
275 @retval EFI_SUCCESS The function completed successfully.
276 @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
277 callback function was previously registered.
278 @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
280 @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
281 callback function was previously registered.
286 EbcDebugRegisterExceptionCallback (
287 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
288 IN UINTN ProcessorIndex
,
289 IN EFI_EXCEPTION_CALLBACK ExceptionCallback
,
290 IN EFI_EXCEPTION_TYPE ExceptionType
294 This EBC debugger protocol service is called by the debug agent. Required
295 for DebugSupport compliance but is only stubbed out for EBC.
297 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
299 @param ProcessorIndex Specifies which processor the callback function
301 @param Start StartSpecifies the physical base of the memory
302 range to be invalidated.
303 @param Length Specifies the minimum number of bytes in the
304 processor's instruction cache to invalidate.
306 @retval EFI_SUCCESS The function completed successfully.
311 EbcDebugInvalidateInstructionCache (
312 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
313 IN UINTN ProcessorIndex
,
319 // We have one linked list of image handles for the whole world. Since
320 // there should only be one interpreter, make them global. They must
321 // also be global since the execution of an EBC image does not provide
324 EBC_IMAGE_LIST
*mEbcImageList
= NULL
;
327 // Callback function to flush the icache after thunk creation
329 EBC_ICACHE_FLUSH mEbcICacheFlush
;
332 // These get set via calls by the debug agent
334 EFI_PERIODIC_CALLBACK mDebugPeriodicCallback
= NULL
;
335 EFI_EXCEPTION_CALLBACK mDebugExceptionCallback
[MAX_EBC_EXCEPTION
+ 1] = { NULL
};
337 VOID
*mStackBuffer
[MAX_STACK_NUM
];
338 EFI_HANDLE mStackBufferIndex
[MAX_STACK_NUM
];
342 // Event for Periodic callback
344 EFI_EVENT mEbcPeriodicEvent
;
345 VM_CONTEXT
*mVmPtr
= NULL
;
348 Check whether the emulator supports executing a certain PE/COFF image
350 @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
352 @param[in] ImageType Whether the image is an application, a boot time
353 driver or a runtime driver.
354 @param[in] DevicePath Path to device where the image originated
355 (e.g., a PCI option ROM)
357 @retval TRUE The image is supported by the emulator
358 @retval FALSE The image is not supported by the emulator.
362 EbcIsImageSupported (
363 IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
*This
,
365 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath OPTIONAL
368 if ((ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) &&
369 (ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
))
378 Register a supported PE/COFF image with the emulator. After this call
379 completes successfully, the PE/COFF image may be started as usual, and
380 it is the responsibility of the emulator implementation that any branch
381 into the code section of the image (including returns from functions called
382 from the foreign code) is executed as if it were running on the machine
383 type it was built for.
385 @param[in] This This pointer for
386 EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL structure
387 @param[in] ImageBase The base address in memory of the PE/COFF image
388 @param[in] ImageSize The size in memory of the PE/COFF image
389 @param[in,out] EntryPoint The entry point of the PE/COFF image. Passed by
390 reference so that the emulator may modify it.
392 @retval EFI_SUCCESS The image was registered with the emulator and
393 can be started as usual.
394 @retval other The image could not be registered.
396 If the PE/COFF machine type or image type are not supported by the emulator,
402 IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
*This
,
403 IN EFI_PHYSICAL_ADDRESS ImageBase
,
405 IN OUT EFI_IMAGE_ENTRY_POINT
*EntryPoint
409 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
412 ZeroMem (&ImageContext
, sizeof (ImageContext
));
414 ImageContext
.Handle
= (VOID
*)(UINTN
)ImageBase
;
415 ImageContext
.ImageRead
= PeCoffLoaderImageReadFromMemory
;
417 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
418 if (EFI_ERROR (Status
)) {
422 ASSERT (ImageContext
.Machine
== EFI_IMAGE_MACHINE_EBC
);
424 ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
||
425 ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
429 EbcRegisterICacheFlush (
431 (EBC_ICACHE_FLUSH
)InvalidateInstructionCacheRange
434 return EbcCreateThunk (
436 (VOID
*)(UINTN
)ImageBase
,
437 (VOID
*)(UINTN
)*EntryPoint
,
443 Unregister a PE/COFF image that has been registered with the emulator.
444 This should be done before the image is unloaded from memory.
446 @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
448 @param[in] ImageBase The base address in memory of the PE/COFF image
450 @retval EFI_SUCCESS The image was unregistered with the emulator.
451 @retval other Image could not be unloaded.
456 IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
*This
,
457 IN EFI_PHYSICAL_ADDRESS ImageBase
460 return EbcUnloadImage (NULL
, (VOID
*)(UINTN
)ImageBase
);
463 STATIC EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL mPeCoffEmuProtocol
= {
467 EDKII_PECOFF_IMAGE_EMULATOR_VERSION
,
468 EFI_IMAGE_MACHINE_EBC
472 Initializes the VM EFI interface. Allocates memory for the VM interface
473 and registers the VM protocol.
475 @param ImageHandle EFI image handle.
476 @param SystemTable Pointer to the EFI system table.
478 @return Standard EFI status code.
483 InitializeEbcDriver (
484 IN EFI_HANDLE ImageHandle
,
485 IN EFI_SYSTEM_TABLE
*SystemTable
488 EFI_EBC_PROTOCOL
*EbcProtocol
;
489 EFI_EBC_PROTOCOL
*OldEbcProtocol
;
491 EFI_DEBUG_SUPPORT_PROTOCOL
*EbcDebugProtocol
;
492 EFI_HANDLE
*HandleBuffer
;
498 EbcDebugProtocol
= NULL
;
501 // Allocate memory for our protocol. Then fill in the blanks.
503 EbcProtocol
= AllocatePool (sizeof (EFI_EBC_PROTOCOL
));
505 if (EbcProtocol
== NULL
) {
506 return EFI_OUT_OF_RESOURCES
;
509 EbcProtocol
->CreateThunk
= EbcCreateThunk
;
510 EbcProtocol
->UnloadImage
= EbcUnloadImage
;
511 EbcProtocol
->RegisterICacheFlush
= EbcRegisterICacheFlush
;
512 EbcProtocol
->GetVersion
= EbcGetVersion
;
513 mEbcICacheFlush
= NULL
;
516 // Find any already-installed EBC protocols and uninstall them
520 Status
= gBS
->LocateHandleBuffer (
522 &gEfiEbcProtocolGuid
,
527 if (Status
== EFI_SUCCESS
) {
529 // Loop through the handles
531 for (Index
= 0; Index
< NumHandles
; Index
++) {
532 Status
= gBS
->HandleProtocol (
534 &gEfiEbcProtocolGuid
,
535 (VOID
**)&OldEbcProtocol
537 if (Status
== EFI_SUCCESS
) {
538 if (gBS
->ReinstallProtocolInterface (
540 &gEfiEbcProtocolGuid
,
551 if (HandleBuffer
!= NULL
) {
552 FreePool (HandleBuffer
);
557 // Add the protocol so someone can locate us if we haven't already.
560 Status
= gBS
->InstallMultipleProtocolInterfaces (
562 &gEfiEbcProtocolGuid
,
564 &gEdkiiPeCoffImageEmulatorProtocolGuid
,
568 if (EFI_ERROR (Status
)) {
569 FreePool (EbcProtocol
);
574 Status
= InitEBCStack ();
575 if (EFI_ERROR (Status
)) {
580 // Allocate memory for our debug protocol. Then fill in the blanks.
582 EbcDebugProtocol
= AllocatePool (sizeof (EFI_DEBUG_SUPPORT_PROTOCOL
));
584 if (EbcDebugProtocol
== NULL
) {
588 EbcDebugProtocol
->Isa
= IsaEbc
;
589 EbcDebugProtocol
->GetMaximumProcessorIndex
= EbcDebugGetMaximumProcessorIndex
;
590 EbcDebugProtocol
->RegisterPeriodicCallback
= EbcDebugRegisterPeriodicCallback
;
591 EbcDebugProtocol
->RegisterExceptionCallback
= EbcDebugRegisterExceptionCallback
;
592 EbcDebugProtocol
->InvalidateInstructionCache
= EbcDebugInvalidateInstructionCache
;
595 // Add the protocol so the debug agent can find us
597 Status
= gBS
->InstallProtocolInterface (
599 &gEfiDebugSupportProtocolGuid
,
600 EFI_NATIVE_INTERFACE
,
604 // This is recoverable, so free the memory and continue.
606 if (EFI_ERROR (Status
)) {
607 FreePool (EbcDebugProtocol
);
612 // Install EbcDebugSupport Protocol Successfully
613 // Now we need to initialize the Ebc default Callback
615 Status
= InitializeEbcCallback (EbcDebugProtocol
);
618 // Produce a VM test interface protocol. Not required for execution.
621 InitEbcVmTestProtocol (&ImageHandle
);
624 EbcDebuggerHookInit (ImageHandle
, EbcDebugProtocol
);
631 Status
= gBS
->LocateHandleBuffer (
633 &gEfiEbcProtocolGuid
,
638 if (Status
== EFI_SUCCESS
) {
640 // Loop through the handles
642 for (Index
= 0; Index
< NumHandles
; Index
++) {
643 Status
= gBS
->HandleProtocol (
645 &gEfiEbcProtocolGuid
,
646 (VOID
**)&OldEbcProtocol
648 if (Status
== EFI_SUCCESS
) {
649 gBS
->UninstallProtocolInterface (
651 &gEfiEbcProtocolGuid
,
658 if (HandleBuffer
!= NULL
) {
659 FreePool (HandleBuffer
);
663 FreePool (EbcProtocol
);
669 This is the top-level routine plugged into the EBC protocol. Since thunks
670 are very processor-specific, from here we dispatch directly to the very
671 processor-specific routine EbcCreateThunks().
673 @param This A pointer to the EFI_EBC_PROTOCOL instance.
674 @param ImageHandle Handle of image for which the thunk is being
675 created. The EBC interpreter may use this to
676 keep track of any resource allocations
677 performed in loading and executing the image.
678 @param EbcEntryPoint Address of the actual EBC entry point or
679 protocol service the thunk should call.
680 @param Thunk Returned pointer to a thunk created.
682 @retval EFI_SUCCESS The function completed successfully.
683 @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
684 @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk.
690 IN EFI_EBC_PROTOCOL
*This
,
691 IN EFI_HANDLE ImageHandle
,
692 IN VOID
*EbcEntryPoint
,
698 Status
= EbcCreateThunks (
702 FLAG_THUNK_ENTRY_POINT
708 This EBC debugger protocol service is called by the debug agent
710 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
712 @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
713 maximum supported processor index is returned.
715 @retval EFI_SUCCESS The function completed successfully.
720 EbcDebugGetMaximumProcessorIndex (
721 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
722 OUT UINTN
*MaxProcessorIndex
725 *MaxProcessorIndex
= 0;
730 This protocol service is called by the debug agent to register a function
731 for us to call on a periodic basis.
733 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
735 @param ProcessorIndex Specifies which processor the callback function
737 @param PeriodicCallback A pointer to a function of type
738 PERIODIC_CALLBACK that is the main periodic
739 entry point of the debug agent. It receives as a
740 parameter a pointer to the full context of the
741 interrupted execution thread.
743 @retval EFI_SUCCESS The function completed successfully.
744 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
745 callback function was previously registered.
746 @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
747 callback function was previously registered.
752 EbcDebugRegisterPeriodicCallback (
753 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
754 IN UINTN ProcessorIndex
,
755 IN EFI_PERIODIC_CALLBACK PeriodicCallback
758 if ((mDebugPeriodicCallback
== NULL
) && (PeriodicCallback
== NULL
)) {
759 return EFI_INVALID_PARAMETER
;
762 if ((mDebugPeriodicCallback
!= NULL
) && (PeriodicCallback
!= NULL
)) {
763 return EFI_ALREADY_STARTED
;
766 mDebugPeriodicCallback
= PeriodicCallback
;
771 This protocol service is called by the debug agent to register a function
772 for us to call when we detect an exception.
774 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
776 @param ProcessorIndex Specifies which processor the callback function
778 @param ExceptionCallback A pointer to a function of type
779 EXCEPTION_CALLBACK that is called when the
780 processor exception specified by ExceptionType
781 occurs. Passing NULL unregisters any previously
782 registered function associated with
784 @param ExceptionType Specifies which processor exception to hook.
786 @retval EFI_SUCCESS The function completed successfully.
787 @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
788 callback function was previously registered.
789 @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
791 @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
792 callback function was previously registered.
797 EbcDebugRegisterExceptionCallback (
798 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
799 IN UINTN ProcessorIndex
,
800 IN EFI_EXCEPTION_CALLBACK ExceptionCallback
,
801 IN EFI_EXCEPTION_TYPE ExceptionType
804 if ((ExceptionType
< 0) || (ExceptionType
> MAX_EBC_EXCEPTION
)) {
805 return EFI_INVALID_PARAMETER
;
808 if ((mDebugExceptionCallback
[ExceptionType
] == NULL
) && (ExceptionCallback
== NULL
)) {
809 return EFI_INVALID_PARAMETER
;
812 if ((mDebugExceptionCallback
[ExceptionType
] != NULL
) && (ExceptionCallback
!= NULL
)) {
813 return EFI_ALREADY_STARTED
;
816 mDebugExceptionCallback
[ExceptionType
] = ExceptionCallback
;
821 This EBC debugger protocol service is called by the debug agent. Required
822 for DebugSupport compliance but is only stubbed out for EBC.
824 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
826 @param ProcessorIndex Specifies which processor the callback function
828 @param Start StartSpecifies the physical base of the memory
829 range to be invalidated.
830 @param Length Specifies the minimum number of bytes in the
831 processor's instruction cache to invalidate.
833 @retval EFI_SUCCESS The function completed successfully.
838 EbcDebugInvalidateInstructionCache (
839 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
840 IN UINTN ProcessorIndex
,
849 The VM interpreter calls this function when an exception is detected.
851 @param ExceptionType Specifies the processor exception detected.
852 @param ExceptionFlags Specifies the exception context.
853 @param VmPtr Pointer to a VM context for passing info to the
856 @retval EFI_SUCCESS This function completed successfully.
860 EbcDebugSignalException (
861 IN EFI_EXCEPTION_TYPE ExceptionType
,
862 IN EXCEPTION_FLAGS ExceptionFlags
,
866 EFI_SYSTEM_CONTEXT_EBC EbcContext
;
867 EFI_SYSTEM_CONTEXT SystemContext
;
869 ASSERT ((ExceptionType
>= 0) && (ExceptionType
<= MAX_EBC_EXCEPTION
));
871 // Save the exception in the context passed in
873 VmPtr
->ExceptionFlags
|= ExceptionFlags
;
874 VmPtr
->LastException
= (UINTN
)ExceptionType
;
876 // If it's a fatal exception, then flag it in the VM context in case an
877 // attached debugger tries to return from it.
879 if ((ExceptionFlags
& EXCEPTION_FLAG_FATAL
) != 0) {
880 VmPtr
->StopFlags
|= STOPFLAG_APP_DONE
;
884 // If someone's registered for exception callbacks, then call them.
886 // EBC driver will register default exception callback to report the
887 // status code via the status code API
889 if (mDebugExceptionCallback
[ExceptionType
] != NULL
) {
891 // Initialize the context structure
893 EbcContext
.R0
= (UINT64
)VmPtr
->Gpr
[0];
894 EbcContext
.R1
= (UINT64
)VmPtr
->Gpr
[1];
895 EbcContext
.R2
= (UINT64
)VmPtr
->Gpr
[2];
896 EbcContext
.R3
= (UINT64
)VmPtr
->Gpr
[3];
897 EbcContext
.R4
= (UINT64
)VmPtr
->Gpr
[4];
898 EbcContext
.R5
= (UINT64
)VmPtr
->Gpr
[5];
899 EbcContext
.R6
= (UINT64
)VmPtr
->Gpr
[6];
900 EbcContext
.R7
= (UINT64
)VmPtr
->Gpr
[7];
901 EbcContext
.Ip
= (UINT64
)(UINTN
)VmPtr
->Ip
;
902 EbcContext
.Flags
= VmPtr
->Flags
;
903 EbcContext
.ControlFlags
= 0;
904 SystemContext
.SystemContextEbc
= &EbcContext
;
906 mDebugExceptionCallback
[ExceptionType
](ExceptionType
, SystemContext
);
908 // Restore the context structure and continue to execute
910 VmPtr
->Gpr
[0] = EbcContext
.R0
;
911 VmPtr
->Gpr
[1] = EbcContext
.R1
;
912 VmPtr
->Gpr
[2] = EbcContext
.R2
;
913 VmPtr
->Gpr
[3] = EbcContext
.R3
;
914 VmPtr
->Gpr
[4] = EbcContext
.R4
;
915 VmPtr
->Gpr
[5] = EbcContext
.R5
;
916 VmPtr
->Gpr
[6] = EbcContext
.R6
;
917 VmPtr
->Gpr
[7] = EbcContext
.R7
;
918 VmPtr
->Ip
= (VMIP
)(UINTN
)EbcContext
.Ip
;
919 VmPtr
->Flags
= EbcContext
.Flags
;
926 To install default Callback function for the VM interpreter.
928 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
931 @retval EFI_SUCCESS The function completed successfully.
932 @retval Others Some error occurs when creating periodic event.
937 InitializeEbcCallback (
938 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
945 // For ExceptionCallback
947 for (Index
= 0; Index
<= MAX_EBC_EXCEPTION
; Index
++) {
948 EbcDebugRegisterExceptionCallback (
951 CommonEbcExceptionHandler
,
957 // For PeriodicCallback
959 Status
= gBS
->CreateEvent (
960 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
962 EbcPeriodicNotifyFunction
,
966 if (EFI_ERROR (Status
)) {
970 Status
= gBS
->SetTimer (
973 EBC_VM_PERIODIC_CALLBACK_RATE
975 if (EFI_ERROR (Status
)) {
983 The default Exception Callback for the VM interpreter.
984 In this function, we report status code, and print debug information
985 about EBC_CONTEXT, then dead loop.
987 @param InterruptType Interrupt type.
988 @param SystemContext EBC system context.
993 CommonEbcExceptionHandler (
994 IN EFI_EXCEPTION_TYPE InterruptType
,
995 IN EFI_SYSTEM_CONTEXT SystemContext
999 // We print debug information to let user know what happen.
1003 "EBC Interrupter Version - 0x%016lx\n",
1004 (UINT64
)(((VM_MAJOR_VERSION
& 0xFFFF) << 16) | ((VM_MINOR_VERSION
& 0xFFFF)))
1008 "Exception Type - 0x%016lx\n",
1009 (UINT64
)(UINTN
)InterruptType
1013 " R0 - 0x%016lx, R1 - 0x%016lx\n",
1014 SystemContext
.SystemContextEbc
->R0
,
1015 SystemContext
.SystemContextEbc
->R1
1019 " R2 - 0x%016lx, R3 - 0x%016lx\n",
1020 SystemContext
.SystemContextEbc
->R2
,
1021 SystemContext
.SystemContextEbc
->R3
1025 " R4 - 0x%016lx, R5 - 0x%016lx\n",
1026 SystemContext
.SystemContextEbc
->R4
,
1027 SystemContext
.SystemContextEbc
->R5
1031 " R6 - 0x%016lx, R7 - 0x%016lx\n",
1032 SystemContext
.SystemContextEbc
->R6
,
1033 SystemContext
.SystemContextEbc
->R7
1037 " Flags - 0x%016lx\n",
1038 SystemContext
.SystemContextEbc
->Flags
1042 " ControlFlags - 0x%016lx\n",
1043 SystemContext
.SystemContextEbc
->ControlFlags
1047 " Ip - 0x%016lx\n\n",
1048 SystemContext
.SystemContextEbc
->Ip
1052 // We deadloop here to make it easy to debug this issue.
1060 The periodic callback function for EBC VM interpreter, which is used
1061 to support the EFI debug support protocol.
1063 @param Event The Periodic Callback Event.
1064 @param Context It should be the address of VM_CONTEXT pointer.
1069 EbcPeriodicNotifyFunction (
1076 VmPtr
= *(VM_CONTEXT
**)Context
;
1078 if (VmPtr
!= NULL
) {
1079 EbcDebugPeriodic (VmPtr
);
1086 The VM interpreter calls this function on a periodic basis to support
1087 the EFI debug support protocol.
1089 @param VmPtr Pointer to a VM context for passing info to the
1092 @retval EFI_SUCCESS The function completed successfully.
1098 IN VM_CONTEXT
*VmPtr
1101 EFI_SYSTEM_CONTEXT_EBC EbcContext
;
1102 EFI_SYSTEM_CONTEXT SystemContext
;
1105 // If someone's registered for periodic callbacks, then call them.
1107 if (mDebugPeriodicCallback
!= NULL
) {
1109 // Initialize the context structure
1111 EbcContext
.R0
= (UINT64
)VmPtr
->Gpr
[0];
1112 EbcContext
.R1
= (UINT64
)VmPtr
->Gpr
[1];
1113 EbcContext
.R2
= (UINT64
)VmPtr
->Gpr
[2];
1114 EbcContext
.R3
= (UINT64
)VmPtr
->Gpr
[3];
1115 EbcContext
.R4
= (UINT64
)VmPtr
->Gpr
[4];
1116 EbcContext
.R5
= (UINT64
)VmPtr
->Gpr
[5];
1117 EbcContext
.R6
= (UINT64
)VmPtr
->Gpr
[6];
1118 EbcContext
.R7
= (UINT64
)VmPtr
->Gpr
[7];
1119 EbcContext
.Ip
= (UINT64
)(UINTN
)VmPtr
->Ip
;
1120 EbcContext
.Flags
= VmPtr
->Flags
;
1121 EbcContext
.ControlFlags
= 0;
1122 SystemContext
.SystemContextEbc
= &EbcContext
;
1124 mDebugPeriodicCallback (SystemContext
);
1127 // Restore the context structure and continue to execute
1129 VmPtr
->Gpr
[0] = EbcContext
.R0
;
1130 VmPtr
->Gpr
[1] = EbcContext
.R1
;
1131 VmPtr
->Gpr
[2] = EbcContext
.R2
;
1132 VmPtr
->Gpr
[3] = EbcContext
.R3
;
1133 VmPtr
->Gpr
[4] = EbcContext
.R4
;
1134 VmPtr
->Gpr
[5] = EbcContext
.R5
;
1135 VmPtr
->Gpr
[6] = EbcContext
.R6
;
1136 VmPtr
->Gpr
[7] = EbcContext
.R7
;
1137 VmPtr
->Ip
= (VMIP
)(UINTN
)EbcContext
.Ip
;
1138 VmPtr
->Flags
= EbcContext
.Flags
;
1145 This routine is called by the core when an image is being unloaded from
1146 memory. Basically we now have the opportunity to do any necessary cleanup.
1147 Typically this will include freeing any memory allocated for thunk-creation.
1149 @param This A pointer to the EFI_EBC_PROTOCOL instance.
1150 @param ImageHandle Handle of image for which the thunk is being
1153 @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
1154 internal list of EBC image handles.
1155 @retval EFI_SUCCESS The function completed successfully.
1161 IN EFI_EBC_PROTOCOL
*This
,
1162 IN EFI_HANDLE ImageHandle
1165 EBC_THUNK_LIST
*ThunkList
;
1166 EBC_THUNK_LIST
*NextThunkList
;
1167 EBC_IMAGE_LIST
*ImageList
;
1168 EBC_IMAGE_LIST
*PrevImageList
;
1171 // First go through our list of known image handles and see if we've already
1172 // created an image list element for this image handle.
1174 ReturnEBCStackByHandle (ImageHandle
);
1175 PrevImageList
= NULL
;
1176 for (ImageList
= mEbcImageList
; ImageList
!= NULL
; ImageList
= ImageList
->Next
) {
1177 if (ImageList
->ImageHandle
== ImageHandle
) {
1182 // Save the previous so we can connect the lists when we remove this one
1184 PrevImageList
= ImageList
;
1187 if (ImageList
== NULL
) {
1188 return EFI_INVALID_PARAMETER
;
1192 // Free up all the thunk buffers and thunks list elements for this image
1195 ThunkList
= ImageList
->ThunkList
;
1196 while (ThunkList
!= NULL
) {
1197 NextThunkList
= ThunkList
->Next
;
1198 FreePool (ThunkList
->ThunkBuffer
);
1199 FreePool (ThunkList
);
1200 ThunkList
= NextThunkList
;
1204 // Now remove this image list element from the chain
1206 if (PrevImageList
== NULL
) {
1210 mEbcImageList
= ImageList
->Next
;
1212 PrevImageList
->Next
= ImageList
->Next
;
1216 // Now free up the image list element
1218 FreePool (ImageList
);
1220 EbcDebuggerHookEbcUnloadImage (ImageHandle
);
1226 Add a thunk to our list of thunks for a given image handle.
1227 Also flush the instruction cache since we've written thunk code
1228 to memory that will be executed eventually.
1230 @param ImageHandle The image handle to which the thunk is tied.
1231 @param ThunkBuffer The buffer that has been created/allocated.
1232 @param ThunkSize The size of the thunk memory allocated.
1234 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1235 @retval EFI_SUCCESS The function completed successfully.
1240 IN EFI_HANDLE ImageHandle
,
1241 IN VOID
*ThunkBuffer
,
1245 EBC_THUNK_LIST
*ThunkList
;
1246 EBC_IMAGE_LIST
*ImageList
;
1250 // It so far so good, then flush the instruction cache
1252 if (mEbcICacheFlush
!= NULL
) {
1253 Status
= mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS
)(UINTN
)ThunkBuffer
, ThunkSize
);
1254 if (EFI_ERROR (Status
)) {
1260 // Go through our list of known image handles and see if we've already
1261 // created a image list element for this image handle.
1263 for (ImageList
= mEbcImageList
; ImageList
!= NULL
; ImageList
= ImageList
->Next
) {
1264 if (ImageList
->ImageHandle
== ImageHandle
) {
1269 if (ImageList
== NULL
) {
1271 // Allocate a new one
1273 ImageList
= AllocatePool (sizeof (EBC_IMAGE_LIST
));
1275 if (ImageList
== NULL
) {
1276 return EFI_OUT_OF_RESOURCES
;
1279 ImageList
->ThunkList
= NULL
;
1280 ImageList
->ImageHandle
= ImageHandle
;
1281 ImageList
->Next
= mEbcImageList
;
1282 mEbcImageList
= ImageList
;
1286 // Ok, now create a new thunk element to add to the list
1288 ThunkList
= AllocatePool (sizeof (EBC_THUNK_LIST
));
1290 if (ThunkList
== NULL
) {
1291 return EFI_OUT_OF_RESOURCES
;
1295 // Add it to the head of the list
1297 ThunkList
->Next
= ImageList
->ThunkList
;
1298 ThunkList
->ThunkBuffer
= ThunkBuffer
;
1299 ImageList
->ThunkList
= ThunkList
;
1304 Registers a callback function that the EBC interpreter calls to flush the
1305 processor instruction cache following creation of thunks.
1307 @param This A pointer to the EFI_EBC_PROTOCOL instance.
1308 @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
1310 @retval EFI_SUCCESS The function completed successfully.
1315 EbcRegisterICacheFlush (
1316 IN EFI_EBC_PROTOCOL
*This
,
1317 IN EBC_ICACHE_FLUSH Flush
1320 mEbcICacheFlush
= Flush
;
1325 Called to get the version of the interpreter.
1327 @param This A pointer to the EFI_EBC_PROTOCOL instance.
1328 @param Version Pointer to where to store the returned version
1331 @retval EFI_SUCCESS The function completed successfully.
1332 @retval EFI_INVALID_PARAMETER Version pointer is NULL.
1338 IN EFI_EBC_PROTOCOL
*This
,
1339 IN OUT UINT64
*Version
1342 if (Version
== NULL
) {
1343 return EFI_INVALID_PARAMETER
;
1346 *Version
= GetVmVersion ();
1351 Returns the stack index and buffer assosicated with the Handle parameter.
1353 @param Handle The EFI handle as the index to the EBC stack.
1354 @param StackBuffer A pointer to hold the returned stack buffer.
1355 @param BufferIndex A pointer to hold the returned stack index.
1357 @retval EFI_OUT_OF_RESOURCES The Handle parameter does not correspond to any
1359 @retval EFI_SUCCESS The stack index and buffer were found and
1360 returned to the caller.
1365 IN EFI_HANDLE Handle
,
1366 OUT VOID
**StackBuffer
,
1367 OUT UINTN
*BufferIndex
1373 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
1374 for (Index
= 0; Index
< mStackNum
; Index
++) {
1375 if (mStackBufferIndex
[Index
] == NULL
) {
1376 mStackBufferIndex
[Index
] = Handle
;
1381 gBS
->RestoreTPL (OldTpl
);
1382 if (Index
== mStackNum
) {
1383 return EFI_OUT_OF_RESOURCES
;
1386 *BufferIndex
= Index
;
1387 *StackBuffer
= mStackBuffer
[Index
];
1392 Returns from the EBC stack by stack Index.
1394 @param Index Specifies which EBC stack to return from.
1396 @retval EFI_SUCCESS The function completed successfully.
1404 mStackBufferIndex
[Index
] = NULL
;
1409 Returns from the EBC stack associated with the Handle parameter.
1411 @param Handle Specifies the EFI handle to find the EBC stack with.
1413 @retval EFI_SUCCESS The function completed successfully.
1417 ReturnEBCStackByHandle (
1418 IN EFI_HANDLE Handle
1423 for (Index
= 0; Index
< mStackNum
; Index
++) {
1424 if (mStackBufferIndex
[Index
] == Handle
) {
1429 if (Index
== mStackNum
) {
1430 return EFI_NOT_FOUND
;
1433 mStackBufferIndex
[Index
] = NULL
;
1438 Allocates memory to hold all the EBC stacks.
1440 @retval EFI_SUCCESS The EBC stacks were allocated successfully.
1441 @retval EFI_OUT_OF_RESOURCES Not enough memory available for EBC stacks.
1449 for (mStackNum
= 0; mStackNum
< MAX_STACK_NUM
; mStackNum
++) {
1450 mStackBuffer
[mStackNum
] = AllocatePool (STACK_POOL_SIZE
);
1451 mStackBufferIndex
[mStackNum
] = NULL
;
1452 if (mStackBuffer
[mStackNum
] == NULL
) {
1457 if (mStackNum
== 0) {
1458 return EFI_OUT_OF_RESOURCES
;
1465 Free all EBC stacks allocated before.
1467 @retval EFI_SUCCESS All the EBC stacks were freed.
1477 for (Index
= 0; Index
< mStackNum
; Index
++) {
1478 FreePool (mStackBuffer
[Index
]);
1485 Produces an EBC VM test protocol that can be used for regression tests.
1487 @param IHandle Handle on which to install the protocol.
1489 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1490 @retval EFI_SUCCESS The function completed successfully.
1494 InitEbcVmTestProtocol (
1495 IN EFI_HANDLE
*IHandle
1500 EFI_EBC_VM_TEST_PROTOCOL
*EbcVmTestProtocol
;
1503 // Allocate memory for the protocol, then fill in the fields
1505 EbcVmTestProtocol
= AllocatePool (sizeof (EFI_EBC_VM_TEST_PROTOCOL
));
1506 if (EbcVmTestProtocol
== NULL
) {
1507 return EFI_OUT_OF_RESOURCES
;
1510 EbcVmTestProtocol
->Execute
= (EBC_VM_TEST_EXECUTE
)EbcExecuteInstructions
;
1512 DEBUG_CODE_BEGIN ();
1513 EbcVmTestProtocol
->Assemble
= (EBC_VM_TEST_ASM
)EbcVmTestUnsupported
;
1514 EbcVmTestProtocol
->Disassemble
= (EBC_VM_TEST_DASM
)EbcVmTestUnsupported
;
1518 // Publish the protocol
1521 Status
= gBS
->InstallProtocolInterface (&Handle
, &gEfiEbcVmTestProtocolGuid
, EFI_NATIVE_INTERFACE
, EbcVmTestProtocol
);
1522 if (EFI_ERROR (Status
)) {
1523 FreePool (EbcVmTestProtocol
);
1530 Returns the EFI_UNSUPPORTED Status.
1532 @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
1537 EbcVmTestUnsupported (
1541 return EFI_UNSUPPORTED
;
1545 Allocates a buffer of type EfiBootServicesCode.
1547 @param AllocationSize The number of bytes to allocate.
1549 @return A pointer to the allocated buffer or NULL if allocation fails.
1554 EbcAllocatePoolForThunk (
1555 IN UINTN AllocationSize
1561 Status
= gBS
->AllocatePool (EfiBootServicesCode
, AllocationSize
, &Buffer
);
1562 if (EFI_ERROR (Status
)) {