IN OUT UINT64 *Version\r
);\r
\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeEbcCallback (\r
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This\r
+ );\r
+\r
+VOID\r
+EFIAPI\r
+CommonEbcExceptionHandler (\r
+ IN EFI_EXCEPTION_TYPE InterruptType,\r
+ IN EFI_SYSTEM_CONTEXT SystemContext\r
+ );\r
+\r
+VOID\r
+EFIAPI\r
+EbcPeriodicNotifyFunction (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+EbcDebugPeriodic (\r
+ IN VM_CONTEXT *VmPtr\r
+ );\r
+\r
//\r
// These two functions and the GUID are used to produce an EBC test protocol.\r
// This functionality is definitely not required for execution.\r
static EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = {NULL};\r
static EFI_GUID mEfiEbcVmTestProtocolGuid = EFI_EBC_VM_TEST_PROTOCOL_GUID;\r
\r
+//\r
+// Event for Periodic callback\r
+//\r
+static EFI_EVENT mEbcPeriodicEvent;\r
+VM_CONTEXT *mVmPtr = NULL;\r
+\r
EFI_STATUS\r
EFIAPI\r
InitializeEbcDriver (\r
UINTN Index;\r
BOOLEAN Installed;\r
\r
+ EbcProtocol = NULL;\r
+ EbcDebugProtocol = NULL;\r
+\r
//\r
// Allocate memory for our protocol. Then fill in the blanks.\r
//\r
(VOID **) &EbcDebugProtocol\r
);\r
if (Status != EFI_SUCCESS) {\r
- return EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
}\r
\r
EbcDebugProtocol->Isa = IsaEbc;\r
//\r
if (EFI_ERROR (Status)) {\r
gBS->FreePool (EbcDebugProtocol);\r
+ goto ErrorExit;\r
}\r
+ //\r
+ // Install EbcDebugSupport Protocol Successfully\r
+ // Now we need to initialize the Ebc default Callback\r
+ //\r
+ Status = InitializeEbcCallback (EbcDebugProtocol);\r
+\r
//\r
// Produce a VM test interface protocol. Not required for execution.\r
//\r
InitEbcVmTestProtocol (&ImageHandle);\r
DEBUG_CODE_END ();\r
\r
+ return EFI_SUCCESS;\r
+\r
+ErrorExit:\r
+ HandleBuffer = NULL;\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiEbcProtocolGuid,\r
+ NULL,\r
+ &NumHandles,\r
+ &HandleBuffer\r
+ );\r
+ if (Status == EFI_SUCCESS) {\r
+ //\r
+ // Loop through the handles\r
+ //\r
+ for (Index = 0; Index < NumHandles; Index++) {\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiEbcProtocolGuid,\r
+ (VOID **) &OldEbcProtocol\r
+ );\r
+ if (Status == EFI_SUCCESS) {\r
+ gBS->UninstallProtocolInterface (\r
+ HandleBuffer[Index],\r
+ &gEfiEbcProtocolGuid,\r
+ OldEbcProtocol\r
+ );\r
+ }\r
+ }\r
+ }\r
+\r
+ if (HandleBuffer != NULL) {\r
+ gBS->FreePool (HandleBuffer);\r
+ HandleBuffer = NULL;\r
+ }\r
+\r
+ gBS->FreePool (EbcProtocol);\r
+\r
return Status;\r
}\r
\r
{\r
EFI_SYSTEM_CONTEXT_EBC EbcContext;\r
EFI_SYSTEM_CONTEXT SystemContext;\r
- EFI_STATUS_CODE_VALUE StatusCodeValue;\r
- BOOLEAN Report;\r
+\r
+ ASSERT ((ExceptionType >= 0) && (ExceptionType <= MAX_EBC_EXCEPTION));\r
//\r
// Save the exception in the context passed in\r
//\r
if (ExceptionFlags & EXCEPTION_FLAG_FATAL) {\r
VmPtr->StopFlags |= STOPFLAG_APP_DONE;\r
}\r
- //\r
- // Initialize the context structure\r
- //\r
- EbcContext.R0 = VmPtr->R[0];\r
- EbcContext.R1 = VmPtr->R[1];\r
- EbcContext.R2 = VmPtr->R[2];\r
- EbcContext.R3 = VmPtr->R[3];\r
- EbcContext.R4 = VmPtr->R[4];\r
- EbcContext.R5 = VmPtr->R[5];\r
- EbcContext.R6 = VmPtr->R[6];\r
- EbcContext.R7 = VmPtr->R[7];\r
- EbcContext.Ip = (UINT64) (UINTN) VmPtr->Ip;\r
- EbcContext.Flags = VmPtr->Flags;\r
- EbcContext.ControlFlags = 0;\r
- SystemContext.SystemContextEbc = &EbcContext;\r
+\r
//\r
// If someone's registered for exception callbacks, then call them.\r
- // Otherwise report the status code via the status code API\r
//\r
- if ((ExceptionType >= 0) && (ExceptionType <= MAX_EBC_EXCEPTION) &&\r
- (mDebugExceptionCallback[ExceptionType] != NULL)) {\r
+ // EBC driver will register default exception callback to report the\r
+ // status code via the status code API\r
+ //\r
+ if (mDebugExceptionCallback[ExceptionType] != NULL) {\r
+\r
+ //\r
+ // Initialize the context structure\r
+ //\r
+ EbcContext.R0 = VmPtr->R[0];\r
+ EbcContext.R1 = VmPtr->R[1];\r
+ EbcContext.R2 = VmPtr->R[2];\r
+ EbcContext.R3 = VmPtr->R[3];\r
+ EbcContext.R4 = VmPtr->R[4];\r
+ EbcContext.R5 = VmPtr->R[5];\r
+ EbcContext.R6 = VmPtr->R[6];\r
+ EbcContext.R7 = VmPtr->R[7];\r
+ EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;\r
+ EbcContext.Flags = VmPtr->Flags;\r
+ EbcContext.ControlFlags = 0;\r
+ SystemContext.SystemContextEbc = &EbcContext;\r
+\r
mDebugExceptionCallback[ExceptionType] (ExceptionType, SystemContext);\r
+ //\r
+ // Restore the context structure and continue to execute\r
+ //\r
+ VmPtr->R[0] = EbcContext.R0;\r
+ VmPtr->R[1] = EbcContext.R1;\r
+ VmPtr->R[2] = EbcContext.R2;\r
+ VmPtr->R[3] = EbcContext.R3;\r
+ VmPtr->R[4] = EbcContext.R4;\r
+ VmPtr->R[5] = EbcContext.R5;\r
+ VmPtr->R[6] = EbcContext.R6;\r
+ VmPtr->R[7] = EbcContext.R7;\r
+ VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;\r
+ VmPtr->Flags = EbcContext.Flags;\r
}\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+InitializeEbcCallback (\r
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ To install default Callback function for the VM interpreter.\r
+ \r
+Arguments:\r
+\r
+ This - pointer to the instance of DebugSupport protocol\r
+\r
+Returns:\r
+\r
+ None\r
+ \r
+--*/\r
+{\r
+ INTN Index;\r
+ EFI_STATUS Status;\r
+\r
//\r
- // Determine if we should report the exception. We report all of them by default,\r
- // but if a debugger is attached don't report the breakpoint, debug, and step exceptions.\r
- // Note that EXCEPT_EBC_OVERFLOW is never reported by this VM implementation, so is\r
- // not included in the switch statement.\r
- //\r
- Report = TRUE;\r
- switch (ExceptionType) {\r
- case EXCEPT_EBC_UNDEFINED:\r
- StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_UNDEFINED;\r
- break;\r
-\r
- case EXCEPT_EBC_DIVIDE_ERROR:\r
- StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_DIVIDE_ERROR;\r
- break;\r
-\r
- case EXCEPT_EBC_DEBUG:\r
- StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_DEBUG;\r
- Report = (BOOLEAN) ((mDebugExceptionCallback[ExceptionType] == NULL) ? TRUE : FALSE);\r
- break;\r
-\r
- case EXCEPT_EBC_BREAKPOINT:\r
- StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_BREAKPOINT;\r
- Report = (BOOLEAN) ((mDebugExceptionCallback[ExceptionType] == NULL) ? TRUE : FALSE);\r
- break;\r
-\r
- case EXCEPT_EBC_INVALID_OPCODE:\r
- StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_INVALID_OPCODE;\r
- break;\r
-\r
- case EXCEPT_EBC_STACK_FAULT:\r
- StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_STACK_FAULT;\r
- break;\r
-\r
- case EXCEPT_EBC_ALIGNMENT_CHECK:\r
- StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_ALIGNMENT_CHECK;\r
- break;\r
-\r
- case EXCEPT_EBC_INSTRUCTION_ENCODING:\r
- StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_INSTRUCTION_ENCODING;\r
- break;\r
-\r
- case EXCEPT_EBC_BAD_BREAK:\r
- StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_BAD_BREAK;\r
- break;\r
-\r
- case EXCEPT_EBC_STEP:\r
- StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_STEP;\r
- Report = (BOOLEAN) ((mDebugExceptionCallback[ExceptionType] == NULL) ? TRUE : FALSE);\r
- break;\r
-\r
- default:\r
- StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_NON_SPECIFIC;\r
- break;\r
+ // For ExceptionCallback\r
+ //\r
+ for (Index = 0; Index <= MAX_EBC_EXCEPTION; Index++) {\r
+ EbcDebugRegisterExceptionCallback (\r
+ This,\r
+ 0,\r
+ CommonEbcExceptionHandler,\r
+ Index\r
+ );\r
}\r
+\r
//\r
- // If we determined that we should report the condition, then do so now.\r
+ // For PeriodicCallback\r
//\r
- if (Report) {\r
- REPORT_STATUS_CODE (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED, StatusCodeValue);\r
+ Status = gBS->CreateEvent (\r
+ EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,\r
+ EFI_TPL_NOTIFY,\r
+ EbcPeriodicNotifyFunction,\r
+ &mVmPtr,\r
+ &mEbcPeriodicEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
}\r
\r
- switch (ExceptionType) {\r
- //\r
- // If ReportStatusCode returned, then for most exceptions we do an assert. The\r
- // ExceptionType++ is done simply to force the ASSERT() condition to be met.\r
- // For breakpoints, assume a debugger did not insert a software breakpoint\r
- // and skip the instruction.\r
- //\r
- case EXCEPT_EBC_BREAKPOINT:\r
- VmPtr->Ip += 2;\r
- break;\r
-\r
- case EXCEPT_EBC_STEP:\r
- break;\r
-\r
- case EXCEPT_EBC_UNDEFINED:\r
- ExceptionType++;\r
- ASSERT (ExceptionType == EXCEPT_EBC_UNDEFINED);\r
- break;\r
-\r
- case EXCEPT_EBC_DIVIDE_ERROR:\r
- ExceptionType++;\r
- ASSERT (ExceptionType == EXCEPT_EBC_DIVIDE_ERROR);\r
- break;\r
-\r
- case EXCEPT_EBC_DEBUG:\r
- ExceptionType++;\r
- ASSERT (ExceptionType == EXCEPT_EBC_DEBUG);\r
- break;\r
-\r
- case EXCEPT_EBC_INVALID_OPCODE:\r
- ExceptionType++;\r
- ASSERT (ExceptionType == EXCEPT_EBC_INVALID_OPCODE);\r
- break;\r
-\r
- case EXCEPT_EBC_STACK_FAULT:\r
- ExceptionType++;\r
- ASSERT (ExceptionType == EXCEPT_EBC_STACK_FAULT);\r
- break;\r
-\r
- case EXCEPT_EBC_ALIGNMENT_CHECK:\r
- ExceptionType++;\r
- ASSERT (ExceptionType == EXCEPT_EBC_ALIGNMENT_CHECK);\r
- break;\r
-\r
- case EXCEPT_EBC_INSTRUCTION_ENCODING:\r
- ExceptionType++;\r
- ASSERT (ExceptionType == EXCEPT_EBC_INSTRUCTION_ENCODING);\r
- break;\r
-\r
- case EXCEPT_EBC_BAD_BREAK:\r
- ExceptionType++;\r
- ASSERT (ExceptionType == EXCEPT_EBC_BAD_BREAK);\r
- break;\r
-\r
- default:\r
- //\r
- // Unknown\r
- //\r
- ASSERT (0);\r
- break;\r
+ Status = gBS->SetTimer (\r
+ mEbcPeriodicEvent,\r
+ TimerPeriodic,\r
+ EBC_VM_PERIODIC_CALLBACK_RATE\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
}\r
\r
return EFI_SUCCESS;\r
}\r
\r
+VOID\r
+CommonEbcExceptionHandler (\r
+ IN EFI_EXCEPTION_TYPE InterruptType,\r
+ IN EFI_SYSTEM_CONTEXT SystemContext\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ The default Exception Callback for the VM interpreter.\r
+ In this function, we report status code, and print debug information\r
+ about EBC_CONTEXT, then dead loop.\r
+ \r
+Arguments:\r
+\r
+ InterruptType - Interrupt type.\r
+ SystemContext - EBC system context.\r
+\r
+Returns:\r
+\r
+ None\r
+ \r
+--*/\r
+{\r
+ //\r
+ // We deadloop here to make it easy to debug this issue.\r
+ //\r
+ ASSERT (FALSE);\r
+\r
+ return ;\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+EbcPeriodicNotifyFunction (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ The periodic callback function for EBC VM interpreter, which is used\r
+ to support the EFI debug support protocol.\r
+ \r
+Arguments:\r
+\r
+ Event - The Periodic Callback Event.\r
+ Context - It should be the address of VM_CONTEXT pointer.\r
+\r
+Returns:\r
+\r
+ None.\r
+ \r
+--*/\r
+{\r
+ VM_CONTEXT *VmPtr;\r
+\r
+ VmPtr = *(VM_CONTEXT **)Context;\r
+\r
+ if (VmPtr != NULL) {\r
+ EbcDebugPeriodic (VmPtr);\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+\r
EFI_STATUS\r
EbcDebugPeriodic (\r
IN VM_CONTEXT *VmPtr\r
\r
--*/\r
{\r
+ EFI_SYSTEM_CONTEXT_EBC EbcContext;\r
+ EFI_SYSTEM_CONTEXT SystemContext;\r
+ \r
+ //\r
+ // If someone's registered for periodic callbacks, then call them.\r
+ //\r
+ if (mDebugPeriodicCallback != NULL) {\r
+\r
+ //\r
+ // Initialize the context structure\r
+ //\r
+ EbcContext.R0 = VmPtr->R[0];\r
+ EbcContext.R1 = VmPtr->R[1];\r
+ EbcContext.R2 = VmPtr->R[2];\r
+ EbcContext.R3 = VmPtr->R[3];\r
+ EbcContext.R4 = VmPtr->R[4];\r
+ EbcContext.R5 = VmPtr->R[5];\r
+ EbcContext.R6 = VmPtr->R[6];\r
+ EbcContext.R7 = VmPtr->R[7];\r
+ EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;\r
+ EbcContext.Flags = VmPtr->Flags;\r
+ EbcContext.ControlFlags = 0;\r
+ SystemContext.SystemContextEbc = &EbcContext;\r
+\r
+ mDebugPeriodicCallback (SystemContext);\r
+\r
+ //\r
+ // Restore the context structure and continue to execute\r
+ //\r
+ VmPtr->R[0] = EbcContext.R0;\r
+ VmPtr->R[1] = EbcContext.R1;\r
+ VmPtr->R[2] = EbcContext.R2;\r
+ VmPtr->R[3] = EbcContext.R3;\r
+ VmPtr->R[4] = EbcContext.R4;\r
+ VmPtr->R[5] = EbcContext.R5;\r
+ VmPtr->R[6] = EbcContext.R6;\r
+ VmPtr->R[7] = EbcContext.R7;\r
+ VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;\r
+ VmPtr->Flags = EbcContext.Flags;\r
+ }\r
+ \r
return EFI_SUCCESS;\r
}\r
\r