| /** @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,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 OUT SMRAM_SAVE_STATE_MAP *CpuState, | |
| IN UINT64 NewInstructionPointer32, | |
| IN UINT64 NewInstructionPointer | |
| ) | |
| { | |
| UINT64 OriginalInstructionPointer; | |
| MSR_IA32_EFER_REGISTER Msr; | |
| 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; | |
| Msr.Uint64 = CpuState->x64.IA32_EFER; | |
| if (!Msr.Bits.LMA) { | |
| 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; | |
| } |