From: Abdul Lateef Attar <AbdulLateef.Attar@amd.com>
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4182
Implements SmmSmramSaveStateLib Library class for
AMD cpu family.
Cc: Paul Grimes <paul.grimes@amd.com>
Cc: Garrett Kirkendall <garrett.kirkendall@amd.com>
Cc: Abner Chang <abner.chang@amd.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Abdul Lateef Attar <abdattar@amd.com>
Reviewed-by: Abner Chang <abner.chang@amd.com>
---
UefiCpuPkg/UefiCpuPkg.dsc | 3 +
.../AmdSmmSmramSaveStateLib.inf | 28 ++
.../SmmSmramSaveStateLib/SmramSaveState.h | 101 ++++++
.../SmmSmramSaveStateLib/AmdSmramSaveState.c | 318 ++++++++++++++++++
.../SmramSaveStateCommon.c | 124 +++++++
5 files changed, 574 insertions(+)
create mode 100644 UefiCpuPkg/Library/SmmSmramSaveStateLib/AmdSmmSmramSaveStateLib.inf
create mode 100644 UefiCpuPkg/Library/SmmSmramSaveStateLib/SmramSaveState.h
create mode 100644 UefiCpuPkg/Library/SmmSmramSaveStateLib/AmdSmramSaveState.c
create mode 100644 UefiCpuPkg/Library/SmmSmramSaveStateLib/SmramSaveStateCommon.c
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index d85d56916f2c..c33059cd3209 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -2,6 +2,7 @@
# UefiCpuPkg Package
#
# Copyright (c) 2007 - 2022, Intel Corporation. All rights reserved.<BR>
+# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -100,6 +101,7 @@ [LibraryClasses.common.DXE_SMM_DRIVER]
MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf
HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
+ SmmSmramSaveStateLib|UefiCpuPkg/Library/SmmSmramSaveStateLib/AmdSmmSmramSaveStateLib.inf
[LibraryClasses.common.MM_STANDALONE]
MmServicesTableLib|MdePkg/Library/StandaloneMmServicesTableLib/StandaloneMmServicesTableLib.inf
@@ -184,6 +186,7 @@ [Components.IA32, Components.X64]
<LibraryClasses>
UnitTestResultReportLib|UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.inf
}
+ UefiCpuPkg/Library/SmmSmramSaveStateLib/AmdSmmSmramSaveStateLib.inf
[Components.X64]
UefiCpuPkg/Library/CpuExceptionHandlerLib/UnitTest/DxeCpuExceptionHandlerLibUnitTest.inf
diff --git a/UefiCpuPkg/Library/SmmSmramSaveStateLib/AmdSmmSmramSaveStateLib.inf b/UefiCpuPkg/Library/SmmSmramSaveStateLib/AmdSmmSmramSaveStateLib.inf
new file mode 100644
index 000000000000..91f8927e0419
--- /dev/null
+++ b/UefiCpuPkg/Library/SmmSmramSaveStateLib/AmdSmmSmramSaveStateLib.inf
@@ -0,0 +1,28 @@
+## @file
+# SMM Smram save state service lib.
+#
+# This is SMM Smram save state service lib that provide service to read and
+# save savestate area registers.
+#
+# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 1.29
+ BASE_NAME = AmdSmmSmramSaveStateLib
+ FILE_GUID = FB7D0A60-E8D4-4EFA-90AA-B357BC569879
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SmmSmramSaveStateLib
+
+[Sources]
+ SmramSaveState.h
+ SmramSaveStateCommon.c
+ AmdSmramSaveState.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
diff --git a/UefiCpuPkg/Library/SmmSmramSaveStateLib/SmramSaveState.h b/UefiCpuPkg/Library/SmmSmramSaveStateLib/SmramSaveState.h
new file mode 100644
index 000000000000..6c424e3e36e9
--- /dev/null
+++ b/UefiCpuPkg/Library/SmmSmramSaveStateLib/SmramSaveState.h
@@ -0,0 +1,101 @@
+/** @file
+ SMRAM Save State Map header file.
+
+ Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+ Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef SMRAM_SAVESTATE_H_
+#define SMRAM_SAVESTATE_H_
+
+#include <Uefi/UefiBaseType.h>
+#include <Protocol/SmmCpu.h>
+#include <Library/DebugLib.h>
+#include <Library/SmmSmramSaveStateLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+
+// EFER register LMA bit
+#define LMA BIT10
+
+// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_REGISTER_RANGE
+#define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }
+
+#define SMM_SAVE_STATE_REGISTER_MAX_INDEX 2
+
+// Structure used to describe a range of registers
+typedef struct {
+ EFI_SMM_SAVE_STATE_REGISTER Start;
+ EFI_SMM_SAVE_STATE_REGISTER End;
+ UINTN Length;
+} CPU_SMM_SAVE_STATE_REGISTER_RANGE;
+
+// Structure used to build a lookup table to retrieve the widths and offsets
+// associated with each supported EFI_SMM_SAVE_STATE_REGISTER value
+
+typedef struct {
+ UINT8 Width32;
+ UINT8 Width64;
+ UINT16 Offset32;
+ UINT16 Offset64Lo;
+ UINT16 Offset64Hi;
+ BOOLEAN Writeable;
+} CPU_SMM_SAVE_STATE_LOOKUP_ENTRY;
+
+/**
+ Returns LMA value of the Processor.
+
+ @param[in] VOID
+
+ @retval UINT8 returns LMA bit value.
+**/
+UINT8
+SmramSaveStateGetRegisterLma (
+ VOID
+ );
+
+/**
+ Read information from the CPU save state.
+
+ @param Register Specifies the CPU register to read form the save state.
+
+ @retval 0 Register is not valid
+ @retval >0 Index into mSmmSmramCpuWidthOffset[] associated with Register
+
+**/
+UINTN
+EFIAPI
+SmramSaveStateGetRegisterIndex (
+ IN EFI_SMM_SAVE_STATE_REGISTER Register
+ );
+
+/**
+ Read a CPU Save State register on the target processor.
+
+ This function abstracts the differences that whether the CPU Save State register is in the
+ IA32 CPU Save State Map or X64 CPU Save State Map.
+
+ This function supports reading a CPU Save State register in SMBase relocation handler.
+
+ @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
+ @param[in] RegisterIndex Index into mSmmSmramCpuWidthOffset[] look up table.
+ @param[in] Width The number of bytes to read from the CPU save state.
+ @param[out] Buffer Upon return, this holds the CPU register value read from the save state.
+
+ @retval EFI_SUCCESS The register was read from Save State.
+ @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
+ @retval EFI_INVALID_PARAMTER This or Buffer is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmramSaveStateReadRegisterByIndex (
+ IN UINTN CpuIndex,
+ IN UINTN RegisterIndex,
+ IN UINTN Width,
+ OUT VOID *Buffer
+ );
+
+#endif
diff --git a/UefiCpuPkg/Library/SmmSmramSaveStateLib/AmdSmramSaveState.c b/UefiCpuPkg/Library/SmmSmramSaveStateLib/AmdSmramSaveState.c
new file mode 100644
index 000000000000..8fc4466f473e
--- /dev/null
+++ b/UefiCpuPkg/Library/SmmSmramSaveStateLib/AmdSmramSaveState.c
@@ -0,0 +1,318 @@
+/** @file
+Provides services to access SMRAM Save State Map
+
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SmramSaveState.h"
+#include <Register/Amd/SmramSaveStateMap.h>
+#include <Library/BaseLib.h>
+
+#define EFER_ADDRESS 0XC0000080ul
+#define SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX 1
+
+// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
+#define SMM_CPU_OFFSET(Field) OFFSET_OF (AMD_SMRAM_SAVE_STATE_MAP, Field)
+
+// Table used by SmramSaveStateGetRegisterIndex() to convert an EFI_SMM_SAVE_STATE_REGISTER
+// value to an index into a table of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
+CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmSmramCpuRegisterRanges[] = {
+ SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_GDTBASE, EFI_SMM_SAVE_STATE_REGISTER_LDTINFO),
+ SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_ES, EFI_SMM_SAVE_STATE_REGISTER_RIP),
+ SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_RFLAGS, EFI_SMM_SAVE_STATE_REGISTER_CR4),
+ { (EFI_SMM_SAVE_STATE_REGISTER)0, (EFI_SMM_SAVE_STATE_REGISTER)0, 0}
+};
+
+// Lookup table used to retrieve the widths and offsets associated with each
+// supported EFI_SMM_SAVE_STATE_REGISTER value
+CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmSmramCpuWidthOffset[] = {
+ { 0, 0, 0, 0, FALSE }, // Reserved
+
+ //
+ // Internally defined CPU Save State Registers. Not defined in PI SMM CPU Protocol.
+ //
+ { 4, 4, SMM_CPU_OFFSET (x86.SMMRevId), SMM_CPU_OFFSET (x64.SMMRevId), 0, FALSE}, // SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX = 1
+
+ //
+ // CPU Save State registers defined in PI SMM CPU Protocol.
+ //
+ { 4, 8, SMM_CPU_OFFSET (x86.GDTBase), SMM_CPU_OFFSET (x64._GDTRBaseLoDword), SMM_CPU_OFFSET (x64._GDTRBaseHiDword), FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_GDTBASE = 4
+ { 0, 8, 0, SMM_CPU_OFFSET (x64._IDTRBaseLoDword), SMM_CPU_OFFSET (x64._IDTRBaseLoDword), FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_IDTBASE = 5
+ { 0, 8, 0, SMM_CPU_OFFSET (x64._LDTRBaseLoDword), SMM_CPU_OFFSET (x64._LDTRBaseLoDword), FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTBASE = 6
+ { 0, 2, 0, SMM_CPU_OFFSET (x64._GDTRLimit), 0, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_GDTLIMIT = 7
+ { 0, 2, 0, SMM_CPU_OFFSET (x64._IDTRLimit), 0, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_IDTLIMIT = 8
+ { 0, 4, 0, SMM_CPU_OFFSET (x64._LDTRLimit), 0, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTLIMIT = 9
+ { 0, 0, 0, 0, 0, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTINFO = 10
+ { 4, 2, SMM_CPU_OFFSET (x86._ES), SMM_CPU_OFFSET (x64._ES), 0, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_ES = 20
+ { 4, 2, SMM_CPU_OFFSET (x86._CS), SMM_CPU_OFFSET (x64._CS), 0, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CS = 21
+ { 4, 2, SMM_CPU_OFFSET (x86._SS), SMM_CPU_OFFSET (x64._SS), 0, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_SS = 22
+ { 4, 2, SMM_CPU_OFFSET (x86._DS), SMM_CPU_OFFSET (x64._DS), 0, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_DS = 23
+ { 4, 2, SMM_CPU_OFFSET (x86._FS), SMM_CPU_OFFSET (x64._FS), 0, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_FS = 24
+ { 4, 2, SMM_CPU_OFFSET (x86._GS), SMM_CPU_OFFSET (x64._GS), 0, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_GS = 25
+ { 0, 2, 0, SMM_CPU_OFFSET (x64._LDTR), 0, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTR_SEL = 26
+ { 0, 2, 0, SMM_CPU_OFFSET (x64._TR), 0, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_TR_SEL = 27
+ { 4, 8, SMM_CPU_OFFSET (x86._DR7), SMM_CPU_OFFSET (x64._DR7), SMM_CPU_OFFSET (x64._DR7) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_DR7 = 28
+ { 4, 8, SMM_CPU_OFFSET (x86._DR6), SMM_CPU_OFFSET (x64._DR6), SMM_CPU_OFFSET (x64._DR6) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_DR6 = 29
+ { 0, 8, 0, SMM_CPU_OFFSET (x64._R8), SMM_CPU_OFFSET (x64._R8) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_R8 = 30
+ { 0, 8, 0, SMM_CPU_OFFSET (x64._R9), SMM_CPU_OFFSET (x64._R9) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_R9 = 31
+ { 0, 8, 0, SMM_CPU_OFFSET (x64._R10), SMM_CPU_OFFSET (x64._R10) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_R10 = 32
+ { 0, 8, 0, SMM_CPU_OFFSET (x64._R11), SMM_CPU_OFFSET (x64._R11) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_R11 = 33
+ { 0, 8, 0, SMM_CPU_OFFSET (x64._R12), SMM_CPU_OFFSET (x64._R12) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_R12 = 34
+ { 0, 8, 0, SMM_CPU_OFFSET (x64._R13), SMM_CPU_OFFSET (x64._R13) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_R13 = 35
+ { 0, 8, 0, SMM_CPU_OFFSET (x64._R14), SMM_CPU_OFFSET (x64._R14) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_R14 = 36
+ { 0, 8, 0, SMM_CPU_OFFSET (x64._R15), SMM_CPU_OFFSET (x64._R15) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_R15 = 37
+ { 4, 8, SMM_CPU_OFFSET (x86._EAX), SMM_CPU_OFFSET (x64._RAX), SMM_CPU_OFFSET (x64._RAX) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_RAX = 38
+ { 4, 8, SMM_CPU_OFFSET (x86._EBX), SMM_CPU_OFFSET (x64._RBX), SMM_CPU_OFFSET (x64._RBX) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_RBX = 39
+ { 4, 8, SMM_CPU_OFFSET (x86._ECX), SMM_CPU_OFFSET (x64._RCX), SMM_CPU_OFFSET (x64._RCX) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_RBX = 39
+ { 4, 8, SMM_CPU_OFFSET (x86._EDX), SMM_CPU_OFFSET (x64._RDX), SMM_CPU_OFFSET (x64._RDX) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_RDX = 41
+ { 4, 8, SMM_CPU_OFFSET (x86._ESP), SMM_CPU_OFFSET (x64._RSP), SMM_CPU_OFFSET (x64._RSP) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_RSP = 42
+ { 4, 8, SMM_CPU_OFFSET (x86._EBP), SMM_CPU_OFFSET (x64._RBP), SMM_CPU_OFFSET (x64._RBP) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_RBP = 43
+ { 4, 8, SMM_CPU_OFFSET (x86._ESI), SMM_CPU_OFFSET (x64._RSI), SMM_CPU_OFFSET (x64._RSI) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_RSI = 44
+ { 4, 8, SMM_CPU_OFFSET (x86._EDI), SMM_CPU_OFFSET (x64._RDI), SMM_CPU_OFFSET (x64._RDI) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_RDI = 45
+ { 4, 8, SMM_CPU_OFFSET (x86._EIP), SMM_CPU_OFFSET (x64._RIP), SMM_CPU_OFFSET (x64._RIP) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_RIP = 46
+
+ { 4, 8, SMM_CPU_OFFSET (x86._EFLAGS), SMM_CPU_OFFSET (x64._RFLAGS), SMM_CPU_OFFSET (x64._RFLAGS) + 4, TRUE}, // EFI_SMM_SAVE_STATE_REGISTER_RFLAGS = 51
+ { 4, 8, SMM_CPU_OFFSET (x86._CR0), SMM_CPU_OFFSET (x64._CR0), SMM_CPU_OFFSET (x64._CR0) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CR0 = 52
+ { 4, 8, SMM_CPU_OFFSET (x86._CR3), SMM_CPU_OFFSET (x64._CR3), SMM_CPU_OFFSET (x64._CR3) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CR3 = 53
+ { 0, 8, 0, SMM_CPU_OFFSET (x64._CR4), SMM_CPU_OFFSET (x64._CR4) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CR4 = 54
+ { 0, 0, 0, 0, 0 }
+};
+
+/**
+ Read an SMM Save State register on the target processor. If this function
+ returns EFI_UNSUPPORTED, then the caller is responsible for reading the
+ SMM Save Sate register.
+
+ @param[in] CpuIndex The index of the CPU to read the SMM Save State. The
+ value must be between 0 and the NumberOfCpus field in
+ the System Management System Table (SMST).
+ @param[in] Register The SMM Save State register to read.
+ @param[in] Width The number of bytes to read from the CPU save state.
+ @param[out] Buffer Upon return, this holds the CPU register value read
+ from the save state.
+
+ @retval EFI_SUCCESS The register was read from Save State.
+ @retval EFI_INVALID_PARAMTER Buffer is NULL.
+ @retval EFI_UNSUPPORTED This function does not support reading Register.
+ @retval EFI_NOT_FOUND If desired Register not found.
+**/
+EFI_STATUS
+EFIAPI
+SmramSaveStateReadRegister (
+ IN UINTN CpuIndex,
+ IN EFI_SMM_SAVE_STATE_REGISTER Register,
+ IN UINTN Width,
+ OUT VOID *Buffer
+ )
+{
+ UINT32 SmmRevId;
+ EFI_SMM_SAVE_STATE_IO_INFO *IoInfo;
+ AMD_SMRAM_SAVE_STATE_MAP *CpuSaveState;
+ UINT8 DataWidth;
+
+ // Read CPU State
+ CpuSaveState = (AMD_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex];
+
+ // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA
+ if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {
+ // Only byte access is supported for this register
+ if (Width != 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *(UINT8 *)Buffer = SmramSaveStateGetRegisterLma ();
+
+ return EFI_SUCCESS;
+ }
+
+ // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO
+
+ if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {
+ //
+ // Get SMM Revision ID
+ //
+ SmramSaveStateReadRegisterByIndex (CpuIndex, SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX, sizeof (SmmRevId), &SmmRevId);
+
+ //
+ // See if the CPU supports the IOMisc register in the save state
+ //
+ if (SmmRevId < AMD_SMM_MIN_REV_ID_X64) {
+ return EFI_NOT_FOUND;
+ }
+
+ // Check if IO Restart Dword [IO Trap] is valid or not using bit 1.
+ if (!(CpuSaveState->x64.IO_DWord & 0x02u)) {
+ return EFI_NOT_FOUND;
+ }
+
+ // Zero the IoInfo structure that will be returned in Buffer
+ IoInfo = (EFI_SMM_SAVE_STATE_IO_INFO *)Buffer;
+ ZeroMem (IoInfo, sizeof (EFI_SMM_SAVE_STATE_IO_INFO));
+
+ IoInfo->IoPort = (UINT16)(CpuSaveState->x64.IO_DWord >> 16u);
+
+ if (CpuSaveState->x64.IO_DWord & 0x10u) {
+ IoInfo->IoWidth = EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8;
+ DataWidth = 0x01u;
+ } else if (CpuSaveState->x64.IO_DWord & 0x20u) {
+ IoInfo->IoWidth = EFI_SMM_SAVE_STATE_IO_WIDTH_UINT16;
+ DataWidth = 0x02u;
+ } else {
+ IoInfo->IoWidth = EFI_SMM_SAVE_STATE_IO_WIDTH_UINT32;
+ DataWidth = 0x04u;
+ }
+
+ if (CpuSaveState->x64.IO_DWord & 0x01u) {
+ IoInfo->IoType = EFI_SMM_SAVE_STATE_IO_TYPE_INPUT;
+ } else {
+ IoInfo->IoType = EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT;
+ }
+
+ if ((IoInfo->IoType == EFI_SMM_SAVE_STATE_IO_TYPE_INPUT) || (IoInfo->IoType == EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT)) {
+ SmramSaveStateReadRegister (CpuIndex, EFI_SMM_SAVE_STATE_REGISTER_RAX, DataWidth, &IoInfo->IoData);
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ // Convert Register to a register lookup table index
+ return SmramSaveStateReadRegisterByIndex (CpuIndex, SmramSaveStateGetRegisterIndex (Register), Width, Buffer);
+}
+
+/**
+ Writes an SMM Save State register on the target processor. If this function
+ returns EFI_UNSUPPORTED, then the caller is responsible for writing the
+ SMM Save Sate register.
+
+ @param[in] CpuIndex The index of the CPU to write the SMM Save State. The
+ value must be between 0 and the NumberOfCpus field in
+ the System Management System Table (SMST).
+ @param[in] Register The SMM Save State register to write.
+ @param[in] Width The number of bytes to write to the CPU save state.
+ @param[in] Buffer Upon entry, this holds the new CPU register value.
+
+ @retval EFI_SUCCESS The register was written to Save State.
+ @retval EFI_INVALID_PARAMTER Buffer is NULL.
+ @retval EFI_UNSUPPORTED This function does not support writing Register.
+ @retval EFI_NOT_FOUND If desired Register not found.
+**/
+EFI_STATUS
+EFIAPI
+SmramSaveStateWriteRegister (
+ IN UINTN CpuIndex,
+ IN EFI_SMM_SAVE_STATE_REGISTER Register,
+ IN UINTN Width,
+ IN CONST VOID *Buffer
+ )
+{
+ UINTN RegisterIndex;
+ AMD_SMRAM_SAVE_STATE_MAP *CpuSaveState;
+
+ //
+ // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored
+ //
+ if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported
+ //
+ if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Convert Register to a register lookup table index
+ //
+ RegisterIndex = SmramSaveStateGetRegisterIndex (Register);
+ if (RegisterIndex == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ CpuSaveState = gSmst->CpuSaveState[CpuIndex];
+
+ //
+ // Do not write non-writable SaveState, because it will cause exception.
+ //
+ if (!mSmmSmramCpuWidthOffset[RegisterIndex].Writeable) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check CPU mode
+ //
+ if (SmramSaveStateGetRegisterLma () == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {
+ //
+ // If 32-bit mode width is zero, then the specified register can not be accessed
+ //
+ if (mSmmSmramCpuWidthOffset[RegisterIndex].Width32 == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
+ //
+ if (Width > mSmmSmramCpuWidthOffset[RegisterIndex].Width32) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Write SMM State register
+ //
+ ASSERT (CpuSaveState != NULL);
+ CopyMem ((UINT8 *)CpuSaveState + mSmmSmramCpuWidthOffset[RegisterIndex].Offset32, Buffer, Width);
+ } else {
+ //
+ // If 64-bit mode width is zero, then the specified register can not be accessed
+ //
+ if (mSmmSmramCpuWidthOffset[RegisterIndex].Width64 == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
+ //
+ if (Width > mSmmSmramCpuWidthOffset[RegisterIndex].Width64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Write lower 32-bits of SMM State register
+ //
+ CopyMem ((UINT8 *)CpuSaveState + mSmmSmramCpuWidthOffset[RegisterIndex].Offset64Lo, Buffer, MIN (4, Width));
+ if (Width >= 4) {
+ //
+ // Write upper 32-bits of SMM State register
+ //
+ CopyMem ((UINT8 *)CpuSaveState + mSmmSmramCpuWidthOffset[RegisterIndex].Offset64Hi, (UINT8 *)Buffer + 4, Width - 4);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns LMA value of the Processor.
+
+ @param[in] VOID
+
+ @retval UINT8 returns LMA bit value.
+**/
+UINT8
+SmramSaveStateGetRegisterLma (
+ VOID
+ )
+{
+ UINT32 LMAValue;
+
+ LMAValue = (UINT32)AsmReadMsr64 (EFER_ADDRESS) & LMA;
+ if (LMAValue) {
+ return EFI_SMM_SAVE_STATE_REGISTER_LMA_64BIT;
+ }
+
+ return EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT;
+}
diff --git a/UefiCpuPkg/Library/SmmSmramSaveStateLib/SmramSaveStateCommon.c b/UefiCpuPkg/Library/SmmSmramSaveStateLib/SmramSaveStateCommon.c
new file mode 100644
index 000000000000..98e89f9eec3f
--- /dev/null
+++ b/UefiCpuPkg/Library/SmmSmramSaveStateLib/SmramSaveStateCommon.c
@@ -0,0 +1,124 @@
+/** @file
+ Provides common supporting function to access SMRAM Save State Map
+
+ Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+ Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SmramSaveState.h"
+
+extern CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmSmramCpuRegisterRanges[];
+extern CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmSmramCpuWidthOffset[];
+
+/**
+ Read information from the CPU save state.
+
+ @param Register Specifies the CPU register to read form the save state.
+
+ @retval 0 Register is not valid
+ @retval >0 Index into mSmmSmramCpuWidthOffset[] associated with Register
+
+**/
+UINTN
+EFIAPI
+SmramSaveStateGetRegisterIndex (
+ IN EFI_SMM_SAVE_STATE_REGISTER Register
+ )
+{
+ UINTN Index;
+ UINTN Offset;
+
+ for (Index = 0, Offset = SMM_SAVE_STATE_REGISTER_MAX_INDEX; mSmmSmramCpuRegisterRanges[Index].Length != 0; Index++) {
+ if ((Register >= mSmmSmramCpuRegisterRanges[Index].Start) && (Register <= mSmmSmramCpuRegisterRanges[Index].End)) {
+ return Register - mSmmSmramCpuRegisterRanges[Index].Start + Offset;
+ }
+
+ Offset += mSmmSmramCpuRegisterRanges[Index].Length;
+ }
+
+ return 0;
+}
+
+/**
+ Read a CPU Save State register on the target processor.
+
+ This function abstracts the differences that whether the CPU Save State register is in the
+ IA32 CPU Save State Map or X64 CPU Save State Map.
+
+ This function supports reading a CPU Save State register in SMBase relocation handler.
+
+ @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
+ @param[in] RegisterIndex Index into mSmmSmramCpuWidthOffset[] look up table.
+ @param[in] Width The number of bytes to read from the CPU save state.
+ @param[out] Buffer Upon return, this holds the CPU register value read from the save state.
+
+ @retval EFI_SUCCESS The register was read from Save State.
+ @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
+ @retval EFI_INVALID_PARAMTER This or Buffer is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmramSaveStateReadRegisterByIndex (
+ IN UINTN CpuIndex,
+ IN UINTN RegisterIndex,
+ IN UINTN Width,
+ OUT VOID *Buffer
+ )
+{
+ if (RegisterIndex == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (SmramSaveStateGetRegisterLma () == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {
+ //
+ // If 32-bit mode width is zero, then the specified register can not be accessed
+ //
+ if (mSmmSmramCpuWidthOffset[RegisterIndex].Width32 == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
+ //
+ if (Width > mSmmSmramCpuWidthOffset[RegisterIndex].Width32) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Write return buffer
+ //
+ ASSERT (gSmst->CpuSaveState[CpuIndex] != NULL);
+ CopyMem (Buffer, (UINT8 *)gSmst->CpuSaveState[CpuIndex] + mSmmSmramCpuWidthOffset[RegisterIndex].Offset32, Width);
+ } else {
+ //
+ // If 64-bit mode width is zero, then the specified register can not be accessed
+ //
+ if (mSmmSmramCpuWidthOffset[RegisterIndex].Width64 == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
+ //
+ if (Width > mSmmSmramCpuWidthOffset[RegisterIndex].Width64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Write lower 32-bits of return buffer
+ //
+ CopyMem (Buffer, (UINT8 *)gSmst->CpuSaveState[CpuIndex] + mSmmSmramCpuWidthOffset[RegisterIndex].Offset64Lo, MIN (4, Width));
+ if (Width >= 4) {
+ //
+ // Write upper 32-bits of return buffer
+ //
+ CopyMem ((UINT8 *)Buffer + 4, (UINT8 *)gSmst->CpuSaveState[CpuIndex] + mSmmSmramCpuWidthOffset[RegisterIndex].Offset64Hi, Width - 4);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
--
2.25.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#102774): https://edk2.groups.io/g/devel/message/102774
Mute This Topic: https://groups.io/mt/98172963/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
> +
> SmmSmramSaveStateLib|UefiCpuPkg/Library/SmmSmramSaveStateLib/Am
> dSmmSmramSaveStateLib.inf
1. The lib instance name can be AmdMmSaveStateLib inside X86MmSaveStateLib folder.
> +[Defines]
> + INF_VERSION = 1.29
> + BASE_NAME = AmdSmmSmramSaveStateLib
> + FILE_GUID = FB7D0A60-E8D4-4EFA-90AA-B357BC569879
> + MODULE_TYPE = DXE_SMM_DRIVER
2. The module type can be BASE.
> + VERSION_STRING = 1.0
> + LIBRARY_CLASS = SmmSmramSaveStateLib
3. The LIBRARY_CLASS can be "MmSaveStateLib|DXE_SMM_DRIVER MM_STANDALONE" indicating it supports the two types of modules.
> +typedef struct {
> + UINT8 Width32;
> + UINT8 Width64;
> + UINT16 Offset32;
> + UINT16 Offset64Lo;
> + UINT16 Offset64Hi;
4. With above structure definition "Offset64Lo/Offset64Hi", I realized that you define AMD_SMRAM_SAVE_STATE_MAP64 in a way
to split the lower 32bit and high 32bit to two fields. I think it's only needed when the lower 32bit and higher 32bit are not adjacent.
Otherwise, you can just define "UINT64 _IDTRBase" in AMD_SMRAM_SAVE_STATE_MAP64.
(Unfortunately, GdtBase/LdtBase/IdtBase are split to two 32bit fields not adjacent to each other in Intel 64bit save state. But AMD
doesn't need to.)
So the recommendation here is to do some simplification to the AMD 64bit save state definition.
5. Another thought here: Can we remove "AMD_" prefix from the structure name "AMD_SMRAM_SAVE_STATE_MAP64"?
Because when we define CPUIDs or MSRs, we don't put "INTEL_" or "AMD_" prefix either.
The definition file is in "MdePkg/Include/Register/Amd" folder which already indicates it's AMD specific definition.
> +**/
> +UINTN
> +EFIAPI
6. No need for "EFIAPI".
> +SmramSaveStateGetRegisterIndex (
7. Since it's not an API, can it be renamed as "MmSaveStateLibGetRegisterIndex"?
> + IN EFI_SMM_SAVE_STATE_REGISTER Register
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SmramSaveStateReadRegisterByIndex (
> + IN UINTN CpuIndex,
> + IN UINTN RegisterIndex,
> + IN UINTN Width,
> + OUT VOID *Buffer
> + )
> +{
> + if (RegisterIndex == 0) {
> + return EFI_NOT_FOUND;
> + }
> +
> + if (SmramSaveStateGetRegisterLma () ==
> EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {
> + //
> + // If 32-bit mode width is zero, then the specified register can not be
> accessed
> + //
> + if (mSmmSmramCpuWidthOffset[RegisterIndex].Width32 == 0) {
> + return EFI_NOT_FOUND;
> + }
> +
> + //
> + // If Width is bigger than the 32-bit mode width, then the specified
> register can not be accessed
> + //
> + if (Width > mSmmSmramCpuWidthOffset[RegisterIndex].Width32) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // Write return buffer
> + //
> + ASSERT (gSmst->CpuSaveState[CpuIndex] != NULL);
> + CopyMem (Buffer, (UINT8 *)gSmst->CpuSaveState[CpuIndex] +
> mSmmSmramCpuWidthOffset[RegisterIndex].Offset32, Width);
> + } else {
> + //
> + // If 64-bit mode width is zero, then the specified register can not be
> accessed
> + //
> + if (mSmmSmramCpuWidthOffset[RegisterIndex].Width64 == 0) {
> + return EFI_NOT_FOUND;
> + }
> +
> + //
> + // If Width is bigger than the 64-bit mode width, then the specified
> register can not be accessed
> + //
> + if (Width > mSmmSmramCpuWidthOffset[RegisterIndex].Width64) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // Write lower 32-bits of return buffer
> + //
> + CopyMem (Buffer, (UINT8 *)gSmst->CpuSaveState[CpuIndex] +
> mSmmSmramCpuWidthOffset[RegisterIndex].Offset64Lo, MIN (4, Width));
> + if (Width >= 4) {
> + //
> + // Write upper 32-bits of return buffer
> + //
> + CopyMem ((UINT8 *)Buffer + 4, (UINT8 *)gSmst-
> >CpuSaveState[CpuIndex] +
> mSmmSmramCpuWidthOffset[RegisterIndex].Offset64Hi, Width - 4);
> + }
> + }
> +
> + return EFI_SUCCESS;
8. I feel the above logic that reads from 32bit/64bit SMRAM save state can be
written in a simpler way.
But since the logic aligns with the existing one in CpuSmm driver, I am ok that we
do the simplification in other time.
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#102812): https://edk2.groups.io/g/devel/message/102812
Mute This Topic: https://groups.io/mt/98172963/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/3901457/1787277/102458076/xyzzy [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
© 2016 - 2026 Red Hat, Inc.