/** @file Provides services to access SMRAM Save State Map Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #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 ); }