123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- /** @file
- CPU Exception Library provides PEI/DXE/SMM CPU common exception handler.
- Copyright (c) 2012 - 2022, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <Library/DebugLib.h>
- #include <Library/CcExitLib.h>
- #include "CpuExceptionCommon.h"
- /**
- Internal worker function for common exception handler.
- @param ExceptionType Exception type.
- @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
- @param ExceptionHandlerData Pointer to exception handler data.
- **/
- VOID
- CommonExceptionHandlerWorker (
- IN EFI_EXCEPTION_TYPE ExceptionType,
- IN EFI_SYSTEM_CONTEXT SystemContext,
- IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
- )
- {
- EFI_STATUS Status;
- EXCEPTION_HANDLER_CONTEXT *ExceptionHandlerContext;
- RESERVED_VECTORS_DATA *ReservedVectors;
- EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;
- switch (ExceptionType) {
- case VC_EXCEPTION:
- //
- // #VC needs to be handled immediately upon enabling exception handling
- // and therefore can't use the RegisterCpuInterruptHandler() interface.
- //
- // Handle the #VC:
- // On EFI_SUCCESS - Exception has been handled, return
- // On other - ExceptionType contains (possibly new) exception
- // value
- //
- Status = CcExitHandleVc (&ExceptionType, SystemContext);
- if (!EFI_ERROR (Status)) {
- return;
- }
- break;
- case VE_EXCEPTION:
- //
- // #VE needs to be handled immediately upon enabling exception handling
- // and therefore can't use the RegisterCpuInterruptHandler() interface.
- //
- // Handle the #VE:
- // On EFI_SUCCESS - Exception has been handled, return
- // On other - ExceptionType contains (possibly new) exception
- // value
- //
- Status = CcExitHandleVe (&ExceptionType, SystemContext);
- if (!EFI_ERROR (Status)) {
- return;
- }
- break;
- default:
- break;
- }
- ExceptionHandlerContext = (EXCEPTION_HANDLER_CONTEXT *)(UINTN)(SystemContext.SystemContextIa32);
- ReservedVectors = ExceptionHandlerData->ReservedVectors;
- ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;
- switch (ReservedVectors[ExceptionType].Attribute) {
- case EFI_VECTOR_HANDOFF_HOOK_BEFORE:
- //
- // The new exception handler registered by RegisterCpuInterruptHandler() is executed BEFORE original handler.
- // Save the original handler to stack so the assembly code can jump to it instead of returning from handler.
- //
- ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;
- ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;
- break;
- case EFI_VECTOR_HANDOFF_HOOK_AFTER:
- while (TRUE) {
- //
- // If spin-lock can be acquired, it's the first time entering here.
- //
- if (AcquireSpinLockOrFail (&ReservedVectors[ExceptionType].SpinLock)) {
- //
- // The new exception handler registered by RegisterCpuInterruptHandler() is executed AFTER original handler.
- // Save the original handler to stack but skip running the new handler so the original handler is executed
- // firstly.
- //
- ReservedVectors[ExceptionType].ApicId = GetApicId ();
- ArchSaveExceptionContext (ExceptionType, SystemContext, ExceptionHandlerData);
- ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;
- ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;
- return;
- }
- //
- // If spin-lock cannot be acquired, it's the second time entering here.
- // 'break' instead of 'return' is used so the new exception handler can be executed.
- //
- if (ReservedVectors[ExceptionType].ApicId == GetApicId ()) {
- //
- // Old IDT handler has been executed, then restore CPU exception content to
- // run new exception handler.
- //
- ArchRestoreExceptionContext (ExceptionType, SystemContext, ExceptionHandlerData);
- //
- // Release spin lock for ApicId
- //
- ReleaseSpinLock (&ReservedVectors[ExceptionType].SpinLock);
- break;
- }
- CpuPause ();
- }
- break;
- case 0xffffffff:
- break;
- default:
- //
- // It should never reach here
- //
- CpuDeadLoop ();
- break;
- }
- if ((ExternalInterruptHandler != NULL) &&
- (ExternalInterruptHandler[ExceptionType] != NULL))
- {
- (ExternalInterruptHandler[ExceptionType])(ExceptionType, SystemContext);
- } else if (ExceptionType < CPU_EXCEPTION_NUM) {
- //
- // Get Spinlock to display CPU information
- //
- while (!AcquireSpinLockOrFail (&ExceptionHandlerData->DisplayMessageSpinLock)) {
- CpuPause ();
- }
- //
- // Initialize the serial port before dumping.
- //
- SerialPortInitialize ();
- //
- // Display ExceptionType, CPU information and Image information
- //
- DumpImageAndCpuContent (ExceptionType, SystemContext);
- //
- // Release Spinlock of output message
- //
- ReleaseSpinLock (&ExceptionHandlerData->DisplayMessageSpinLock);
- //
- // Enter a dead loop if needn't to execute old IDT handler further
- //
- if (ReservedVectors[ExceptionType].Attribute != EFI_VECTOR_HANDOFF_HOOK_BEFORE) {
- CpuDeadLoop ();
- }
- }
- }
- /**
- Internal worker function to update IDT entries accordling to vector attributes.
- @param[in] IdtTable Pointer to IDT table.
- @param[in] TemplateMap Pointer to a buffer where the address map is
- returned.
- @param[in] ExceptionHandlerData Pointer to exception handler data.
- **/
- VOID
- UpdateIdtTable (
- IN IA32_IDT_GATE_DESCRIPTOR *IdtTable,
- IN EXCEPTION_HANDLER_TEMPLATE_MAP *TemplateMap,
- IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
- )
- {
- UINT16 CodeSegment;
- UINTN Index;
- UINTN InterruptHandler;
- RESERVED_VECTORS_DATA *ReservedVectors;
- ReservedVectors = ExceptionHandlerData->ReservedVectors;
- //
- // Use current CS as the segment selector of interrupt gate in IDT
- //
- CodeSegment = AsmReadCs ();
- for (Index = 0; Index < ExceptionHandlerData->IdtEntryCount; Index++) {
- IdtTable[Index].Bits.Selector = CodeSegment;
- //
- // Check reserved vectors attributes
- //
- switch (ReservedVectors[Index].Attribute) {
- case EFI_VECTOR_HANDOFF_DO_NOT_HOOK:
- //
- // Keep original IDT entry
- //
- continue;
- case EFI_VECTOR_HANDOFF_HOOK_AFTER:
- InitializeSpinLock (&ReservedVectors[Index].SpinLock);
- CopyMem (
- (VOID *)ReservedVectors[Index].HookAfterStubHeaderCode,
- (VOID *)TemplateMap->HookAfterStubHeaderStart,
- TemplateMap->ExceptionStubHeaderSize
- );
- AsmVectorNumFixup (
- (VOID *)ReservedVectors[Index].HookAfterStubHeaderCode,
- (UINT8)Index,
- (VOID *)TemplateMap->HookAfterStubHeaderStart
- );
- //
- // Go on the following code
- //
- case EFI_VECTOR_HANDOFF_HOOK_BEFORE:
- //
- // Save original IDT handler address
- //
- ReservedVectors[Index].ExceptonHandler = ArchGetIdtHandler (&IdtTable[Index]);
- //
- // Go on the following code
- //
- default:
- //
- // Update new IDT entry
- //
- InterruptHandler = TemplateMap->ExceptionStart + Index * TemplateMap->ExceptionStubHeaderSize;
- ArchUpdateIdtEntry (&IdtTable[Index], InterruptHandler);
- break;
- }
- }
- }
- /**
- Internal worker function to initialize exception handler.
- @param[in] VectorInfo Pointer to reserved vector list.
- @param[in, out] ExceptionHandlerData Pointer to exception handler data.
- @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
- with default exception handlers.
- @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
- @retval EFI_UNSUPPORTED This function is not supported.
- **/
- EFI_STATUS
- InitializeCpuExceptionHandlersWorker (
- IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,
- IN OUT EXCEPTION_HANDLER_DATA *ExceptionHandlerData
- )
- {
- EFI_STATUS Status;
- IA32_DESCRIPTOR IdtDescriptor;
- UINTN IdtEntryCount;
- EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;
- IA32_IDT_GATE_DESCRIPTOR *IdtTable;
- RESERVED_VECTORS_DATA *ReservedVectors;
- ReservedVectors = ExceptionHandlerData->ReservedVectors;
- SetMem ((VOID *)ReservedVectors, sizeof (RESERVED_VECTORS_DATA) * ExceptionHandlerData->IdtEntryCount, 0xff);
- if (VectorInfo != NULL) {
- Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectors, ExceptionHandlerData->IdtEntryCount);
- if (EFI_ERROR (Status)) {
- return EFI_INVALID_PARAMETER;
- }
- }
- //
- // Setup the exception handlers according to IDT size, but no more than
- // ExceptionHandlerData->IdtEntryCount (32 in PEI and SMM, 256 in DXE) handlers.
- //
- AsmReadIdtr (&IdtDescriptor);
- IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);
- ExceptionHandlerData->IdtEntryCount = MIN (IdtEntryCount, ExceptionHandlerData->IdtEntryCount);
- IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base;
- AsmGetTemplateAddressMap (&TemplateMap);
- ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE);
- UpdateIdtTable (IdtTable, &TemplateMap, ExceptionHandlerData);
- return EFI_SUCCESS;
- }
- /**
- Registers a function to be called from the processor interrupt handler.
- @param[in] InterruptType Defines which interrupt or exception to hook.
- @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
- when a processor interrupt occurs. If this parameter is NULL, then the handler
- will be uninstalled
- @param[in] ExceptionHandlerData Pointer to exception handler data.
- @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
- @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
- previously installed.
- @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
- previously installed.
- @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
- or this function is not supported.
- **/
- EFI_STATUS
- RegisterCpuInterruptHandlerWorker (
- IN EFI_EXCEPTION_TYPE InterruptType,
- IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,
- IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
- )
- {
- UINTN EnabledInterruptNum;
- RESERVED_VECTORS_DATA *ReservedVectors;
- EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;
- EnabledInterruptNum = ExceptionHandlerData->IdtEntryCount;
- ReservedVectors = ExceptionHandlerData->ReservedVectors;
- ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;
- if ((InterruptType < 0) || (InterruptType >= (EFI_EXCEPTION_TYPE)EnabledInterruptNum) ||
- (ReservedVectors[InterruptType].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK))
- {
- return EFI_UNSUPPORTED;
- }
- if ((InterruptHandler == NULL) && (ExternalInterruptHandler[InterruptType] == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- if ((InterruptHandler != NULL) && (ExternalInterruptHandler[InterruptType] != NULL)) {
- return EFI_ALREADY_STARTED;
- }
- ExternalInterruptHandler[InterruptType] = InterruptHandler;
- return EFI_SUCCESS;
- }
|