This patch just separates the smbase relocation logic from PiSmmCpuDxeSmm driver, and moves to the SmmRelocationInit interface. It maintains the original implementation of most functions and leaves the definitions of global variables intact. Further refinements to the code are planned for subsequent patches. Platform shall consume the interface for the smbase relocation if need SMM support. Note: Before using SmmRelocationLib, the PiSmmCpuDxeSmm driver allocates the SMRAM to be used for SMI handler and Save state area of each processor from Smst->AllocatePages(). With SmmRelocationLib, the SMRAM allocation for SMI handlers and Save state areas is moved to early PEI phase (Smst->AllocatePages() service is not available). So, the allocation is done by splitting the SMRAM out of the SMRAM regions reported from gEfiSmmSMramMemoryGuid. So, Platform must produce the gEfiSmmSMramMemoryGuid HOB for SmmRelocationLib usage. Cc: Ray Ni <ray.ni@intel.com> Cc: Zeng Star <star.zeng@intel.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> Signed-off-by: Jiaxin Wu <jiaxin.wu@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com>
140 lines
4.4 KiB
C
140 lines
4.4 KiB
C
/** @file
|
|
Config SMRAM Save State for SmmBases Relocation.
|
|
|
|
Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
#include "InternalSmmRelocationLib.h"
|
|
#include <Library/CpuLib.h>
|
|
|
|
/**
|
|
Get the mode of the CPU at the time an SMI occurs
|
|
|
|
@retval EFI_MM_SAVE_STATE_REGISTER_LMA_32BIT 32 bit.
|
|
@retval EFI_MM_SAVE_STATE_REGISTER_LMA_64BIT 64 bit.
|
|
|
|
**/
|
|
UINT8
|
|
GetMmSaveStateRegisterLma (
|
|
VOID
|
|
)
|
|
{
|
|
CPUID_VERSION_INFO_EAX RegEax;
|
|
CPUID_EXTENDED_CPU_SIG_EDX RegEdx;
|
|
UINTN FamilyId;
|
|
UINTN ModelId;
|
|
UINT32 Eax;
|
|
UINT8 SmmSaveStateRegisterLma;
|
|
|
|
//
|
|
// Determine the mode of the CPU at the time an SMI occurs
|
|
// Intel(R) 64 and IA-32 Architectures Software Developer's Manual
|
|
// Volume 3C, Section 34.4.1.1
|
|
//
|
|
RegEax.Uint32 = GetCpuFamilyModel ();
|
|
FamilyId = RegEax.Bits.FamilyId;
|
|
ModelId = RegEax.Bits.Model;
|
|
if ((FamilyId == 0x06) || (FamilyId == 0x0f)) {
|
|
ModelId = ModelId | RegEax.Bits.ExtendedModelId << 4;
|
|
}
|
|
|
|
RegEdx.Uint32 = 0;
|
|
AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax, NULL, NULL, NULL);
|
|
if (Eax >= CPUID_EXTENDED_CPU_SIG) {
|
|
AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &(RegEdx.Uint32));
|
|
}
|
|
|
|
SmmSaveStateRegisterLma = (UINT8)EFI_MM_SAVE_STATE_REGISTER_LMA_32BIT;
|
|
if (RegEdx.Bits.LM) {
|
|
SmmSaveStateRegisterLma = (UINT8)EFI_MM_SAVE_STATE_REGISTER_LMA_64BIT;
|
|
}
|
|
|
|
if (FamilyId == 0x06) {
|
|
if ((ModelId == 0x17) || (ModelId == 0x0f) || (ModelId == 0x1c)) {
|
|
SmmSaveStateRegisterLma = (UINT8)EFI_MM_SAVE_STATE_REGISTER_LMA_64BIT;
|
|
}
|
|
}
|
|
|
|
return SmmSaveStateRegisterLma;
|
|
}
|
|
|
|
/**
|
|
This function configures the SmBase on the currently executing CPU.
|
|
|
|
@param[in] SmBase The SmBase on the currently executing CPU.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
ConfigureSmBase (
|
|
IN UINT64 SmBase
|
|
)
|
|
{
|
|
SMRAM_SAVE_STATE_MAP *CpuState;
|
|
|
|
CpuState = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET);
|
|
|
|
CpuState->x86.SMBASE = (UINT32)SmBase;
|
|
}
|
|
|
|
/**
|
|
Hook the code executed immediately after an RSM instruction on the currently
|
|
executing CPU. The mode of code executed immediately after RSM must be
|
|
detected, and the appropriate hook must be selected. Always clear the auto
|
|
HALT restart flag if it is set.
|
|
|
|
@param[in] CpuIndex The processor index for the currently
|
|
executing CPU.
|
|
@param[in,out] CpuState Pointer to SMRAM Save State Map for the
|
|
currently executing CPU.
|
|
@param[in] NewInstructionPointer32 Instruction pointer to use if resuming to
|
|
32-bit mode from 64-bit SMM.
|
|
@param[in] NewInstructionPointer Instruction pointer to use if resuming to
|
|
same mode as SMM.
|
|
|
|
@retval The value of the original instruction pointer before it was hooked.
|
|
|
|
**/
|
|
UINT64
|
|
EFIAPI
|
|
HookReturnFromSmm (
|
|
IN UINTN CpuIndex,
|
|
IN OUT SMRAM_SAVE_STATE_MAP *CpuState,
|
|
IN UINT64 NewInstructionPointer32,
|
|
IN UINT64 NewInstructionPointer
|
|
)
|
|
{
|
|
UINT64 OriginalInstructionPointer;
|
|
|
|
if (GetMmSaveStateRegisterLma () == EFI_MM_SAVE_STATE_REGISTER_LMA_32BIT) {
|
|
OriginalInstructionPointer = (UINT64)CpuState->x86._EIP;
|
|
CpuState->x86._EIP = (UINT32)NewInstructionPointer;
|
|
|
|
//
|
|
// Clear the auto HALT restart flag so the RSM instruction returns
|
|
// program control to the instruction following the HLT instruction.
|
|
//
|
|
if ((CpuState->x86.AutoHALTRestart & BIT0) != 0) {
|
|
CpuState->x86.AutoHALTRestart &= ~BIT0;
|
|
}
|
|
} else {
|
|
OriginalInstructionPointer = CpuState->x64._RIP;
|
|
if ((CpuState->x64.IA32_EFER & LMA) == 0) {
|
|
CpuState->x64._RIP = (UINT32)NewInstructionPointer32;
|
|
} else {
|
|
CpuState->x64._RIP = (UINT32)NewInstructionPointer;
|
|
}
|
|
|
|
//
|
|
// Clear the auto HALT restart flag so the RSM instruction returns
|
|
// program control to the instruction following the HLT instruction.
|
|
//
|
|
if ((CpuState->x64.AutoHALTRestart & BIT0) != 0) {
|
|
CpuState->x64.AutoHALTRestart &= ~BIT0;
|
|
}
|
|
}
|
|
|
|
return OriginalInstructionPointer;
|
|
}
|