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.
169 Produces an EBC VM test protocol that can be used for regression tests.
171 @param IHandle Handle on which to install the protocol.
173 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
174 @retval EFI_SUCCESS The function completed successfully.
178 InitEbcVmTestProtocol (
179 IN EFI_HANDLE
*IHandle
183 Returns the EFI_UNSUPPORTED Status.
185 @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
190 EbcVmTestUnsupported (
195 Registers a callback function that the EBC interpreter calls to flush the
196 processor instruction cache following creation of thunks.
198 @param This A pointer to the EFI_EBC_PROTOCOL instance.
199 @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
201 @retval EFI_SUCCESS The function completed successfully.
206 EbcRegisterICacheFlush (
207 IN EFI_EBC_PROTOCOL
*This
,
208 IN EBC_ICACHE_FLUSH Flush
212 This EBC debugger protocol service is called by the debug agent
214 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
216 @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
217 maximum supported processor index is returned.
219 @retval EFI_SUCCESS The function completed successfully.
224 EbcDebugGetMaximumProcessorIndex (
225 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
226 OUT UINTN
*MaxProcessorIndex
230 This protocol service is called by the debug agent to register a function
231 for us to call on a periodic basis.
233 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
235 @param ProcessorIndex Specifies which processor the callback function
237 @param PeriodicCallback A pointer to a function of type
238 PERIODIC_CALLBACK that is the main periodic
239 entry point of the debug agent. It receives as a
240 parameter a pointer to the full context of the
241 interrupted execution thread.
243 @retval EFI_SUCCESS The function completed successfully.
244 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
245 callback function was previously registered.
246 @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
247 callback function was previously registered.
252 EbcDebugRegisterPeriodicCallback (
253 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
254 IN UINTN ProcessorIndex
,
255 IN EFI_PERIODIC_CALLBACK PeriodicCallback
259 This protocol service is called by the debug agent to register a function
260 for us to call when we detect an exception.
262 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
264 @param ProcessorIndex Specifies which processor the callback function
266 @param ExceptionCallback A pointer to a function of type
267 EXCEPTION_CALLBACK that is called when the
268 processor exception specified by ExceptionType
269 occurs. Passing NULL unregisters any previously
270 registered function associated with
272 @param ExceptionType Specifies which processor exception to hook.
274 @retval EFI_SUCCESS The function completed successfully.
275 @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
276 callback function was previously registered.
277 @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
279 @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
280 callback function was previously registered.
285 EbcDebugRegisterExceptionCallback (
286 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
287 IN UINTN ProcessorIndex
,
288 IN EFI_EXCEPTION_CALLBACK ExceptionCallback
,
289 IN EFI_EXCEPTION_TYPE ExceptionType
293 This EBC debugger protocol service is called by the debug agent. Required
294 for DebugSupport compliance but is only stubbed out for EBC.
296 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
298 @param ProcessorIndex Specifies which processor the callback function
300 @param Start StartSpecifies the physical base of the memory
301 range to be invalidated.
302 @param Length Specifies the minimum number of bytes in the
303 processor's instruction cache to invalidate.
305 @retval EFI_SUCCESS The function completed successfully.
310 EbcDebugInvalidateInstructionCache (
311 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
312 IN UINTN ProcessorIndex
,
318 // We have one linked list of image handles for the whole world. Since
319 // there should only be one interpreter, make them global. They must
320 // also be global since the execution of an EBC image does not provide
323 EBC_IMAGE_LIST
*mEbcImageList
= NULL
;
326 // Callback function to flush the icache after thunk creation
328 EBC_ICACHE_FLUSH mEbcICacheFlush
;
331 // These get set via calls by the debug agent
333 EFI_PERIODIC_CALLBACK mDebugPeriodicCallback
= NULL
;
334 EFI_EXCEPTION_CALLBACK mDebugExceptionCallback
[MAX_EBC_EXCEPTION
+ 1] = {NULL
};
336 VOID
*mStackBuffer
[MAX_STACK_NUM
];
337 EFI_HANDLE mStackBufferIndex
[MAX_STACK_NUM
];
341 // Event for Periodic callback
343 EFI_EVENT mEbcPeriodicEvent
;
344 VM_CONTEXT
*mVmPtr
= NULL
;
347 Check whether the emulator supports executing a certain PE/COFF image
349 @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
351 @param[in] ImageType Whether the image is an application, a boot time
352 driver or a runtime driver.
353 @param[in] DevicePath Path to device where the image originated
354 (e.g., a PCI option ROM)
356 @retval TRUE The image is supported by the emulator
357 @retval FALSE The image is not supported by the emulator.
361 EbcIsImageSupported (
362 IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
*This
,
364 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath OPTIONAL
367 if (ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
&&
368 ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
) {
375 Register a supported PE/COFF image with the emulator. After this call
376 completes successfully, the PE/COFF image may be started as usual, and
377 it is the responsibility of the emulator implementation that any branch
378 into the code section of the image (including returns from functions called
379 from the foreign code) is executed as if it were running on the machine
380 type it was built for.
382 @param[in] This This pointer for
383 EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL structure
384 @param[in] ImageBase The base address in memory of the PE/COFF image
385 @param[in] ImageSize The size in memory of the PE/COFF image
386 @param[in,out] EntryPoint The entry point of the PE/COFF image. Passed by
387 reference so that the emulator may modify it.
389 @retval EFI_SUCCESS The image was registered with the emulator and
390 can be started as usual.
391 @retval other The image could not be registered.
393 If the PE/COFF machine type or image type are not supported by the emulator,
399 IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
*This
,
400 IN EFI_PHYSICAL_ADDRESS ImageBase
,
402 IN OUT EFI_IMAGE_ENTRY_POINT
*EntryPoint
406 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
409 ZeroMem (&ImageContext
, sizeof (ImageContext
));
411 ImageContext
.Handle
= (VOID
*)(UINTN
)ImageBase
;
412 ImageContext
.ImageRead
= PeCoffLoaderImageReadFromMemory
;
414 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
415 if (EFI_ERROR (Status
)) {
419 ASSERT (ImageContext
.Machine
== EFI_IMAGE_MACHINE_EBC
);
420 ASSERT (ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
||
421 ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
);
424 EbcRegisterICacheFlush (NULL
,
425 (EBC_ICACHE_FLUSH
)InvalidateInstructionCacheRange
);
427 return EbcCreateThunk (NULL
, (VOID
*)(UINTN
)ImageBase
,
428 (VOID
*)(UINTN
)*EntryPoint
, (VOID
**)EntryPoint
);
432 Unregister a PE/COFF image that has been registered with the emulator.
433 This should be done before the image is unloaded from memory.
435 @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
437 @param[in] ImageBase The base address in memory of the PE/COFF image
439 @retval EFI_SUCCESS The image was unregistered with the emulator.
440 @retval other Image could not be unloaded.
445 IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
*This
,
446 IN EFI_PHYSICAL_ADDRESS ImageBase
449 return EbcUnloadImage (NULL
, (VOID
*)(UINTN
)ImageBase
);
452 STATIC EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL mPeCoffEmuProtocol
= {
456 EDKII_PECOFF_IMAGE_EMULATOR_VERSION
,
457 EFI_IMAGE_MACHINE_EBC
461 Initializes the VM EFI interface. Allocates memory for the VM interface
462 and registers the VM protocol.
464 @param ImageHandle EFI image handle.
465 @param SystemTable Pointer to the EFI system table.
467 @return Standard EFI status code.
472 InitializeEbcDriver (
473 IN EFI_HANDLE ImageHandle
,
474 IN EFI_SYSTEM_TABLE
*SystemTable
477 EFI_EBC_PROTOCOL
*EbcProtocol
;
478 EFI_EBC_PROTOCOL
*OldEbcProtocol
;
480 EFI_DEBUG_SUPPORT_PROTOCOL
*EbcDebugProtocol
;
481 EFI_HANDLE
*HandleBuffer
;
487 EbcDebugProtocol
= NULL
;
490 // Allocate memory for our protocol. Then fill in the blanks.
492 EbcProtocol
= AllocatePool (sizeof (EFI_EBC_PROTOCOL
));
494 if (EbcProtocol
== NULL
) {
495 return EFI_OUT_OF_RESOURCES
;
498 EbcProtocol
->CreateThunk
= EbcCreateThunk
;
499 EbcProtocol
->UnloadImage
= EbcUnloadImage
;
500 EbcProtocol
->RegisterICacheFlush
= EbcRegisterICacheFlush
;
501 EbcProtocol
->GetVersion
= EbcGetVersion
;
502 mEbcICacheFlush
= NULL
;
505 // Find any already-installed EBC protocols and uninstall them
509 Status
= gBS
->LocateHandleBuffer (
511 &gEfiEbcProtocolGuid
,
516 if (Status
== EFI_SUCCESS
) {
518 // Loop through the handles
520 for (Index
= 0; Index
< NumHandles
; Index
++) {
521 Status
= gBS
->HandleProtocol (
523 &gEfiEbcProtocolGuid
,
524 (VOID
**) &OldEbcProtocol
526 if (Status
== EFI_SUCCESS
) {
527 if (gBS
->ReinstallProtocolInterface (
529 &gEfiEbcProtocolGuid
,
539 if (HandleBuffer
!= NULL
) {
540 FreePool (HandleBuffer
);
544 // Add the protocol so someone can locate us if we haven't already.
547 Status
= gBS
->InstallMultipleProtocolInterfaces (
549 &gEfiEbcProtocolGuid
, EbcProtocol
,
550 &gEdkiiPeCoffImageEmulatorProtocolGuid
, &mPeCoffEmuProtocol
,
553 if (EFI_ERROR (Status
)) {
554 FreePool (EbcProtocol
);
559 Status
= InitEBCStack();
560 if (EFI_ERROR(Status
)) {
565 // Allocate memory for our debug protocol. Then fill in the blanks.
567 EbcDebugProtocol
= AllocatePool (sizeof (EFI_DEBUG_SUPPORT_PROTOCOL
));
569 if (EbcDebugProtocol
== NULL
) {
573 EbcDebugProtocol
->Isa
= IsaEbc
;
574 EbcDebugProtocol
->GetMaximumProcessorIndex
= EbcDebugGetMaximumProcessorIndex
;
575 EbcDebugProtocol
->RegisterPeriodicCallback
= EbcDebugRegisterPeriodicCallback
;
576 EbcDebugProtocol
->RegisterExceptionCallback
= EbcDebugRegisterExceptionCallback
;
577 EbcDebugProtocol
->InvalidateInstructionCache
= EbcDebugInvalidateInstructionCache
;
580 // Add the protocol so the debug agent can find us
582 Status
= gBS
->InstallProtocolInterface (
584 &gEfiDebugSupportProtocolGuid
,
585 EFI_NATIVE_INTERFACE
,
589 // This is recoverable, so free the memory and continue.
591 if (EFI_ERROR (Status
)) {
592 FreePool (EbcDebugProtocol
);
596 // Install EbcDebugSupport Protocol Successfully
597 // Now we need to initialize the Ebc default Callback
599 Status
= InitializeEbcCallback (EbcDebugProtocol
);
602 // Produce a VM test interface protocol. Not required for execution.
605 InitEbcVmTestProtocol (&ImageHandle
);
608 EbcDebuggerHookInit (ImageHandle
, EbcDebugProtocol
);
615 Status
= gBS
->LocateHandleBuffer (
617 &gEfiEbcProtocolGuid
,
622 if (Status
== EFI_SUCCESS
) {
624 // Loop through the handles
626 for (Index
= 0; Index
< NumHandles
; Index
++) {
627 Status
= gBS
->HandleProtocol (
629 &gEfiEbcProtocolGuid
,
630 (VOID
**) &OldEbcProtocol
632 if (Status
== EFI_SUCCESS
) {
633 gBS
->UninstallProtocolInterface (
635 &gEfiEbcProtocolGuid
,
642 if (HandleBuffer
!= NULL
) {
643 FreePool (HandleBuffer
);
647 FreePool (EbcProtocol
);
654 This is the top-level routine plugged into the EBC protocol. Since thunks
655 are very processor-specific, from here we dispatch directly to the very
656 processor-specific routine EbcCreateThunks().
658 @param This A pointer to the EFI_EBC_PROTOCOL instance.
659 @param ImageHandle Handle of image for which the thunk is being
660 created. The EBC interpreter may use this to
661 keep track of any resource allocations
662 performed in loading and executing the image.
663 @param EbcEntryPoint Address of the actual EBC entry point or
664 protocol service the thunk should call.
665 @param Thunk Returned pointer to a thunk created.
667 @retval EFI_SUCCESS The function completed successfully.
668 @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
669 @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk.
675 IN EFI_EBC_PROTOCOL
*This
,
676 IN EFI_HANDLE ImageHandle
,
677 IN VOID
*EbcEntryPoint
,
683 Status
= EbcCreateThunks (
687 FLAG_THUNK_ENTRY_POINT
694 This EBC debugger protocol service is called by the debug agent
696 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
698 @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
699 maximum supported processor index is returned.
701 @retval EFI_SUCCESS The function completed successfully.
706 EbcDebugGetMaximumProcessorIndex (
707 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
708 OUT UINTN
*MaxProcessorIndex
711 *MaxProcessorIndex
= 0;
717 This protocol service is called by the debug agent to register a function
718 for us to call on a periodic basis.
720 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
722 @param ProcessorIndex Specifies which processor the callback function
724 @param PeriodicCallback A pointer to a function of type
725 PERIODIC_CALLBACK that is the main periodic
726 entry point of the debug agent. It receives as a
727 parameter a pointer to the full context of the
728 interrupted execution thread.
730 @retval EFI_SUCCESS The function completed successfully.
731 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
732 callback function was previously registered.
733 @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
734 callback function was previously registered.
739 EbcDebugRegisterPeriodicCallback (
740 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
741 IN UINTN ProcessorIndex
,
742 IN EFI_PERIODIC_CALLBACK PeriodicCallback
745 if ((mDebugPeriodicCallback
== NULL
) && (PeriodicCallback
== NULL
)) {
746 return EFI_INVALID_PARAMETER
;
748 if ((mDebugPeriodicCallback
!= NULL
) && (PeriodicCallback
!= NULL
)) {
749 return EFI_ALREADY_STARTED
;
752 mDebugPeriodicCallback
= PeriodicCallback
;
758 This protocol service is called by the debug agent to register a function
759 for us to call when we detect an exception.
761 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
763 @param ProcessorIndex Specifies which processor the callback function
765 @param ExceptionCallback A pointer to a function of type
766 EXCEPTION_CALLBACK that is called when the
767 processor exception specified by ExceptionType
768 occurs. Passing NULL unregisters any previously
769 registered function associated with
771 @param ExceptionType Specifies which processor exception to hook.
773 @retval EFI_SUCCESS The function completed successfully.
774 @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
775 callback function was previously registered.
776 @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
778 @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
779 callback function was previously registered.
784 EbcDebugRegisterExceptionCallback (
785 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
786 IN UINTN ProcessorIndex
,
787 IN EFI_EXCEPTION_CALLBACK ExceptionCallback
,
788 IN EFI_EXCEPTION_TYPE ExceptionType
791 if ((ExceptionType
< 0) || (ExceptionType
> MAX_EBC_EXCEPTION
)) {
792 return EFI_INVALID_PARAMETER
;
794 if ((mDebugExceptionCallback
[ExceptionType
] == NULL
) && (ExceptionCallback
== NULL
)) {
795 return EFI_INVALID_PARAMETER
;
797 if ((mDebugExceptionCallback
[ExceptionType
] != NULL
) && (ExceptionCallback
!= NULL
)) {
798 return EFI_ALREADY_STARTED
;
800 mDebugExceptionCallback
[ExceptionType
] = ExceptionCallback
;
806 This EBC debugger protocol service is called by the debug agent. Required
807 for DebugSupport compliance but is only stubbed out for EBC.
809 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
811 @param ProcessorIndex Specifies which processor the callback function
813 @param Start StartSpecifies the physical base of the memory
814 range to be invalidated.
815 @param Length Specifies the minimum number of bytes in the
816 processor's instruction cache to invalidate.
818 @retval EFI_SUCCESS The function completed successfully.
823 EbcDebugInvalidateInstructionCache (
824 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
825 IN UINTN ProcessorIndex
,
835 The VM interpreter calls this function when an exception is detected.
837 @param ExceptionType Specifies the processor exception detected.
838 @param ExceptionFlags Specifies the exception context.
839 @param VmPtr Pointer to a VM context for passing info to the
842 @retval EFI_SUCCESS This function completed successfully.
846 EbcDebugSignalException (
847 IN EFI_EXCEPTION_TYPE ExceptionType
,
848 IN EXCEPTION_FLAGS ExceptionFlags
,
852 EFI_SYSTEM_CONTEXT_EBC EbcContext
;
853 EFI_SYSTEM_CONTEXT SystemContext
;
855 ASSERT ((ExceptionType
>= 0) && (ExceptionType
<= MAX_EBC_EXCEPTION
));
857 // Save the exception in the context passed in
859 VmPtr
->ExceptionFlags
|= ExceptionFlags
;
860 VmPtr
->LastException
= (UINTN
) ExceptionType
;
862 // If it's a fatal exception, then flag it in the VM context in case an
863 // attached debugger tries to return from it.
865 if ((ExceptionFlags
& EXCEPTION_FLAG_FATAL
) != 0) {
866 VmPtr
->StopFlags
|= STOPFLAG_APP_DONE
;
870 // If someone's registered for exception callbacks, then call them.
872 // EBC driver will register default exception callback to report the
873 // status code via the status code API
875 if (mDebugExceptionCallback
[ExceptionType
] != NULL
) {
878 // Initialize the context structure
880 EbcContext
.R0
= (UINT64
) VmPtr
->Gpr
[0];
881 EbcContext
.R1
= (UINT64
) VmPtr
->Gpr
[1];
882 EbcContext
.R2
= (UINT64
) VmPtr
->Gpr
[2];
883 EbcContext
.R3
= (UINT64
) VmPtr
->Gpr
[3];
884 EbcContext
.R4
= (UINT64
) VmPtr
->Gpr
[4];
885 EbcContext
.R5
= (UINT64
) VmPtr
->Gpr
[5];
886 EbcContext
.R6
= (UINT64
) VmPtr
->Gpr
[6];
887 EbcContext
.R7
= (UINT64
) VmPtr
->Gpr
[7];
888 EbcContext
.Ip
= (UINT64
)(UINTN
)VmPtr
->Ip
;
889 EbcContext
.Flags
= VmPtr
->Flags
;
890 EbcContext
.ControlFlags
= 0;
891 SystemContext
.SystemContextEbc
= &EbcContext
;
893 mDebugExceptionCallback
[ExceptionType
] (ExceptionType
, SystemContext
);
895 // Restore the context structure and continue to execute
897 VmPtr
->Gpr
[0] = EbcContext
.R0
;
898 VmPtr
->Gpr
[1] = EbcContext
.R1
;
899 VmPtr
->Gpr
[2] = EbcContext
.R2
;
900 VmPtr
->Gpr
[3] = EbcContext
.R3
;
901 VmPtr
->Gpr
[4] = EbcContext
.R4
;
902 VmPtr
->Gpr
[5] = EbcContext
.R5
;
903 VmPtr
->Gpr
[6] = EbcContext
.R6
;
904 VmPtr
->Gpr
[7] = EbcContext
.R7
;
905 VmPtr
->Ip
= (VMIP
)(UINTN
)EbcContext
.Ip
;
906 VmPtr
->Flags
= EbcContext
.Flags
;
914 To install default Callback function for the VM interpreter.
916 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
919 @retval EFI_SUCCESS The function completed successfully.
920 @retval Others Some error occurs when creating periodic event.
925 InitializeEbcCallback (
926 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
933 // For ExceptionCallback
935 for (Index
= 0; Index
<= MAX_EBC_EXCEPTION
; Index
++) {
936 EbcDebugRegisterExceptionCallback (
939 CommonEbcExceptionHandler
,
945 // For PeriodicCallback
947 Status
= gBS
->CreateEvent (
948 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
950 EbcPeriodicNotifyFunction
,
954 if (EFI_ERROR(Status
)) {
958 Status
= gBS
->SetTimer (
961 EBC_VM_PERIODIC_CALLBACK_RATE
963 if (EFI_ERROR(Status
)) {
972 The default Exception Callback for the VM interpreter.
973 In this function, we report status code, and print debug information
974 about EBC_CONTEXT, then dead loop.
976 @param InterruptType Interrupt type.
977 @param SystemContext EBC system context.
982 CommonEbcExceptionHandler (
983 IN EFI_EXCEPTION_TYPE InterruptType
,
984 IN EFI_SYSTEM_CONTEXT SystemContext
988 // We print debug information to let user know what happen.
992 "EBC Interrupter Version - 0x%016lx\n",
993 (UINT64
) (((VM_MAJOR_VERSION
& 0xFFFF) << 16) | ((VM_MINOR_VERSION
& 0xFFFF)))
997 "Exception Type - 0x%016lx\n",
998 (UINT64
)(UINTN
)InterruptType
1002 " R0 - 0x%016lx, R1 - 0x%016lx\n",
1003 SystemContext
.SystemContextEbc
->R0
,
1004 SystemContext
.SystemContextEbc
->R1
1008 " R2 - 0x%016lx, R3 - 0x%016lx\n",
1009 SystemContext
.SystemContextEbc
->R2
,
1010 SystemContext
.SystemContextEbc
->R3
1014 " R4 - 0x%016lx, R5 - 0x%016lx\n",
1015 SystemContext
.SystemContextEbc
->R4
,
1016 SystemContext
.SystemContextEbc
->R5
1020 " R6 - 0x%016lx, R7 - 0x%016lx\n",
1021 SystemContext
.SystemContextEbc
->R6
,
1022 SystemContext
.SystemContextEbc
->R7
1026 " Flags - 0x%016lx\n",
1027 SystemContext
.SystemContextEbc
->Flags
1031 " ControlFlags - 0x%016lx\n",
1032 SystemContext
.SystemContextEbc
->ControlFlags
1036 " Ip - 0x%016lx\n\n",
1037 SystemContext
.SystemContextEbc
->Ip
1041 // We deadloop here to make it easy to debug this issue.
1050 The periodic callback function for EBC VM interpreter, which is used
1051 to support the EFI debug support protocol.
1053 @param Event The Periodic Callback Event.
1054 @param Context It should be the address of VM_CONTEXT pointer.
1059 EbcPeriodicNotifyFunction (
1066 VmPtr
= *(VM_CONTEXT
**)Context
;
1068 if (VmPtr
!= NULL
) {
1069 EbcDebugPeriodic (VmPtr
);
1077 The VM interpreter calls this function on a periodic basis to support
1078 the EFI debug support protocol.
1080 @param VmPtr Pointer to a VM context for passing info to the
1083 @retval EFI_SUCCESS The function completed successfully.
1089 IN VM_CONTEXT
*VmPtr
1092 EFI_SYSTEM_CONTEXT_EBC EbcContext
;
1093 EFI_SYSTEM_CONTEXT SystemContext
;
1096 // If someone's registered for periodic callbacks, then call them.
1098 if (mDebugPeriodicCallback
!= NULL
) {
1101 // Initialize the context structure
1103 EbcContext
.R0
= (UINT64
) VmPtr
->Gpr
[0];
1104 EbcContext
.R1
= (UINT64
) VmPtr
->Gpr
[1];
1105 EbcContext
.R2
= (UINT64
) VmPtr
->Gpr
[2];
1106 EbcContext
.R3
= (UINT64
) VmPtr
->Gpr
[3];
1107 EbcContext
.R4
= (UINT64
) VmPtr
->Gpr
[4];
1108 EbcContext
.R5
= (UINT64
) VmPtr
->Gpr
[5];
1109 EbcContext
.R6
= (UINT64
) VmPtr
->Gpr
[6];
1110 EbcContext
.R7
= (UINT64
) VmPtr
->Gpr
[7];
1111 EbcContext
.Ip
= (UINT64
)(UINTN
)VmPtr
->Ip
;
1112 EbcContext
.Flags
= VmPtr
->Flags
;
1113 EbcContext
.ControlFlags
= 0;
1114 SystemContext
.SystemContextEbc
= &EbcContext
;
1116 mDebugPeriodicCallback (SystemContext
);
1119 // Restore the context structure and continue to execute
1121 VmPtr
->Gpr
[0] = EbcContext
.R0
;
1122 VmPtr
->Gpr
[1] = EbcContext
.R1
;
1123 VmPtr
->Gpr
[2] = EbcContext
.R2
;
1124 VmPtr
->Gpr
[3] = EbcContext
.R3
;
1125 VmPtr
->Gpr
[4] = EbcContext
.R4
;
1126 VmPtr
->Gpr
[5] = EbcContext
.R5
;
1127 VmPtr
->Gpr
[6] = EbcContext
.R6
;
1128 VmPtr
->Gpr
[7] = EbcContext
.R7
;
1129 VmPtr
->Ip
= (VMIP
)(UINTN
)EbcContext
.Ip
;
1130 VmPtr
->Flags
= EbcContext
.Flags
;
1138 This routine is called by the core when an image is being unloaded from
1139 memory. Basically we now have the opportunity to do any necessary cleanup.
1140 Typically this will include freeing any memory allocated for thunk-creation.
1142 @param This A pointer to the EFI_EBC_PROTOCOL instance.
1143 @param ImageHandle Handle of image for which the thunk is being
1146 @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
1147 internal list of EBC image handles.
1148 @retval EFI_SUCCESS The function completed successfully.
1154 IN EFI_EBC_PROTOCOL
*This
,
1155 IN EFI_HANDLE ImageHandle
1158 EBC_THUNK_LIST
*ThunkList
;
1159 EBC_THUNK_LIST
*NextThunkList
;
1160 EBC_IMAGE_LIST
*ImageList
;
1161 EBC_IMAGE_LIST
*PrevImageList
;
1163 // First go through our list of known image handles and see if we've already
1164 // created an image list element for this image handle.
1166 ReturnEBCStackByHandle(ImageHandle
);
1167 PrevImageList
= NULL
;
1168 for (ImageList
= mEbcImageList
; ImageList
!= NULL
; ImageList
= ImageList
->Next
) {
1169 if (ImageList
->ImageHandle
== ImageHandle
) {
1173 // Save the previous so we can connect the lists when we remove this one
1175 PrevImageList
= ImageList
;
1178 if (ImageList
== NULL
) {
1179 return EFI_INVALID_PARAMETER
;
1182 // Free up all the thunk buffers and thunks list elements for this image
1185 ThunkList
= ImageList
->ThunkList
;
1186 while (ThunkList
!= NULL
) {
1187 NextThunkList
= ThunkList
->Next
;
1188 FreePool (ThunkList
->ThunkBuffer
);
1189 FreePool (ThunkList
);
1190 ThunkList
= NextThunkList
;
1193 // Now remove this image list element from the chain
1195 if (PrevImageList
== NULL
) {
1199 mEbcImageList
= ImageList
->Next
;
1201 PrevImageList
->Next
= ImageList
->Next
;
1204 // Now free up the image list element
1206 FreePool (ImageList
);
1208 EbcDebuggerHookEbcUnloadImage (ImageHandle
);
1215 Add a thunk to our list of thunks for a given image handle.
1216 Also flush the instruction cache since we've written thunk code
1217 to memory that will be executed eventually.
1219 @param ImageHandle The image handle to which the thunk is tied.
1220 @param ThunkBuffer The buffer that has been created/allocated.
1221 @param ThunkSize The size of the thunk memory allocated.
1223 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1224 @retval EFI_SUCCESS The function completed successfully.
1229 IN EFI_HANDLE ImageHandle
,
1230 IN VOID
*ThunkBuffer
,
1234 EBC_THUNK_LIST
*ThunkList
;
1235 EBC_IMAGE_LIST
*ImageList
;
1239 // It so far so good, then flush the instruction cache
1241 if (mEbcICacheFlush
!= NULL
) {
1242 Status
= mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS
) (UINTN
) ThunkBuffer
, ThunkSize
);
1243 if (EFI_ERROR (Status
)) {
1248 // Go through our list of known image handles and see if we've already
1249 // created a image list element for this image handle.
1251 for (ImageList
= mEbcImageList
; ImageList
!= NULL
; ImageList
= ImageList
->Next
) {
1252 if (ImageList
->ImageHandle
== ImageHandle
) {
1257 if (ImageList
== NULL
) {
1259 // Allocate a new one
1261 ImageList
= AllocatePool (sizeof (EBC_IMAGE_LIST
));
1263 if (ImageList
== NULL
) {
1264 return EFI_OUT_OF_RESOURCES
;
1267 ImageList
->ThunkList
= NULL
;
1268 ImageList
->ImageHandle
= ImageHandle
;
1269 ImageList
->Next
= mEbcImageList
;
1270 mEbcImageList
= ImageList
;
1273 // Ok, now create a new thunk element to add to the list
1275 ThunkList
= AllocatePool (sizeof (EBC_THUNK_LIST
));
1277 if (ThunkList
== NULL
) {
1278 return EFI_OUT_OF_RESOURCES
;
1281 // Add it to the head of the list
1283 ThunkList
->Next
= ImageList
->ThunkList
;
1284 ThunkList
->ThunkBuffer
= ThunkBuffer
;
1285 ImageList
->ThunkList
= ThunkList
;
1290 Registers a callback function that the EBC interpreter calls to flush the
1291 processor instruction cache following creation of thunks.
1293 @param This A pointer to the EFI_EBC_PROTOCOL instance.
1294 @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
1296 @retval EFI_SUCCESS The function completed successfully.
1301 EbcRegisterICacheFlush (
1302 IN EFI_EBC_PROTOCOL
*This
,
1303 IN EBC_ICACHE_FLUSH Flush
1306 mEbcICacheFlush
= Flush
;
1311 Called to get the version of the interpreter.
1313 @param This A pointer to the EFI_EBC_PROTOCOL instance.
1314 @param Version Pointer to where to store the returned version
1317 @retval EFI_SUCCESS The function completed successfully.
1318 @retval EFI_INVALID_PARAMETER Version pointer is NULL.
1324 IN EFI_EBC_PROTOCOL
*This
,
1325 IN OUT UINT64
*Version
1328 if (Version
== NULL
) {
1329 return EFI_INVALID_PARAMETER
;
1332 *Version
= GetVmVersion ();
1337 Returns the stack index and buffer assosicated with the Handle parameter.
1339 @param Handle The EFI handle as the index to the EBC stack.
1340 @param StackBuffer A pointer to hold the returned stack buffer.
1341 @param BufferIndex A pointer to hold the returned stack index.
1343 @retval EFI_OUT_OF_RESOURCES The Handle parameter does not correspond to any
1345 @retval EFI_SUCCESS The stack index and buffer were found and
1346 returned to the caller.
1351 IN EFI_HANDLE Handle
,
1352 OUT VOID
**StackBuffer
,
1353 OUT UINTN
*BufferIndex
1358 OldTpl
= gBS
->RaiseTPL(TPL_HIGH_LEVEL
);
1359 for (Index
= 0; Index
< mStackNum
; Index
++) {
1360 if (mStackBufferIndex
[Index
] == NULL
) {
1361 mStackBufferIndex
[Index
] = Handle
;
1365 gBS
->RestoreTPL(OldTpl
);
1366 if (Index
== mStackNum
) {
1367 return EFI_OUT_OF_RESOURCES
;
1369 *BufferIndex
= Index
;
1370 *StackBuffer
= mStackBuffer
[Index
];
1375 Returns from the EBC stack by stack Index.
1377 @param Index Specifies which EBC stack to return from.
1379 @retval EFI_SUCCESS The function completed successfully.
1387 mStackBufferIndex
[Index
] = NULL
;
1392 Returns from the EBC stack associated with the Handle parameter.
1394 @param Handle Specifies the EFI handle to find the EBC stack with.
1396 @retval EFI_SUCCESS The function completed successfully.
1400 ReturnEBCStackByHandle(
1401 IN EFI_HANDLE Handle
1405 for (Index
= 0; Index
< mStackNum
; Index
++) {
1406 if (mStackBufferIndex
[Index
] == Handle
) {
1410 if (Index
== mStackNum
) {
1411 return EFI_NOT_FOUND
;
1413 mStackBufferIndex
[Index
] = NULL
;
1418 Allocates memory to hold all the EBC stacks.
1420 @retval EFI_SUCCESS The EBC stacks were allocated successfully.
1421 @retval EFI_OUT_OF_RESOURCES Not enough memory available for EBC stacks.
1429 for (mStackNum
= 0; mStackNum
< MAX_STACK_NUM
; mStackNum
++) {
1430 mStackBuffer
[mStackNum
] = AllocatePool(STACK_POOL_SIZE
);
1431 mStackBufferIndex
[mStackNum
] = NULL
;
1432 if (mStackBuffer
[mStackNum
] == NULL
) {
1436 if (mStackNum
== 0) {
1437 return EFI_OUT_OF_RESOURCES
;
1444 Free all EBC stacks allocated before.
1446 @retval EFI_SUCCESS All the EBC stacks were freed.
1455 for (Index
= 0; Index
< mStackNum
; Index
++) {
1456 FreePool(mStackBuffer
[Index
]);
1462 Produces an EBC VM test protocol that can be used for regression tests.
1464 @param IHandle Handle on which to install the protocol.
1466 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1467 @retval EFI_SUCCESS The function completed successfully.
1471 InitEbcVmTestProtocol (
1472 IN EFI_HANDLE
*IHandle
1477 EFI_EBC_VM_TEST_PROTOCOL
*EbcVmTestProtocol
;
1480 // Allocate memory for the protocol, then fill in the fields
1482 EbcVmTestProtocol
= AllocatePool (sizeof (EFI_EBC_VM_TEST_PROTOCOL
));
1483 if (EbcVmTestProtocol
== NULL
) {
1484 return EFI_OUT_OF_RESOURCES
;
1486 EbcVmTestProtocol
->Execute
= (EBC_VM_TEST_EXECUTE
) EbcExecuteInstructions
;
1488 DEBUG_CODE_BEGIN ();
1489 EbcVmTestProtocol
->Assemble
= (EBC_VM_TEST_ASM
) EbcVmTestUnsupported
;
1490 EbcVmTestProtocol
->Disassemble
= (EBC_VM_TEST_DASM
) EbcVmTestUnsupported
;
1494 // Publish the protocol
1497 Status
= gBS
->InstallProtocolInterface (&Handle
, &gEfiEbcVmTestProtocolGuid
, EFI_NATIVE_INTERFACE
, EbcVmTestProtocol
);
1498 if (EFI_ERROR (Status
)) {
1499 FreePool (EbcVmTestProtocol
);
1506 Returns the EFI_UNSUPPORTED Status.
1508 @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
1513 EbcVmTestUnsupported (
1517 return EFI_UNSUPPORTED
;
1521 Allocates a buffer of type EfiBootServicesCode.
1523 @param AllocationSize The number of bytes to allocate.
1525 @return A pointer to the allocated buffer or NULL if allocation fails.
1530 EbcAllocatePoolForThunk (
1531 IN UINTN AllocationSize
1537 Status
= gBS
->AllocatePool (EfiBootServicesCode
, AllocationSize
, &Buffer
);
1538 if (EFI_ERROR (Status
)) {