/** @file\r
CPU Exception Library provides PEI/DXE/SMM CPU common exception handler.\r
\r
-Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials are licensed and made available under\r
-the terms and conditions of the BSD License that accompanies this distribution.\r
-The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php.\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
-#include "CpuExceptionCommon.h"\r
#include <Library/DebugLib.h>\r
-\r
-//\r
-// Spinlock for CPU information display\r
-//\r
-SPIN_LOCK mDisplayMessageSpinLock;\r
-\r
-//\r
-// Image align size for DXE/SMM\r
-//\r
-CONST UINTN mImageAlignSize = SIZE_4KB;\r
-\r
-RESERVED_VECTORS_DATA mReservedVectorsData[CPU_EXCEPTION_NUM];\r
-EFI_CPU_INTERRUPT_HANDLER mExternalInterruptHandlerTable[CPU_EXCEPTION_NUM];\r
-EFI_CPU_INTERRUPT_HANDLER *mExternalInterruptHandler = NULL;\r
-UINTN mEnabledInterruptNum = 0;\r
+#include <Library/VmgExitLib.h>\r
+#include "CpuExceptionCommon.h"\r
\r
/**\r
- Common exception handler.\r
+ Internal worker function for common exception handler.\r
\r
- @param ExceptionType Exception type.\r
- @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
+ @param ExceptionType Exception type.\r
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
+ @param ExceptionHandlerData Pointer to exception handler data.\r
**/\r
VOID\r
-EFIAPI\r
-CommonExceptionHandler (\r
- IN EFI_EXCEPTION_TYPE ExceptionType, \r
- IN EFI_SYSTEM_CONTEXT SystemContext\r
+CommonExceptionHandlerWorker (\r
+ IN EFI_EXCEPTION_TYPE ExceptionType,\r
+ IN EFI_SYSTEM_CONTEXT SystemContext,\r
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
)\r
{\r
- EXCEPTION_HANDLER_CONTEXT *ExceptionHandlerContext;\r
+ EXCEPTION_HANDLER_CONTEXT *ExceptionHandlerContext;\r
+ RESERVED_VECTORS_DATA *ReservedVectors;\r
+ EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;\r
\r
- ExceptionHandlerContext = (EXCEPTION_HANDLER_CONTEXT *) (UINTN) (SystemContext.SystemContextIa32);\r
-\r
- switch (mReservedVectors[ExceptionType].Attribute) {\r
- case EFI_VECTOR_HANDOFF_HOOK_BEFORE:\r
+ if (ExceptionType == VC_EXCEPTION) {\r
+ EFI_STATUS Status;\r
//\r
- // Need to jmp to old IDT handler after this exception handler\r
+ // #VC needs to be handled immediately upon enabling exception handling\r
+ // and therefore can't use the RegisterCpuInterruptHandler() interface.\r
//\r
- ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;\r
- ExceptionHandlerContext->OldIdtHandler = mReservedVectors[ExceptionType].ExceptonHandler;\r
- break;\r
- case EFI_VECTOR_HANDOFF_HOOK_AFTER:\r
- while (TRUE) {\r
- //\r
- // If if anyone has gotten SPIN_LOCK for owner running hook after\r
- //\r
- if (AcquireSpinLockOrFail (&mReservedVectors[ExceptionType].SpinLock)) {\r
- //\r
- // Need to execute old IDT handler before running this exception handler\r
- //\r
- mReservedVectors[ExceptionType].ApicId = GetApicId ();\r
- ArchSaveExceptionContext (ExceptionType, SystemContext);\r
- ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;\r
- ExceptionHandlerContext->OldIdtHandler = mReservedVectors[ExceptionType].ExceptonHandler;\r
- return;\r
- }\r
+ // Handle the #VC:\r
+ // On EFI_SUCCESS - Exception has been handled, return\r
+ // On other - ExceptionType contains (possibly new) exception\r
+ // value\r
+ //\r
+ Status = VmgExitHandleVc (&ExceptionType, SystemContext);\r
+ if (!EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+ }\r
+\r
+ ExceptionHandlerContext = (EXCEPTION_HANDLER_CONTEXT *)(UINTN)(SystemContext.SystemContextIa32);\r
+ ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
+ ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;\r
+\r
+ switch (ReservedVectors[ExceptionType].Attribute) {\r
+ case EFI_VECTOR_HANDOFF_HOOK_BEFORE:\r
//\r
- // If failed to acquire SPIN_LOCK, check if it was locked by processor itself\r
+ // The new exception handler registered by RegisterCpuInterruptHandler() is executed BEFORE original handler.\r
+ // Save the original handler to stack so the assembly code can jump to it instead of returning from handler.\r
//\r
- if (mReservedVectors[ExceptionType].ApicId == GetApicId ()) {\r
+ ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;\r
+ ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;\r
+ break;\r
+ case EFI_VECTOR_HANDOFF_HOOK_AFTER:\r
+ while (TRUE) {\r
//\r
- // Old IDT handler has been executed, then retore CPU exception content to\r
- // run new exception handler.\r
+ // If spin-lock can be acquired, it's the first time entering here.\r
//\r
- ArchRestoreExceptionContext (ExceptionType, SystemContext);\r
+ if (AcquireSpinLockOrFail (&ReservedVectors[ExceptionType].SpinLock)) {\r
+ //\r
+ // The new exception handler registered by RegisterCpuInterruptHandler() is executed AFTER original handler.\r
+ // Save the original handler to stack but skip running the new handler so the original handler is executed\r
+ // firstly.\r
+ //\r
+ ReservedVectors[ExceptionType].ApicId = GetApicId ();\r
+ ArchSaveExceptionContext (ExceptionType, SystemContext, ExceptionHandlerData);\r
+ ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;\r
+ ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;\r
+ return;\r
+ }\r
+\r
//\r
- // Rlease spin lock for ApicId\r
+ // If spin-lock cannot be acquired, it's the second time entering here.\r
+ // 'break' instead of 'return' is used so the new exception handler can be executed.\r
//\r
- ReleaseSpinLock (&mReservedVectors[ExceptionType].SpinLock);\r
- break;\r
+ if (ReservedVectors[ExceptionType].ApicId == GetApicId ()) {\r
+ //\r
+ // Old IDT handler has been executed, then restore CPU exception content to\r
+ // run new exception handler.\r
+ //\r
+ ArchRestoreExceptionContext (ExceptionType, SystemContext, ExceptionHandlerData);\r
+ //\r
+ // Release spin lock for ApicId\r
+ //\r
+ ReleaseSpinLock (&ReservedVectors[ExceptionType].SpinLock);\r
+ break;\r
+ }\r
+\r
+ CpuPause ();\r
}\r
- CpuPause ();\r
- }\r
- break;\r
- case 0xffffffff:\r
- break;\r
- default:\r
- //\r
- // It should never reach here\r
- //\r
- CpuDeadLoop ();\r
- break;\r
+\r
+ break;\r
+ case 0xffffffff:\r
+ break;\r
+ default:\r
+ //\r
+ // It should never reach here\r
+ //\r
+ CpuDeadLoop ();\r
+ break;\r
}\r
- \r
- if (mExternalInterruptHandler[ExceptionType] != NULL) {\r
- (mExternalInterruptHandler[ExceptionType]) (ExceptionType, SystemContext);\r
+\r
+ if ((ExternalInterruptHandler != NULL) &&\r
+ (ExternalInterruptHandler[ExceptionType] != NULL))\r
+ {\r
+ (ExternalInterruptHandler[ExceptionType])(ExceptionType, SystemContext);\r
} else if (ExceptionType < CPU_EXCEPTION_NUM) {\r
//\r
// Get Spinlock to display CPU information\r
//\r
- while (!AcquireSpinLockOrFail (&mDisplayMessageSpinLock)) {\r
+ while (!AcquireSpinLockOrFail (&ExceptionHandlerData->DisplayMessageSpinLock)) {\r
CpuPause ();\r
}\r
+\r
+ //\r
+ // Initialize the serial port before dumping.\r
+ //\r
+ SerialPortInitialize ();\r
//\r
// Display ExceptionType, CPU information and Image information\r
- // \r
- DumpCpuContent (ExceptionType, SystemContext);\r
+ //\r
+ DumpImageAndCpuContent (ExceptionType, SystemContext);\r
//\r
// Release Spinlock of output message\r
//\r
- ReleaseSpinLock (&mDisplayMessageSpinLock);\r
+ ReleaseSpinLock (&ExceptionHandlerData->DisplayMessageSpinLock);\r
//\r
// Enter a dead loop if needn't to execute old IDT handler further\r
//\r
- if (mReservedVectors[ExceptionType].Attribute != EFI_VECTOR_HANDOFF_HOOK_BEFORE) {\r
+ if (ReservedVectors[ExceptionType].Attribute != EFI_VECTOR_HANDOFF_HOOK_BEFORE) {\r
CpuDeadLoop ();\r
}\r
}\r
IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
)\r
{\r
- UINT16 CodeSegment;\r
- UINTN Index;\r
- UINTN InterruptHandler;\r
- RESERVED_VECTORS_DATA *ReservedVectors;\r
+ UINT16 CodeSegment;\r
+ UINTN Index;\r
+ UINTN InterruptHandler;\r
+ RESERVED_VECTORS_DATA *ReservedVectors;\r
\r
ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
//\r
//\r
CodeSegment = AsmReadCs ();\r
\r
- for (Index = 0; Index < ExceptionHandlerData->IdtEntryCount; Index ++) {\r
+ for (Index = 0; Index < ExceptionHandlerData->IdtEntryCount; Index++) {\r
IdtTable[Index].Bits.Selector = CodeSegment;\r
//\r
// Check reserved vectors attributes\r
//\r
switch (ReservedVectors[Index].Attribute) {\r
- case EFI_VECTOR_HANDOFF_DO_NOT_HOOK:\r
- //\r
- // Keep original IDT entry\r
- //\r
- continue;\r
- case EFI_VECTOR_HANDOFF_HOOK_AFTER:\r
- InitializeSpinLock (&ReservedVectors[Index].SpinLock);\r
- CopyMem (\r
- (VOID *) ReservedVectors[Index].HookAfterStubHeaderCode,\r
- (VOID *) TemplateMap->HookAfterStubHeaderStart,\r
- TemplateMap->ExceptionStubHeaderSize\r
- );\r
- AsmVectorNumFixup (\r
- (VOID *) ReservedVectors[Index].HookAfterStubHeaderCode,\r
- (UINT8) Index,\r
- (VOID *) TemplateMap->HookAfterStubHeaderStart\r
- );\r
+ case EFI_VECTOR_HANDOFF_DO_NOT_HOOK:\r
+ //\r
+ // Keep original IDT entry\r
+ //\r
+ continue;\r
+ case EFI_VECTOR_HANDOFF_HOOK_AFTER:\r
+ InitializeSpinLock (&ReservedVectors[Index].SpinLock);\r
+ CopyMem (\r
+ (VOID *)ReservedVectors[Index].HookAfterStubHeaderCode,\r
+ (VOID *)TemplateMap->HookAfterStubHeaderStart,\r
+ TemplateMap->ExceptionStubHeaderSize\r
+ );\r
+ AsmVectorNumFixup (\r
+ (VOID *)ReservedVectors[Index].HookAfterStubHeaderCode,\r
+ (UINT8)Index,\r
+ (VOID *)TemplateMap->HookAfterStubHeaderStart\r
+ );\r
//\r
// Go on the following code\r
//\r
- case EFI_VECTOR_HANDOFF_HOOK_BEFORE:\r
- //\r
- // Save original IDT handler address\r
- //\r
- ReservedVectors[Index].ExceptonHandler = ArchGetIdtHandler (&IdtTable[Index]);\r
+ case EFI_VECTOR_HANDOFF_HOOK_BEFORE:\r
+ //\r
+ // Save original IDT handler address\r
+ //\r
+ ReservedVectors[Index].ExceptonHandler = ArchGetIdtHandler (&IdtTable[Index]);\r
//\r
// Go on the following code\r
//\r
- default:\r
- //\r
- // Update new IDT entry\r
- //\r
- InterruptHandler = TemplateMap->ExceptionStart + Index * TemplateMap->ExceptionStubHeaderSize;\r
- ArchUpdateIdtEntry (&IdtTable[Index], InterruptHandler);\r
- break;\r
+ default:\r
+ //\r
+ // Update new IDT entry\r
+ //\r
+ InterruptHandler = TemplateMap->ExceptionStart + Index * TemplateMap->ExceptionStubHeaderSize;\r
+ ArchUpdateIdtEntry (&IdtTable[Index], InterruptHandler);\r
+ break;\r
}\r
}\r
- \r
- //\r
- // Save Interrupt number to global variable used for RegisterCpuInterruptHandler ()\r
- //\r
- mEnabledInterruptNum = ExceptionHandlerData->IdtEntryCount;\r
}\r
\r
/**\r
\r
@param[in] VectorInfo Pointer to reserved vector list.\r
@param[in, out] ExceptionHandlerData Pointer to exception handler data.\r
- \r
- @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized \r
+\r
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized\r
with default exception handlers.\r
@retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.\r
@retval EFI_UNSUPPORTED This function is not supported.\r
**/\r
EFI_STATUS\r
InitializeCpuExceptionHandlersWorker (\r
- IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,\r
- IN OUT EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,\r
+ IN OUT EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
)\r
{\r
- EFI_STATUS Status;\r
- IA32_DESCRIPTOR IdtDescriptor;\r
- UINTN IdtEntryCount;\r
- EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;\r
- IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
- RESERVED_VECTORS_DATA *ReservedVectors;\r
+ EFI_STATUS Status;\r
+ IA32_DESCRIPTOR IdtDescriptor;\r
+ UINTN IdtEntryCount;\r
+ EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;\r
+ IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
+ RESERVED_VECTORS_DATA *ReservedVectors;\r
\r
ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
- SetMem ((VOID *) ReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff);\r
+ SetMem ((VOID *)ReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff);\r
if (VectorInfo != NULL) {\r
Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectors, CPU_EXCEPTION_NUM);\r
if (EFI_ERROR (Status)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
}\r
- InitializeSpinLock (&mDisplayMessageSpinLock);\r
\r
- mExternalInterruptHandler = mExternalInterruptHandlerTable;\r
//\r
// Read IDT descriptor and calculate IDT size\r
//\r
IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);\r
if (IdtEntryCount > CPU_EXCEPTION_NUM) {\r
//\r
- // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most\r
+ // CPU exception library only setup CPU_EXCEPTION_NUM exception handler at most\r
//\r
IdtEntryCount = CPU_EXCEPTION_NUM;\r
}\r
\r
- IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;\r
+ IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base;\r
AsmGetTemplateAddressMap (&TemplateMap);\r
ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE);\r
\r
ExceptionHandlerData->IdtEntryCount = IdtEntryCount;\r
UpdateIdtTable (IdtTable, &TemplateMap, ExceptionHandlerData);\r
- mEnabledInterruptNum = IdtEntryCount;\r
+\r
return EFI_SUCCESS;\r
}\r
\r
**/\r
EFI_STATUS\r
RegisterCpuInterruptHandlerWorker (\r
- IN EFI_EXCEPTION_TYPE InterruptType,\r
- IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,\r
- IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
+ IN EFI_EXCEPTION_TYPE InterruptType,\r
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,\r
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
)\r
{\r
- UINTN EnabledInterruptNum;\r
- RESERVED_VECTORS_DATA *ReservedVectors;\r
- EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;\r
+ UINTN EnabledInterruptNum;\r
+ RESERVED_VECTORS_DATA *ReservedVectors;\r
+ EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;\r
\r
EnabledInterruptNum = ExceptionHandlerData->IdtEntryCount;\r
ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;\r
\r
- if (InterruptType < 0 || InterruptType >= (EFI_EXCEPTION_TYPE)EnabledInterruptNum ||\r
- ReservedVectors[InterruptType].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK) {\r
+ if ((InterruptType < 0) || (InterruptType >= (EFI_EXCEPTION_TYPE)EnabledInterruptNum) ||\r
+ (ReservedVectors[InterruptType].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK))\r
+ {\r
return EFI_UNSUPPORTED;\r
}\r
\r
- if (InterruptHandler == NULL && ExternalInterruptHandler[InterruptType] == NULL) {\r
+ if ((InterruptHandler == NULL) && (ExternalInterruptHandler[InterruptType] == NULL)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if (InterruptHandler != NULL && ExternalInterruptHandler[InterruptType] != NULL) {\r
+ if ((InterruptHandler != NULL) && (ExternalInterruptHandler[InterruptType] != NULL)) {\r
return EFI_ALREADY_STARTED;\r
}\r
\r
ExternalInterruptHandler[InterruptType] = InterruptHandler;\r
return EFI_SUCCESS;\r
}\r
-\r