mirror of
https://github.com/acidanthera/audk.git
synced 2025-08-19 08:38:10 +02:00
This commit is code refinement to current smm pagetable generation code. Add a new GenSmmPageTable() API to create smm page table based on the PageTableMap() API in CpuPageTableLib. Caller only needs to specify the paging mode and the PhysicalAddressBits to map. This function can be used to create both IA32 pae paging and X64 5level, 4level paging. Signed-off-by: Dun Tan <dun.tan@intel.com> Cc: Eric Dong <eric.dong@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> Cc: Gerd Hoffmann <kraxel@redhat.com>
245 lines
6.4 KiB
C
245 lines
6.4 KiB
C
/** @file
|
|
Page table manipulation functions for IA-32 processors
|
|
|
|
Copyright (c) 2009 - 2023, Intel Corporation. All rights reserved.<BR>
|
|
Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
|
|
|
|
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;
|
|
}
|