/** @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 <PiSmm.h> | |
#include <Library/SmmCpuFeaturesLib.h> | |
#include <Library/BaseLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/SmmServicesTableLib.h> | |
#include <Library/DebugLib.h> | |
#include "PiSmmCpuDxeSmm.h" | |
typedef struct { | |
UINT64 Signature; // Offset 0x00 | |
UINT16 Reserved1; // Offset 0x08 | |
UINT16 Reserved2; // Offset 0x0A | |
UINT16 Reserved3; // Offset 0x0C | |
UINT16 SmmCs; // Offset 0x0E | |
UINT16 SmmDs; // Offset 0x10 | |
UINT16 SmmSs; // Offset 0x12 | |
UINT16 SmmOtherSegment; // Offset 0x14 | |
UINT16 Reserved4; // Offset 0x16 | |
UINT64 Reserved5; // Offset 0x18 | |
UINT64 Reserved6; // Offset 0x20 | |
UINT64 Reserved7; // Offset 0x28 | |
UINT64 SmmGdtPtr; // Offset 0x30 | |
UINT32 SmmGdtSize; // Offset 0x38 | |
UINT32 Reserved8; // Offset 0x3C | |
UINT64 Reserved9; // Offset 0x40 | |
UINT64 Reserved10; // Offset 0x48 | |
UINT16 Reserved11; // Offset 0x50 | |
UINT16 Reserved12; // Offset 0x52 | |
UINT32 Reserved13; // Offset 0x54 | |
UINT64 Reserved14; // Offset 0x58 | |
} PROCESSOR_SMM_DESCRIPTOR; | |
extern CONST PROCESSOR_SMM_DESCRIPTOR gcPsd; | |
// | |
// EFER register LMA bit | |
// | |
#define LMA BIT10 | |
/// | |
/// Variables from SMI Handler | |
/// | |
X86_ASSEMBLY_PATCH_LABEL gPatchSmbase; | |
X86_ASSEMBLY_PATCH_LABEL gPatchSmiStack; | |
X86_ASSEMBLY_PATCH_LABEL gPatchSmiCr3; | |
extern volatile UINT8 gcSmiHandlerTemplate[]; | |
extern CONST UINT16 gcSmiHandlerSize; | |
// | |
// Variables used by SMI Handler | |
// | |
IA32_DESCRIPTOR gSmiHandlerIdtr; | |
/// | |
/// The mode of the CPU at the time an SMI occurs | |
/// | |
UINT8 mSmmSaveStateRegisterLma; | |
/** | |
Get the size of the SMI Handler in bytes. | |
@retval The size, in bytes, of the SMI Handler. | |
**/ | |
UINTN | |
EFIAPI | |
GetSmiHandlerSize ( | |
VOID | |
) | |
{ | |
UINTN Size; | |
Size = SmmCpuFeaturesGetSmiHandlerSize (); | |
if (Size != 0) { | |
return Size; | |
} | |
return gcSmiHandlerSize; | |
} | |
/** | |
Install the SMI handler for the CPU specified by CpuIndex. This function | |
is called by the CPU that was elected as monarch during System Management | |
Mode initialization. | |
@param[in] CpuIndex The index of the CPU to install the custom SMI handler. | |
The value must be between 0 and the NumberOfCpus field | |
in the System Management System Table (SMST). | |
@param[in] SmBase The SMBASE address for the CPU specified by CpuIndex. | |
@param[in] SmiStack The stack to use when an SMI is processed by the | |
the CPU specified by CpuIndex. | |
@param[in] StackSize The size, in bytes, if the stack used when an SMI is | |
processed by the CPU specified by CpuIndex. | |
@param[in] GdtBase The base address of the GDT to use when an SMI is | |
processed by the CPU specified by CpuIndex. | |
@param[in] GdtSize The size, in bytes, of the GDT used when an SMI is | |
processed by the CPU specified by CpuIndex. | |
@param[in] IdtBase The base address of the IDT to use when an SMI is | |
processed by the CPU specified by CpuIndex. | |
@param[in] IdtSize The size, in bytes, of the IDT used when an SMI is | |
processed by the CPU specified by CpuIndex. | |
@param[in] Cr3 The base address of the page tables to use when an SMI | |
is processed by the CPU specified by CpuIndex. | |
**/ | |
VOID | |
EFIAPI | |
InstallSmiHandler ( | |
IN UINTN CpuIndex, | |
IN UINT32 SmBase, | |
IN VOID *SmiStack, | |
IN UINTN StackSize, | |
IN UINTN GdtBase, | |
IN UINTN GdtSize, | |
IN UINTN IdtBase, | |
IN UINTN IdtSize, | |
IN UINT32 Cr3 | |
) | |
{ | |
PROCESSOR_SMM_DESCRIPTOR *Psd; | |
UINT32 CpuSmiStack; | |
// | |
// Initialize PROCESSOR_SMM_DESCRIPTOR | |
// | |
Psd = (PROCESSOR_SMM_DESCRIPTOR *)(VOID *)((UINTN)SmBase + SMM_PSD_OFFSET); | |
CopyMem (Psd, &gcPsd, sizeof (gcPsd)); | |
Psd->SmmGdtPtr = (UINT64)GdtBase; | |
Psd->SmmGdtSize = (UINT32)GdtSize; | |
if (SmmCpuFeaturesGetSmiHandlerSize () != 0) { | |
// | |
// Install SMI handler provided by library | |
// | |
SmmCpuFeaturesInstallSmiHandler ( | |
CpuIndex, | |
SmBase, | |
SmiStack, | |
StackSize, | |
GdtBase, | |
GdtSize, | |
IdtBase, | |
IdtSize, | |
Cr3 | |
); | |
return; | |
} | |
InitShadowStack (CpuIndex, (VOID *)((UINTN)SmiStack + StackSize)); | |
// | |
// Initialize values in template before copy | |
// | |
CpuSmiStack = (UINT32)((UINTN)SmiStack + StackSize - sizeof (UINTN)); | |
PatchInstructionX86 (gPatchSmiStack, CpuSmiStack, 4); | |
PatchInstructionX86 (gPatchSmiCr3, Cr3, 4); | |
PatchInstructionX86 (gPatchSmbase, SmBase, 4); | |
gSmiHandlerIdtr.Base = IdtBase; | |
gSmiHandlerIdtr.Limit = (UINT16)(IdtSize - 1); | |
// | |
// Set the value at the top of the CPU stack to the CPU Index | |
// | |
*(UINTN *)(UINTN)CpuSmiStack = CpuIndex; | |
// | |
// Copy template to CPU specific SMI handler location | |
// | |
CopyMem ( | |
(VOID *)((UINTN)SmBase + SMM_HANDLER_OFFSET), | |
(VOID *)gcSmiHandlerTemplate, | |
gcSmiHandlerSize | |
); | |
} |