/** @file Page table manipulation functions for IA-32 processors Copyright (c) 2009 - 2023, Intel Corporation. All rights reserved.
Copyright (c) 2017, AMD Incorporated. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "PiSmmCpuDxeSmm.h" /** Create PageTable for SMM use. @return PageTable Address **/ UINT32 SmmInitPageTable ( VOID ) { UINTN PageFaultHandlerHookAddress; IA32_IDT_GATE_DESCRIPTOR *IdtEntry; EFI_STATUS Status; // // Initialize spin lock // InitializeSpinLock (mPFLock); mPhysicalAddressBits = 32; mPagingMode = PagingPae; if (FeaturePcdGet (PcdCpuSmmProfileEnable) || HEAP_GUARD_NONSTOP_MODE || NULL_DETECTION_NONSTOP_MODE) { // // Set own Page Fault entry instead of the default one, because SMM Profile // feature depends on IRET instruction to do Single Step // PageFaultHandlerHookAddress = (UINTN)PageFaultIdtHandlerSmmProfile; IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base; IdtEntry += EXCEPT_IA32_PAGE_FAULT; IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress; IdtEntry->Bits.Reserved_0 = 0; IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16); } else { // // Register SMM Page Fault Handler // Status = SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler); ASSERT_EFI_ERROR (Status); } // // Additional SMM IDT initialization for SMM stack guard // if (FeaturePcdGet (PcdCpuSmmStackGuard)) { InitializeIDTSmmStackGuard (); } return GenSmmPageTable (PagingPae, mPhysicalAddressBits); } /** Page Fault handler for SMM use. **/ VOID SmiDefaultPFHandler ( VOID ) { CpuDeadLoop (); } /** ThePage Fault handler wrapper for SMM use. @param InterruptType Defines the type of interrupt or exception that occurred on the processor.This parameter is processor architecture specific. @param SystemContext A pointer to the processor context when the interrupt occurred on the processor. **/ VOID EFIAPI SmiPFHandler ( IN EFI_EXCEPTION_TYPE InterruptType, IN EFI_SYSTEM_CONTEXT SystemContext ) { UINTN PFAddress; UINTN GuardPageAddress; UINTN CpuIndex; ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT); AcquireSpinLock (mPFLock); PFAddress = AsmReadCr2 (); // // If a page fault occurs in SMRAM range, it might be in a SMM stack guard page, // or SMM page protection violation. // if ((PFAddress >= mCpuHotPlugData.SmrrBase) && (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) { DumpCpuContext (InterruptType, SystemContext); CpuIndex = GetCpuIndex (); GuardPageAddress = (mSmmStackArrayBase + EFI_PAGE_SIZE + CpuIndex * mSmmStackSize); if ((FeaturePcdGet (PcdCpuSmmStackGuard)) && (PFAddress >= GuardPageAddress) && (PFAddress < (GuardPageAddress + EFI_PAGE_SIZE))) { DEBUG ((DEBUG_ERROR, "SMM stack overflow!\n")); } else { if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) { DEBUG ((DEBUG_ERROR, "SMM exception at execution (0x%x)\n", PFAddress)); DEBUG_CODE ( DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp); ); } else { DEBUG ((DEBUG_ERROR, "SMM exception at access (0x%x)\n", PFAddress)); DEBUG_CODE ( DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip); ); } if (HEAP_GUARD_NONSTOP_MODE) { GuardPagePFHandler (SystemContext.SystemContextIa32->ExceptionData); goto Exit; } } CpuDeadLoop (); goto Exit; } // // If a page fault occurs in non-SMRAM range. // if ((PFAddress < mCpuHotPlugData.SmrrBase) || (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) { if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) { DumpCpuContext (InterruptType, SystemContext); DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress)); DEBUG_CODE ( DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp); ); CpuDeadLoop (); goto Exit; } // // If NULL pointer was just accessed // if (((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0) && (PFAddress < EFI_PAGE_SIZE)) { DumpCpuContext (InterruptType, SystemContext); DEBUG ((DEBUG_ERROR, "!!! NULL pointer access !!!\n")); DEBUG_CODE ( DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip); ); if (NULL_DETECTION_NONSTOP_MODE) { GuardPagePFHandler (SystemContext.SystemContextIa32->ExceptionData); goto Exit; } CpuDeadLoop (); goto Exit; } if (IsSmmCommBufferForbiddenAddress (PFAddress)) { DumpCpuContext (InterruptType, SystemContext); DEBUG ((DEBUG_ERROR, "Access SMM communication forbidden address (0x%x)!\n", PFAddress)); DEBUG_CODE ( DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip); ); CpuDeadLoop (); goto Exit; } } if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { SmmProfilePFHandler ( SystemContext.SystemContextIa32->Eip, SystemContext.SystemContextIa32->ExceptionData ); } else { DumpCpuContext (InterruptType, SystemContext); SmiDefaultPFHandler (); } Exit: ReleaseSpinLock (mPFLock); } /** This function returns with no action for 32 bit. @param[out] *Cr2 Pointer to variable to hold CR2 register value. **/ VOID SaveCr2 ( OUT UINTN *Cr2 ) { return; } /** This function returns with no action for 32 bit. @param[in] Cr2 Value to write into CR2 register. **/ VOID RestoreCr2 ( IN UINTN Cr2 ) { return; } /** Return whether access to non-SMRAM is restricted. @retval TRUE Access to non-SMRAM is restricted. @retval FALSE Access to non-SMRAM is not restricted. **/ BOOLEAN IsRestrictedMemoryAccess ( VOID ) { return TRUE; }