/** @file
|
Helper functions for PCH SMM dispatcher.
|
|
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
#include "PchSmmHelpers.h"
|
|
///
|
/// SUPPORT / HELPER FUNCTIONS (PCH version-independent)
|
///
|
|
/**
|
Compare 2 SMM source descriptors' enable settings.
|
|
@param[in] Src1 Pointer to the PCH SMI source description table 1
|
@param[in] Src2 Pointer to the PCH SMI source description table 2
|
|
@retval TRUE The enable settings of the 2 SMM source descriptors are identical.
|
@retval FALSE The enable settings of the 2 SMM source descriptors are not identical.
|
**/
|
BOOLEAN
|
CompareEnables (
|
CONST IN PCH_SMM_SOURCE_DESC *Src1,
|
CONST IN PCH_SMM_SOURCE_DESC *Src2
|
)
|
{
|
BOOLEAN IsEqual;
|
UINTN DescIndex;
|
|
IsEqual = TRUE;
|
for (DescIndex = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
|
///
|
/// It's okay to compare a NULL bit description to a non-NULL bit description.
|
/// They are unequal and these tests will generate the correct result.
|
///
|
if (Src1->En[DescIndex].Bit != Src2->En[DescIndex].Bit ||
|
Src1->En[DescIndex].Reg.Type != Src2->En[DescIndex].Reg.Type ||
|
Src1->En[DescIndex].Reg.Data.raw != Src2->En[DescIndex].Reg.Data.raw
|
) {
|
IsEqual = FALSE;
|
break;
|
///
|
/// out of for loop
|
///
|
}
|
}
|
|
return IsEqual;
|
}
|
|
/**
|
Compare a bit descriptor to the enables of source descriptor. Includes null address type.
|
|
@param[in] BitDesc Pointer to the PCH SMI bit descriptor
|
@param[in] Src Pointer to the PCH SMI source description table 2
|
|
@retval TRUE The bit desc is equal to any of the enables in source descriptor
|
@retval FALSE The bid desc is not equal to all of the enables in source descriptor
|
**/
|
BOOLEAN
|
IsBitEqualToAnySourceEn (
|
CONST IN PCH_SMM_BIT_DESC *BitDesc,
|
CONST IN PCH_SMM_SOURCE_DESC *Src
|
)
|
{
|
BOOLEAN IsEqual;
|
UINTN DescIndex;
|
|
IsEqual = FALSE;
|
|
for (DescIndex = 0; DescIndex < NUM_EN_BITS; ++DescIndex) {
|
if ((BitDesc->Reg.Type == Src->En[DescIndex].Reg.Type) &&
|
(BitDesc->Reg.Data.raw == Src->En[DescIndex].Reg.Data.raw) &&
|
(BitDesc->Bit == Src->En[DescIndex].Bit)) {
|
IsEqual = TRUE;
|
break;
|
}
|
}
|
return IsEqual;
|
}
|
|
/**
|
Compare 2 SMM source descriptors' statuses.
|
|
@param[in] Src1 Pointer to the PCH SMI source description table 1
|
@param[in] Src2 Pointer to the PCH SMI source description table 2
|
|
@retval TRUE The statuses of the 2 SMM source descriptors are identical.
|
@retval FALSE The statuses of the 2 SMM source descriptors are not identical.
|
**/
|
BOOLEAN
|
CompareStatuses (
|
CONST IN PCH_SMM_SOURCE_DESC *Src1,
|
CONST IN PCH_SMM_SOURCE_DESC *Src2
|
)
|
{
|
BOOLEAN IsEqual;
|
UINTN DescIndex;
|
|
IsEqual = TRUE;
|
|
for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
|
///
|
/// It's okay to compare a NULL bit description to a non-NULL bit description.
|
/// They are unequal and these tests will generate the correct result.
|
///
|
if (Src1->Sts[DescIndex].Bit != Src2->Sts[DescIndex].Bit ||
|
Src1->Sts[DescIndex].Reg.Type != Src2->Sts[DescIndex].Reg.Type ||
|
Src1->Sts[DescIndex].Reg.Data.raw != Src2->Sts[DescIndex].Reg.Data.raw
|
) {
|
IsEqual = FALSE;
|
break;
|
///
|
/// out of for loop
|
///
|
}
|
}
|
|
return IsEqual;
|
}
|
|
/**
|
Compare 2 SMM source descriptors, based on Enable settings and Status settings of them.
|
|
@param[in] Src1 Pointer to the PCH SMI source description table 1
|
@param[in] Src2 Pointer to the PCH SMI source description table 2
|
|
@retval TRUE The 2 SMM source descriptors are identical.
|
@retval FALSE The 2 SMM source descriptors are not identical.
|
**/
|
BOOLEAN
|
CompareSources (
|
CONST IN PCH_SMM_SOURCE_DESC *Src1,
|
CONST IN PCH_SMM_SOURCE_DESC *Src2
|
)
|
{
|
return (BOOLEAN) (CompareEnables (Src1, Src2) && CompareStatuses (Src1, Src2));
|
}
|
|
/**
|
Check if an SMM source is active.
|
|
@param[in] Src Pointer to the PCH SMI source description table
|
@param[in] SciEn Indicate if SCI is enabled or not
|
@param[in] SmiEnValue Value from R_PCH_SMI_EN
|
@param[in] SmiStsValue Value from R_PCH_SMI_STS
|
|
@retval TRUE It is active.
|
@retval FALSE It is inactive.
|
**/
|
BOOLEAN
|
SourceIsActive (
|
CONST IN PCH_SMM_SOURCE_DESC *Src,
|
CONST IN BOOLEAN SciEn,
|
CONST IN UINT32 SmiEnValue,
|
CONST IN UINT32 SmiStsValue
|
)
|
{
|
UINTN DescIndex;
|
|
///
|
/// This source is dependent on SciEn, and SciEn == 1. An ACPI OS is present,
|
/// so we shouldn't do anything w/ this source until SciEn == 0.
|
///
|
if ((Src->Flags == PCH_SMM_SCI_EN_DEPENDENT) && (SciEn)) {
|
return FALSE;
|
}
|
|
///
|
/// Checking top level SMI status. If the status is not active, return false immediately
|
///
|
if (!IS_BIT_DESC_NULL (Src->PmcSmiSts)) {
|
if ((Src->PmcSmiSts.Reg.Type == ACPI_ADDR_TYPE) &&
|
(Src->PmcSmiSts.Reg.Data.acpi == R_PCH_SMI_STS) &&
|
((SmiStsValue & (1u << Src->PmcSmiSts.Bit)) == 0)) {
|
return FALSE;
|
}
|
}
|
|
///
|
/// Read each bit desc from hardware and make sure it's a one
|
///
|
for (DescIndex = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
|
if (!IS_BIT_DESC_NULL (Src->En[DescIndex])) {
|
if ((Src->En[DescIndex].Reg.Type == ACPI_ADDR_TYPE) &&
|
(Src->En[DescIndex].Reg.Data.acpi == R_PCH_SMI_EN) &&
|
((SmiEnValue & (1u << Src->En[DescIndex].Bit)) == 0)) {
|
return FALSE;
|
} else if (ReadBitDesc (&Src->En[DescIndex]) == 0) {
|
return FALSE;
|
}
|
}
|
}
|
|
///
|
/// Read each bit desc from hardware and make sure it's a one
|
///
|
for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
|
if (!IS_BIT_DESC_NULL (Src->Sts[DescIndex])) {
|
if ((Src->Sts[DescIndex].Reg.Type == ACPI_ADDR_TYPE) &&
|
(Src->Sts[DescIndex].Reg.Data.acpi == R_PCH_SMI_STS) &&
|
((SmiStsValue & (1u << Src->Sts[DescIndex].Bit)) == 0)) {
|
return FALSE;
|
} else if (ReadBitDesc (&Src->Sts[DescIndex]) == 0) {
|
return FALSE;
|
}
|
}
|
}
|
|
return TRUE;
|
}
|
|
/**
|
Enable the SMI source event by set the SMI enable bit, this function would also clear SMI
|
status bit to make initial state is correct
|
|
@param[in] SrcDesc Pointer to the PCH SMI source description table
|
|
**/
|
VOID
|
PchSmmEnableSource (
|
CONST PCH_SMM_SOURCE_DESC *SrcDesc
|
)
|
{
|
UINTN DescIndex;
|
|
///
|
/// Set enables to 1 by writing a 1
|
///
|
for (DescIndex = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
|
if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) {
|
WriteBitDesc (&SrcDesc->En[DescIndex], 1, FALSE);
|
}
|
}
|
///
|
/// Clear statuses to 0 by writing a 1
|
///
|
for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
|
if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) {
|
WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE);
|
}
|
}
|
}
|
|
/**
|
Disable the SMI source event by clear the SMI enable bit
|
|
@param[in] SrcDesc Pointer to the PCH SMI source description table
|
|
**/
|
VOID
|
PchSmmDisableSource (
|
CONST PCH_SMM_SOURCE_DESC *SrcDesc
|
)
|
{
|
UINTN DescIndex;
|
|
for (DescIndex = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
|
if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) {
|
WriteBitDesc (&SrcDesc->En[DescIndex], 0, FALSE);
|
}
|
}
|
}
|
|
/**
|
Clear the SMI status bit by set the source bit of SMI status register
|
|
@param[in] SrcDesc Pointer to the PCH SMI source description table
|
|
**/
|
VOID
|
PchSmmClearSource (
|
CONST PCH_SMM_SOURCE_DESC *SrcDesc
|
)
|
{
|
UINTN DescIndex;
|
|
for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
|
if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) {
|
WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE);
|
}
|
}
|
}
|
|
/**
|
Sets the source to a 1 and then waits for it to clear.
|
Be very careful when calling this function -- it will not
|
ASSERT. An acceptable case to call the function is when
|
waiting for the NEWCENTURY_STS bit to clear (which takes
|
3 RTCCLKs).
|
|
@param[in] SrcDesc Pointer to the PCH SMI source description table
|
|
**/
|
VOID
|
PchSmmClearSourceAndBlock (
|
CONST PCH_SMM_SOURCE_DESC *SrcDesc
|
)
|
{
|
UINTN DescIndex;
|
BOOLEAN IsSet;
|
|
for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
|
|
if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) {
|
///
|
/// Write the bit
|
///
|
WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE);
|
|
///
|
/// Don't return until the bit actually clears.
|
///
|
IsSet = TRUE;
|
while (IsSet) {
|
IsSet = ReadBitDesc (&SrcDesc->Sts[DescIndex]);
|
///
|
/// IsSet will eventually clear -- or else we'll have
|
/// an infinite loop.
|
///
|
}
|
}
|
}
|
}
|
|