361 lines
10 KiB
C
361 lines
10 KiB
C
/** @file
|
|
Helper functions for PCH SMM dispatcher.
|
|
|
|
@copyright
|
|
INTEL CONFIDENTIAL
|
|
Copyright 1999 - 2018 Intel Corporation.
|
|
|
|
The source code contained or described herein and all documents related to the
|
|
source code ("Material") are owned by Intel Corporation or its suppliers or
|
|
licensors. Title to the Material remains with Intel Corporation or its suppliers
|
|
and licensors. The Material may contain trade secrets and proprietary and
|
|
confidential information of Intel Corporation and its suppliers and licensors,
|
|
and is protected by worldwide copyright and trade secret laws and treaty
|
|
provisions. No part of the Material may be used, copied, reproduced, modified,
|
|
published, uploaded, posted, transmitted, distributed, or disclosed in any way
|
|
without Intel's prior express written permission.
|
|
|
|
No license under any patent, copyright, trade secret or other intellectual
|
|
property right is granted to or conferred upon you by disclosure or delivery
|
|
of the Materials, either expressly, by implication, inducement, estoppel or
|
|
otherwise. Any license under such intellectual property rights must be
|
|
express and approved by Intel in writing.
|
|
|
|
Unless otherwise agreed by Intel in writing, you may not remove or alter
|
|
this notice or any other notice embedded in Materials by Intel or
|
|
Intel's suppliers or licensors in any way.
|
|
|
|
This file contains an 'Intel Peripheral Driver' and is uniquely identified as
|
|
"Intel Reference Module" and is licensed for Intel CPUs and chipsets under
|
|
the terms of your license agreement with Intel or your vendor. This file may
|
|
be modified by the user, subject to additional terms of the license agreement.
|
|
|
|
@par Specification Reference:
|
|
**/
|
|
#include "PchSmmHelpers.h"
|
|
#include <Register/PmcRegs.h>
|
|
|
|
///
|
|
/// #define BIT_ZERO 0x00000001
|
|
///
|
|
GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT32 BIT_ZERO = 0x00000001;
|
|
|
|
///
|
|
/// 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_ACPI_IO_SMI_EN
|
|
@param[in] SmiStsValue Value from R_ACPI_IO_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_ACPI_IO_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_ACPI_IO_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_ACPI_IO_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.
|
|
///
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|