From 94dc3ac4ad6bf27e3c2af9257da19509dd6bf2cb Mon Sep 17 00:00:00 2001 From: Taylor Beebe Date: Thu, 27 Apr 2023 10:27:19 -0700 Subject: [PATCH] Add SEC and PEI MU Exception Handler --- .../SecPeiCpuExceptionHandlerLibMu.inf | 58 +++++ .../SecPeiCpuExceptionMu.c | 238 ++++++++++++++++++ UefiCpuPkg/UefiCpuPkg.dsc | 1 + 3 files changed, 297 insertions(+) create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLibMu.inf create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionMu.c diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLibMu.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLibMu.inf new file mode 100644 index 0000000000..fbe2f0c0d6 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLibMu.inf @@ -0,0 +1,58 @@ +## @file +# CPU Exception Handler library instance for SEC/PEI modules. +# +# Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved. +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SecPeiCpuExceptionHandlerLib + MODULE_UNI_FILE = SecPeiCpuExceptionHandlerLib.uni + FILE_GUID = D719EBB9-20EC-42E2-9B66-8FF06E809EAB + MODULE_TYPE = PEIM + VERSION_STRING = 1.1 + LIBRARY_CLASS = CpuExceptionHandlerLib|SEC PEI_CORE PEIM + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.Ia32] + Ia32/ExceptionHandlerAsm.nasm + Ia32/ExceptionTssEntryAsm.nasm + Ia32/ArchExceptionHandler.c + Ia32/ArchInterruptDefs.h + +[Sources.X64] + X64/ExceptionHandlerAsm.nasm + X64/ArchExceptionHandler.c + X64/ArchInterruptDefs.h + +[Sources.common] + CpuExceptionCommon.h + CpuExceptionCommon.c + SecPeiCpuExceptionMu.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + SerialPortLib + PrintLib + LocalApicLib + PeCoffGetEntryPointLib + VmgExitLib + ResetSystemLib + ExceptionPersistenceLib + +[FeaturePcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES + diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionMu.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionMu.c new file mode 100644 index 0000000000..e93a19b315 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionMu.c @@ -0,0 +1,238 @@ +/** @file + CPU exception handler library implementation for SEC/PEIM modules. + +Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent +Copyright (c) Microsoft Corporation. + +**/ + +#include +#include +#include "CpuExceptionCommon.h" +#include +#include + +CONST UINTN mDoFarReturnFlag = 0; + +/** + Common exception handler. + + @param ExceptionType Exception type. + @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. +**/ +VOID +EFIAPI +CommonExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + if (ExceptionType == VC_EXCEPTION) { + EFI_STATUS Status; + // + // #VC needs to be handled immediately upon enabling exception handling + // and therefore can't use the RegisterCpuInterruptHandler() interface + // (which isn't supported under Sec and Pei anyway). + // + // Handle the #VC: + // On EFI_SUCCESS - Exception has been handled, return + // On other - ExceptionType contains (possibly new) exception + // value + // + Status = VmgExitHandleVc (&ExceptionType, SystemContext); + if (!EFI_ERROR (Status)) { + return; + } + } + + // + // Initialize the serial port before dumping. + // + SerialPortInitialize (); + // + // Display ExceptionType, CPU information and Image information + // + DumpImageAndCpuContent (ExceptionType, SystemContext); + + ExPersistSetException (ExceptionPersistOther); + ResetWarm (); + + // + // Enter a dead loop. + // + CpuDeadLoop (); +} + +/** + Initializes all CPU exceptions entries and provides the default exception handlers. + + Caller should try to get an array of interrupt and/or exception vectors that are in use and need to + persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification. + If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL. + If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly. + Note: Before invoking this API, caller must allocate memory for IDT table and load + IDTR by AsmWriteIdtr(). + + @param[in] VectorInfo Pointer to reserved vector list. + + @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 +EFIAPI +InitializeCpuExceptionHandlers ( + IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL + ) +{ + EFI_STATUS Status; + RESERVED_VECTORS_DATA ReservedVectorData[CPU_EXCEPTION_NUM]; + IA32_DESCRIPTOR IdtDescriptor; + UINTN IdtEntryCount; + UINT16 CodeSegment; + EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap; + IA32_IDT_GATE_DESCRIPTOR *IdtTable; + UINTN Index; + UINTN InterruptHandler; + + if (VectorInfo != NULL) { + SetMem ((VOID *)ReservedVectorData, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff); + Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectorData, CPU_EXCEPTION_NUM); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Read IDT descriptor and calculate IDT size + // + AsmReadIdtr (&IdtDescriptor); + IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR); + if (IdtEntryCount > CPU_EXCEPTION_NUM) { + // + // CPU exception library only setup CPU_EXCEPTION_NUM exception handler at most + // + IdtEntryCount = CPU_EXCEPTION_NUM; + } + + // + // Use current CS as the segment selector of interrupt gate in IDT + // + CodeSegment = AsmReadCs (); + + AsmGetTemplateAddressMap (&TemplateMap); + IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base; + for (Index = 0; Index < IdtEntryCount; Index++) { + IdtTable[Index].Bits.Selector = CodeSegment; + // + // Check reserved vectors attributes if has, only EFI_VECTOR_HANDOFF_DO_NOT_HOOK + // supported in this instance + // + if (VectorInfo != NULL) { + if (ReservedVectorData[Index].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK) { + continue; + } + } + + // + // Update IDT entry + // + InterruptHandler = TemplateMap.ExceptionStart + Index * TemplateMap.ExceptionStubHeaderSize; + ArchUpdateIdtEntry (&IdtTable[Index], InterruptHandler); + } + + return EFI_SUCCESS; +} + +/** + Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers. + + Caller should try to get an array of interrupt and/or exception vectors that are in use and need to + persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification. + If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL. + If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly. + + @param[in] VectorInfo Pointer to reserved vector list. + + @retval EFI_SUCCESS All CPU interrupt/exception entries have been successfully initialized + with default interrupt/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 +EFIAPI +InitializeCpuInterruptHandlers ( + IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Registers a function to be called from the processor interrupt handler. + + This function registers and enables the handler specified by InterruptHandler for a processor + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. + The installed handler is called once for each processor interrupt or exception. + NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or + InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned. + + @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. + + @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 +EFIAPI +RegisterCpuInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Initializes all CPU exceptions entries with optional extra initializations. + + By default, this method should include all functionalities implemented by + InitializeCpuExceptionHandlers(), plus extra initialization works, if any. + This could be done by calling InitializeCpuExceptionHandlers() directly + in this method besides the extra works. + + InitData is optional and its use and content are processor arch dependent. + The typical usage of it is to convey resources which have to be reserved + elsewhere and are necessary for the extra initializations of exception. + + @param[in] VectorInfo Pointer to reserved vector list. + @param[in] InitData Pointer to data optional for extra initializations + of exception. + + @retval EFI_SUCCESS The exceptions have been successfully + initialized. + @retval EFI_INVALID_PARAMETER VectorInfo or InitData contains invalid + content. + +**/ +EFI_STATUS +EFIAPI +InitializeCpuExceptionHandlersEx ( + IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL, + IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL + ) +{ + return InitializeCpuExceptionHandlers (VectorInfo); +} diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index f36c51b43b..1402917f6c 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -184,6 +184,7 @@ UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf !if $(TOOL_CHAIN_TAG) != "XCODE5" UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf + UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLibMu.inf # MU_CHANGE !endif UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf