/** @file | |
Functions and types shared by the SMM accessor PEI and DXE modules. | |
Copyright (C) 2015, Red Hat, Inc. | |
Copyright (c) 2024 Intel Corporation. | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <IndustryStandard/Q35MchIch9.h> | |
#include <Library/DebugLib.h> | |
#include <Library/PcdLib.h> | |
#include <Library/PciLib.h> | |
#include "SmramInternal.h" | |
// | |
// The value of PcdQ35TsegMbytes is saved into this variable at module startup. | |
// | |
UINT16 mQ35TsegMbytes; | |
// | |
// The value of PcdQ35SmramAtDefaultSmbase is saved into this variable at | |
// module startup. | |
// | |
STATIC BOOLEAN mQ35SmramAtDefaultSmbase; | |
/** | |
Save PcdQ35TsegMbytes into mQ35TsegMbytes. | |
**/ | |
VOID | |
InitQ35TsegMbytes ( | |
VOID | |
) | |
{ | |
mQ35TsegMbytes = PcdGet16 (PcdQ35TsegMbytes); | |
} | |
/** | |
Save PcdQ35SmramAtDefaultSmbase into mQ35SmramAtDefaultSmbase. | |
**/ | |
VOID | |
InitQ35SmramAtDefaultSmbase ( | |
VOID | |
) | |
{ | |
mQ35SmramAtDefaultSmbase = PcdGetBool (PcdQ35SmramAtDefaultSmbase); | |
} | |
/** | |
Read the MCH_SMRAM and ESMRAMC registers, and update the LockState and | |
OpenState fields in the PEI_SMM_ACCESS_PPI / EFI_SMM_ACCESS2_PROTOCOL object, | |
from the D_LCK and T_EN bits. | |
PEI_SMM_ACCESS_PPI and EFI_SMM_ACCESS2_PROTOCOL member functions can rely on | |
the LockState and OpenState fields being up-to-date on entry, and they need | |
to restore the same invariant on exit, if they touch the bits in question. | |
@param[out] LockState Reflects the D_LCK bit on output; TRUE iff SMRAM is | |
locked. | |
@param[out] OpenState Reflects the inverse of the T_EN bit on output; TRUE | |
iff SMRAM is open. | |
**/ | |
VOID | |
GetStates ( | |
OUT BOOLEAN *LockState, | |
OUT BOOLEAN *OpenState | |
) | |
{ | |
UINT8 SmramVal, EsmramcVal; | |
SmramVal = PciRead8 (DRAMC_REGISTER_Q35 (MCH_SMRAM)); | |
EsmramcVal = PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC)); | |
*LockState = !!(SmramVal & MCH_SMRAM_D_LCK); | |
*OpenState = !(EsmramcVal & MCH_ESMRAMC_T_EN); | |
} | |
// | |
// The functions below follow the PEI_SMM_ACCESS_PPI and | |
// EFI_SMM_ACCESS2_PROTOCOL member declarations. The PeiServices and This | |
// pointers are removed (TSEG doesn't depend on them), and so is the | |
// DescriptorIndex parameter (TSEG doesn't support range-wise locking). | |
// | |
// The LockState and OpenState members that are common to both | |
// PEI_SMM_ACCESS_PPI and EFI_SMM_ACCESS2_PROTOCOL are taken and updated in | |
// isolation from the rest of the (non-shared) members. | |
// | |
EFI_STATUS | |
SmramAccessOpen ( | |
OUT BOOLEAN *LockState, | |
OUT BOOLEAN *OpenState | |
) | |
{ | |
// | |
// Open TSEG by clearing T_EN. | |
// | |
PciAnd8 ( | |
DRAMC_REGISTER_Q35 (MCH_ESMRAMC), | |
(UINT8)((~(UINT32)MCH_ESMRAMC_T_EN) & 0xff) | |
); | |
GetStates (LockState, OpenState); | |
if (!*OpenState) { | |
return EFI_DEVICE_ERROR; | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
SmramAccessClose ( | |
OUT BOOLEAN *LockState, | |
OUT BOOLEAN *OpenState | |
) | |
{ | |
// | |
// Close TSEG by setting T_EN. | |
// | |
PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), MCH_ESMRAMC_T_EN); | |
GetStates (LockState, OpenState); | |
if (*OpenState) { | |
return EFI_DEVICE_ERROR; | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
SmramAccessLock ( | |
OUT BOOLEAN *LockState, | |
IN OUT BOOLEAN *OpenState | |
) | |
{ | |
if (*OpenState) { | |
return EFI_DEVICE_ERROR; | |
} | |
// | |
// Close & lock TSEG by setting T_EN and D_LCK. | |
// | |
PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), MCH_ESMRAMC_T_EN); | |
PciOr8 (DRAMC_REGISTER_Q35 (MCH_SMRAM), MCH_SMRAM_D_LCK); | |
// | |
// Close & lock the SMRAM at the default SMBASE, if it exists. | |
// | |
if (mQ35SmramAtDefaultSmbase) { | |
PciWrite8 ( | |
DRAMC_REGISTER_Q35 (MCH_DEFAULT_SMBASE_CTL), | |
MCH_DEFAULT_SMBASE_LCK | |
); | |
} | |
GetStates (LockState, OpenState); | |
if (*OpenState || !*LockState) { | |
return EFI_DEVICE_ERROR; | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
SmramAccessGetCapabilities ( | |
IN OUT UINTN *SmramMapSize, | |
IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap | |
) | |
{ | |
UINTN BufferSize; | |
EFI_HOB_GUID_TYPE *GuidHob; | |
EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock; | |
UINTN Index; | |
// | |
// Get Hob list | |
// | |
GuidHob = GetFirstGuidHob (&gEfiSmmSmramMemoryGuid); | |
DescriptorBlock = GET_GUID_HOB_DATA (GuidHob); | |
ASSERT (DescriptorBlock); | |
BufferSize = DescriptorBlock->NumberOfSmmReservedRegions * sizeof (EFI_SMRAM_DESCRIPTOR); | |
if (*SmramMapSize < BufferSize) { | |
*SmramMapSize = BufferSize; | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
// | |
// Update SmramMapSize to real return SMRAM map size | |
// | |
*SmramMapSize = BufferSize; | |
// | |
// Use the hob to publish SMRAM capabilities | |
// | |
for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) { | |
SmramMap[Index].PhysicalStart = DescriptorBlock->Descriptor[Index].PhysicalStart; | |
SmramMap[Index].CpuStart = DescriptorBlock->Descriptor[Index].CpuStart; | |
SmramMap[Index].PhysicalSize = DescriptorBlock->Descriptor[Index].PhysicalSize; | |
SmramMap[Index].RegionState = DescriptorBlock->Descriptor[Index].RegionState; | |
} | |
return EFI_SUCCESS; | |
} |