* [edk2-devel] [PATCH v2 1/7] AlderlakeSiliconPkg: Add package and library instances @ 2023-08-04 17:37 Saloni Kasbekar 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 2/7] AlderlakeSiliconPkg: Add Cpu modules Saloni Kasbekar ` (6 more replies) 0 siblings, 7 replies; 14+ messages in thread From: Saloni Kasbekar @ 2023-08-04 17:37 UTC (permalink / raw) To: devel Cc: Saloni Kasbekar, Sai Chaganty, Nate DeSimone, Isaac Oram, Rosen Chuang Create the AlderlakeSiliconPkg to provide an initial package for silicon initialization code for Alder Lake (ADL) products. Add the following libraries - - BasePciSegmentMultiSegLibPci - BaseSiConfigBlockLib - PeiPostMemSiliconPolicyInitLib - PeiPreMemSiliconPolicyInitLib Cc: Sai Chaganty <rangasai.v.chaganty@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Isaac Oram <isaac.w.oram@intel.com> Cc: Rosen Chuang <rosen.chuang@intel.com> Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com> --- .../BasePciSegmentMultiSegLibPci.inf | 37 ++ .../BasePciSegmentMultiSegLibPci.uni | 14 + .../PciSegmentLib.c | 597 ++++++++++++++++++ .../BaseSiConfigBlockLib.c | 87 +++ .../BaseSiConfigBlockLib.inf | 32 + .../PeiPostMemSiliconPolicyInitLib.c | 94 +++ .../PeiPostMemSiliconPolicyInitLib.inf | 36 ++ .../PeiPreMemSiliconPolicyInitLib.c | 98 +++ .../PeiPreMemSiliconPolicyInitLib.inf | 36 ++ 9 files changed, 1031 insertions(+) create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/BasePciSegmentMultiSegLibPci.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/BasePciSegmentMultiSegLibPci.uni create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/PciSegmentLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/BaseSiConfigBlockLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/BaseSiConfigBlockLib.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyInitLib/PeiPostMemSiliconPolicyInitLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyInitLib/PeiPostMemSiliconPolicyInitLib.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyInitLib/PeiPreMemSiliconPolicyInitLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyInitLib/PeiPreMemSiliconPolicyInitLib.inf diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/BasePciSegmentMultiSegLibPci.inf b/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/BasePciSegmentMultiSegLibPci.inf new file mode 100644 index 0000000000..f3764d0187 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/BasePciSegmentMultiSegLibPci.inf @@ -0,0 +1,37 @@ +## @file +# Instance of PCI Segment Library based on PCI Library. +# +# PCI Segment Library that layers on top of the PCI Library which only +# supports segment 0 and segment 1 PCI configuration access. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BasePciSegmentMultiSegLibPci + MODULE_UNI_FILE = BasePciSegmentMultiSegLibPci.uni + FILE_GUID = AC65B409-DF03-466e-8D2B-6FCE1079F0B2 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = PciSegmentLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + PciSegmentLib.c + +[Packages] + MdePkg/MdePkg.dec + AlderlakeSiliconPkg/SiPkg.dec + +[LibraryClasses] + BaseLib + PciLib + DebugLib + PcdLib diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/BasePciSegmentMultiSegLibPci.uni b/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/BasePciSegmentMultiSegLibPci.uni new file mode 100644 index 0000000000..dd8d74bee8 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/BasePciSegmentMultiSegLibPci.uni @@ -0,0 +1,14 @@ +// /** @file +// Instance of PCI Segment Library based on PCI Library. +// +// PCI Segment Library that layers on top of the PCI Library which only +// supports segment 0 and segment 1 PCI configuration access. +// +// Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +// SPDX-License-Identifier: BSD-2-Clause-Patent +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Instance of PCI Segment Library based on PCI Library." + +#string STR_MODULE_DESCRIPTION #language en-US "PCI Segment Library that layers on top of the PCI Library which only supports segment 0 and segment 1 PCI configuration access." diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/PciSegmentLib.c b/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/PciSegmentLib.c new file mode 100644 index 0000000000..9bcb388016 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/PciSegmentLib.c @@ -0,0 +1,597 @@ +/** @file + PCI Segment Library that layers on top of the PCI Library which only + supports segment 0 and segment 1 PCI configuration access. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Base.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/PciLib.h> +#include <Library/PciSegmentLib.h> + +/** + Assert the validity of a PCI Segment address. + A valid PCI Segment address should not contain 1's in bits 28..31 and 33..63 + and the segment should be 0 or 1. + + @param A The address to validate. + @param M Additional bits to assert to be zero. + +**/ +#define ASSERT_INVALID_PCI_SEGMENT_ADDRESS(A,M) \ + ASSERT (((A) & (0xfffffffef0000000ULL | (M))) == 0) + +/** + Convert the PCI Segment library address to PCI library address. + From ICL generation support the multiple segment, and the segment number start from BIT28, + So we convert the Segment Number offset from BIT32 to BIT28 + + @param A The address to convert. +**/ +#define PCI_SEGMENT_TO_PCI_ADDRESS(A) ((UINTN) (UINT32) ((A) | ((RShiftU64 ((A) & BIT32, 4))))) + + + +/** + Reads an 8-bit PCI configuration register. + + Reads and returns the 8-bit PCI configuration register specified by Address. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + + @return The 8-bit PCI configuration register specified by Address. + +**/ +UINT8 +EFIAPI +PciSegmentRead8 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + + return PciRead8 (PCI_SEGMENT_TO_PCI_ADDRESS (Address)); +} + +/** + Writes an 8-bit PCI configuration register. + + Writes the 8-bit PCI configuration register specified by Address with the value specified by Value. + Value is returned. This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param Value The value to write. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentWrite8 ( + IN UINT64 Address, + IN UINT8 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + + return PciWrite8 (PCI_SEGMENT_TO_PCI_ADDRESS (Address), Value); +} + +/** + Performs a bitwise OR of an 8-bit PCI configuration register with an 8-bit value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by OrData, + and writes the result to the 8-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentOr8 ( + IN UINT64 Address, + IN UINT8 OrData + ) +{ + return PciWrite8 (PCI_SEGMENT_TO_PCI_ADDRESS (Address), (UINT8) (PciSegmentRead8 (Address) | OrData)); +} + +/** + Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified by AndData, + and writes the result to the 8-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param AndData The value to AND with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentAnd8 ( + IN UINT64 Address, + IN UINT8 AndData + ) +{ + return PciSegmentWrite8 (Address, (UINT8) (PciSegmentRead8 (Address) & AndData)); +} + +/** + Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value, + followed a bitwise OR with another 8-bit value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified by AndData, + performs a bitwise OR between the result of the AND operation and the value specified by OrData, + and writes the result to the 8-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentAndThenOr8 ( + IN UINT64 Address, + IN UINT8 AndData, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 (Address, (UINT8) ((PciSegmentRead8 (Address) & AndData) | OrData)); +} + +/** + Reads a 16-bit PCI configuration register. + + Reads and returns the 16-bit PCI configuration register specified by Address. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + + @return The 16-bit PCI configuration register specified by Address. + +**/ +UINT16 +EFIAPI +PciSegmentRead16 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1); + + return PciRead16 (PCI_SEGMENT_TO_PCI_ADDRESS (Address)); +} + +/** + Writes a 16-bit PCI configuration register. + + Writes the 16-bit PCI configuration register specified by Address with the value specified by Value. + Value is returned. This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param Value The value to write. + + @return The parameter of Value. + +**/ +UINT16 +EFIAPI +PciSegmentWrite16 ( + IN UINT64 Address, + IN UINT16 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1); + + return PciWrite16 (PCI_SEGMENT_TO_PCI_ADDRESS (Address), Value); +} + +/** + Performs a bitwise OR of a 16-bit PCI configuration register with + a 16-bit value. + + Reads the 16-bit PCI configuration register specified by Address, performs a + bitwise OR between the read result and the value specified by + OrData, and writes the result to the 16-bit PCI configuration register + specified by Address. The value written to the PCI configuration register is + returned. This function must guarantee that all PCI read and write operations + are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function and + Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentOr16 ( + IN UINT64 Address, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 (Address, (UINT16) (PciSegmentRead16 (Address) | OrData)); +} + +/** + Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value, + followed a bitwise OR with another 16-bit value. + + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified by AndData, + performs a bitwise OR between the result of the AND operation and the value specified by OrData, + and writes the result to the 16-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentAndThenOr16 ( + IN UINT64 Address, + IN UINT16 AndData, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 (Address, (UINT16) ((PciSegmentRead16 (Address) & AndData) | OrData)); +} + +/** + Reads a 32-bit PCI configuration register. + + Reads and returns the 32-bit PCI configuration register specified by Address. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + + @return The 32-bit PCI configuration register specified by Address. + +**/ +UINT32 +EFIAPI +PciSegmentRead32 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); + + return PciRead32 (PCI_SEGMENT_TO_PCI_ADDRESS (Address)); +} + +/** + Writes a 32-bit PCI configuration register. + + Writes the 32-bit PCI configuration register specified by Address with the value specified by Value. + Value is returned. This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param Value The value to write. + + @return The parameter of Value. + +**/ +UINT32 +EFIAPI +PciSegmentWrite32 ( + IN UINT64 Address, + IN UINT32 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); + + return PciWrite32 (PCI_SEGMENT_TO_PCI_ADDRESS (Address), Value); +} + +/** + Performs a bitwise OR of a 32-bit PCI configuration register with a 32-bit value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by OrData, + and writes the result to the 32-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentOr32 ( + IN UINT64 Address, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) | OrData); +} + +/** + Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value, + followed a bitwise OR with another 32-bit value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified by AndData, + performs a bitwise OR between the result of the AND operation and the value specified by OrData, + and writes the result to the 32-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentAndThenOr32 ( + IN UINT64 Address, + IN UINT32 AndData, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 (Address, (PciSegmentRead32 (Address) & AndData) | OrData); +} +/** + Reads a range of PCI configuration registers into a caller supplied buffer. + + Reads the range of PCI configuration registers specified by StartAddress and + Size into the buffer specified by Buffer. This function only allows the PCI + configuration registers from a single PCI function to be read. Size is + returned. When possible 32-bit PCI configuration read cycles are used to read + from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit + and 16-bit PCI configuration read cycles may be used at the beginning and the + end of the range. + + If any reserved bits in StartAddress are set, then ASSERT(). + If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). + If Size > 0 and Buffer is NULL, then ASSERT(). + + @param StartAddress The starting address that encodes the PCI Segment, Bus, Device, + Function and Register. + @param Size The size in bytes of the transfer. + @param Buffer The pointer to a buffer receiving the data read. + + @return Size + +**/ +UINTN +EFIAPI +PciSegmentReadBuffer ( + IN UINT64 StartAddress, + IN UINTN Size, + OUT VOID *Buffer + ) +{ + UINTN ReturnValue; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0); + ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000); + + if (Size == 0) { + return Size; + } + + ASSERT (Buffer != NULL); + if (Buffer == NULL) { + return 0; + } + + // + // Save Size for return + // + ReturnValue = Size; + + if ((StartAddress & BIT0) != 0) { + // + // Read a byte if StartAddress is byte aligned + // + *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress); + StartAddress += sizeof (UINT8); + Size -= sizeof (UINT8); + Buffer = (UINT8*)Buffer + 1; + } + + if (Size >= sizeof (UINT16) && (StartAddress & BIT1) != 0) { + // + // Read a word if StartAddress is word aligned + // + WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress)); + StartAddress += sizeof (UINT16); + Size -= sizeof (UINT16); + Buffer = (UINT16*)Buffer + 1; + } + + while (Size >= sizeof (UINT32)) { + // + // Read as many double words as possible + // + WriteUnaligned32 (Buffer, PciSegmentRead32 (StartAddress)); + StartAddress += sizeof (UINT32); + Size -= sizeof (UINT32); + Buffer = (UINT32*)Buffer + 1; + } + + if (Size >= sizeof (UINT16)) { + // + // Read the last remaining word if exist + // + WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress)); + StartAddress += sizeof (UINT16); + Size -= sizeof (UINT16); + Buffer = (UINT16*)Buffer + 1; + } + + if (Size >= sizeof (UINT8)) { + // + // Read the last remaining byte if exist + // + *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress); + } + + return ReturnValue; +} + +/** + Copies the data in a caller supplied buffer to a specified range of PCI + configuration space. + + Writes the range of PCI configuration registers specified by StartAddress and + Size from the buffer specified by Buffer. This function only allows the PCI + configuration registers from a single PCI function to be written. Size is + returned. When possible 32-bit PCI configuration write cycles are used to + write from StartAdress to StartAddress + Size. Due to alignment restrictions, + 8-bit and 16-bit PCI configuration write cycles may be used at the beginning + and the end of the range. + + If any reserved bits in StartAddress are set, then ASSERT(). + If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). + If Size > 0 and Buffer is NULL, then ASSERT(). + + @param StartAddress The starting address that encodes the PCI Segment, Bus, Device, + Function and Register. + @param Size The size in bytes of the transfer. + @param Buffer The pointer to a buffer containing the data to write. + + @return The parameter of Size. + +**/ +UINTN +EFIAPI +PciSegmentWriteBuffer ( + IN UINT64 StartAddress, + IN UINTN Size, + IN VOID *Buffer + ) +{ + UINTN ReturnValue; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0); + ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000); + + if (Size == 0) { + return 0; + } + + ASSERT (Buffer != NULL); + if (Buffer == NULL) { + return 0; + } + + // + // Save Size for return + // + ReturnValue = Size; + + if ((StartAddress & BIT0) != 0) { + // + // Write a byte if StartAddress is byte aligned + // + PciSegmentWrite8 (StartAddress, *(UINT8*) Buffer); + StartAddress += sizeof (UINT8); + Size -= sizeof (UINT8); + Buffer = (UINT8*) Buffer + 1; + } + + if (Size >= sizeof (UINT16) && (StartAddress & BIT1) != 0) { + // + // Write a word if StartAddress is word aligned + // + PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer)); + StartAddress += sizeof (UINT16); + Size -= sizeof (UINT16); + Buffer = (UINT16*) Buffer + 1; + } + + while (Size >= sizeof (UINT32)) { + // + // Write as many double words as possible + // + PciSegmentWrite32 (StartAddress, ReadUnaligned32 (Buffer)); + StartAddress += sizeof (UINT32); + Size -= sizeof (UINT32); + Buffer = (UINT32*) Buffer + 1; + } + + if (Size >= sizeof (UINT16)) { + // + // Write the last remaining word if exist + // + PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer)); + StartAddress += sizeof (UINT16); + Size -= sizeof (UINT16); + Buffer = (UINT16*) Buffer + 1; + } + + if (Size >= sizeof (UINT8)) { + // + // Write the last remaining byte if exist + // + PciSegmentWrite8 (StartAddress, *(UINT8*) Buffer); + } + + return ReturnValue; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/BaseSiConfigBlockLib.c b/Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/BaseSiConfigBlockLib.c new file mode 100644 index 0000000000..93290d8371 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/BaseSiConfigBlockLib.c @@ -0,0 +1,87 @@ +/** @file + This file is BaseSiConfigBlockLib library is used to add config blocks + to config block header. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <ConfigBlock.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/ConfigBlockLib.h> +#include <Library/SiConfigBlockLib.h> + + +/** + GetComponentConfigBlockTotalSize get config block table total size. + + @param[in] ComponentBlocks Component blocks array + @param[in] TotalBlockCount Number of blocks + + @retval Size of config block table +**/ +UINT16 +EFIAPI +GetComponentConfigBlockTotalSize ( + IN COMPONENT_BLOCK_ENTRY *ComponentBlocks, + IN UINT16 TotalBlockCount + ) +{ + UINT16 TotalBlockSize; + UINT16 BlockCount; + + TotalBlockSize = 0; + for (BlockCount = 0 ; BlockCount < TotalBlockCount; BlockCount++) { + TotalBlockSize += (UINT32) ComponentBlocks[BlockCount].Size; + } + + return TotalBlockSize; +} + +/** + AddComponentConfigBlocks add all config blocks. + + @param[in] ConfigBlockTableAddress The pointer to add config blocks + @param[in] ComponentBlocks Config blocks array + @param[in] TotalBlockCount Number of blocks + + @retval EFI_SUCCESS The policy default is initialized. + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create buffer +**/ +EFI_STATUS +EFIAPI +AddComponentConfigBlocks ( + IN VOID *ConfigBlockTableAddress, + IN COMPONENT_BLOCK_ENTRY *ComponentBlocks, + IN UINT16 TotalBlockCount + ) +{ + UINT16 BlockCount; + VOID *ConfigBlockPointer; + CONFIG_BLOCK ConfigBlockBuf; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + // + // Initialize ConfigBlockPointer to NULL + // + ConfigBlockPointer = NULL; + // + // Loop to identify each config block from ComponentBlocks[] Table and add each of them + // + for (BlockCount = 0; BlockCount < TotalBlockCount; BlockCount++) { + ZeroMem (&ConfigBlockBuf, sizeof (CONFIG_BLOCK)); + CopyMem (&(ConfigBlockBuf.Header.GuidHob.Name), ComponentBlocks[BlockCount].Guid, sizeof (EFI_GUID)); + ConfigBlockBuf.Header.GuidHob.Header.HobLength = ComponentBlocks[BlockCount].Size; + ConfigBlockBuf.Header.Revision = ComponentBlocks[BlockCount].Revision; + ConfigBlockPointer = (VOID *)&ConfigBlockBuf; + Status = AddConfigBlock ((VOID *)ConfigBlockTableAddress, (VOID *)&ConfigBlockPointer); + ASSERT_EFI_ERROR (Status); + if (ComponentBlocks[BlockCount].LoadDefault != NULL) { + ComponentBlocks[BlockCount].LoadDefault (ConfigBlockPointer); + } + } + return Status; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/BaseSiConfigBlockLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/BaseSiConfigBlockLib.inf new file mode 100644 index 0000000000..097095ef0d --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/BaseSiConfigBlockLib.inf @@ -0,0 +1,32 @@ +## @file +# Component description file for the BaseSiConfigBlockLib library. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = BaseSiConfigBlockLib +FILE_GUID = 6C068D0F-F48E-48CB-B369-433E507AF4A2 +VERSION_STRING = 1.0 +MODULE_TYPE = BASE +LIBRARY_CLASS = SiConfigBlockLib + + +[LibraryClasses] +DebugLib +IoLib +ConfigBlockLib + + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + + +[Sources] +BaseSiConfigBlockLib.c + + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyInitLib/PeiPostMemSiliconPolicyInitLib.c b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyInitLib/PeiPostMemSiliconPolicyInitLib.c new file mode 100644 index 0000000000..a9d6c7e265 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyInitLib/PeiPostMemSiliconPolicyInitLib.c @@ -0,0 +1,94 @@ +/** @file + This library initialize Silicon Policy for PostMemory. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <Ppi/SiPolicy.h> +#include <Ppi/PeiSiDefaultPolicy.h> +#include <Library/PcdLib.h> +#include <Library/DebugLib.h> +#include <Library/PeiServicesLib.h> +#include <Library/SiPolicyLib.h> + +/** + Performs silicon post-mem policy initialization. + + The returned data must be used as input data for SiliconPolicyDonePostMem (), + and SiliconPolicyUpdateLib.SiliconPolicyUpdatePostMem (). + + @param[in, out] Policy Pointer to policy. + @return the initialized policy. +**/ +VOID * +EFIAPI +SiliconPolicyInitPostMem ( + IN OUT VOID *Policy + ) +{ + EFI_STATUS Status; + SI_POLICY_PPI *SiPolicyPpi; + PEI_SI_DEFAULT_POLICY_INIT_PPI *PeiSiDefaultPolicyInitPpi; + + DEBUG ((DEBUG_INFO, "Silicon PEI Policy Initialization Start in Post-Memory...\n")); + + ASSERT (Policy == NULL); + SiPolicyPpi = NULL; + PeiSiDefaultPolicyInitPpi = NULL; + + // + // Locate Policy init PPI to install default silicon policy + // + Status = PeiServicesLocatePpi ( + &gSiDefaultPolicyInitPpiGuid, + 0, + NULL, + (VOID **) &PeiSiDefaultPolicyInitPpi + ); + ASSERT_EFI_ERROR (Status); + if (PeiSiDefaultPolicyInitPpi != NULL) { + Status = PeiSiDefaultPolicyInitPpi->PeiPolicyInit (); + ASSERT_EFI_ERROR (Status); + if (Status == EFI_SUCCESS) { + Status = PeiServicesLocatePpi ( + &gSiPolicyPpiGuid, + 0, + NULL, + (VOID **) &SiPolicyPpi + ); + ASSERT_EFI_ERROR (Status); + } + } + + if (SiPolicyPpi == NULL) { + DEBUG ((DEBUG_ERROR, "Fail to create default policy!\n")); + return NULL; + } + + + return SiPolicyPpi; +} + +/** + The silicon post-mem policy is finalized. + Silicon code can do initialization based upon the policy data. + + The input Policy must be returned by SiliconPolicyInitPostMem(). + + @param[in] Policy Pointer to policy. + @retval RETURN_SUCCESS The policy is handled consumed by silicon code. +**/ +RETURN_STATUS +EFIAPI +SiliconPolicyDonePostMem ( + IN VOID *Policy + ) +{ + EFI_STATUS Status; + + Status = SiInstallPolicyReadyPpi (); + ASSERT_EFI_ERROR (Status); + DEBUG ((DEBUG_INFO, "Silicon PEI Policy Initialization Done in Post-Memory\n")); + + return Status; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyInitLib/PeiPostMemSiliconPolicyInitLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyInitLib/PeiPostMemSiliconPolicyInitLib.inf new file mode 100644 index 0000000000..b13d63d337 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyInitLib/PeiPostMemSiliconPolicyInitLib.inf @@ -0,0 +1,36 @@ +## @file +# Component information file for Silicon Policy Init Library +# This library implements Silicon Policy Initialization for PostMemory. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PeiPostMemSiliconPolicyInitLib + FILE_GUID = 20B51FFB-93D3-4546-9F13-2C91AEEF9212 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = SiliconPolicyInitLib + +[LibraryClasses] + BaseLib + PcdLib + PeiServicesLib + DebugLib + SiPolicyLib + +[Packages] + MdePkg/MdePkg.dec + AlderlakeSiliconPkg/SiPkg.dec + +[Sources] + PeiPostMemSiliconPolicyInitLib.c + +[Ppis] + gSiDefaultPolicyInitPpiGuid + gEfiPeiMpServicesPpiGuid + +[Depex] + gSiDefaultPolicyInitPpiGuid diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyInitLib/PeiPreMemSiliconPolicyInitLib.c b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyInitLib/PeiPreMemSiliconPolicyInitLib.c new file mode 100644 index 0000000000..74fb47a73d --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyInitLib/PeiPreMemSiliconPolicyInitLib.c @@ -0,0 +1,98 @@ +/** @file + This library initialize Silicon Policy for PreMemory. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <Ppi/SiPolicy.h> +#include <Ppi/PeiPreMemSiDefaultPolicy.h> +#include <Library/DebugLib.h> +#include <Library/PeiServicesLib.h> +#include <Library/SiPolicyLib.h> + + +/** + Performs silicon pre-mem policy initialization. + + The returned data must be used as input data for SiliconPolicyDonePreMem (), + and SiliconPolicyUpdateLib.SiliconPolicyUpdatePreMem (). + + @param[in, out] Policy Pointer to policy. + @return the initialized policy. +**/ +VOID * +EFIAPI +SiliconPolicyInitPreMem ( + IN OUT VOID *Policy + ) +{ + EFI_STATUS Status; + SI_PREMEM_POLICY_PPI *SiPreMemPolicyPpi; + PEI_PREMEM_SI_DEFAULT_POLICY_INIT_PPI *PeiPreMemSiDefaultPolicyInitPpi; + + DEBUG ((DEBUG_INFO, "Silicon PEI Policy Initialization Start in Pre-Memory...\n")); + + ASSERT (Policy == NULL); + SiPreMemPolicyPpi = NULL; + PeiPreMemSiDefaultPolicyInitPpi = NULL; + + // + // Locate Policy init PPI to install default silicon policy + // + Status = PeiServicesLocatePpi ( + &gSiPreMemDefaultPolicyInitPpiGuid, + 0, + NULL, + (VOID **) &PeiPreMemSiDefaultPolicyInitPpi + ); + ASSERT_EFI_ERROR (Status); + if (PeiPreMemSiDefaultPolicyInitPpi != NULL) { + Status = PeiPreMemSiDefaultPolicyInitPpi->PeiPreMemPolicyInit (); + ASSERT_EFI_ERROR (Status); + if (Status == EFI_SUCCESS) { + Status = PeiServicesLocatePpi ( + &gSiPreMemPolicyPpiGuid, + 0, + NULL, + (VOID **) &SiPreMemPolicyPpi + ); + ASSERT_EFI_ERROR (Status); + } + } + + if (SiPreMemPolicyPpi == NULL) { + DEBUG ((DEBUG_ERROR, "Fail to create default policy!\n")); + return NULL; + } + + return SiPreMemPolicyPpi; +} + +/** + The silicon pre-mem policy is finalized. + Silicon code can do initialization based upon the policy data. + + The input Policy must be returned by SiliconPolicyInitPreMem(). + + @param[in] Policy Pointer to policy. + @retval RETURN_SUCCESS The policy is handled consumed by silicon code. +**/ +RETURN_STATUS +EFIAPI +SiliconPolicyDonePreMem ( + IN VOID *Policy + ) +{ + EFI_STATUS Status; + // + // Install PreMem Policy Ready PPI + // While installs PreMemPolicyReadyPpi, RC assumes the Policy is ready and finalized. So please + // update and override any setting before calling this function. + // + Status = SiPreMemInstallPolicyReadyPpi (); + ASSERT_EFI_ERROR (Status); + + DEBUG ((DEBUG_INFO, "Silicon PEI Policy Initialization Done in Pre-Memory\n")); + + return Status; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyInitLib/PeiPreMemSiliconPolicyInitLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyInitLib/PeiPreMemSiliconPolicyInitLib.inf new file mode 100644 index 0000000000..d5ce714ce5 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyInitLib/PeiPreMemSiliconPolicyInitLib.inf @@ -0,0 +1,36 @@ +## @file +# Component information file for Silicon Policy Init Library +# This library implements Silicon Policy Initialization for PreMemory. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PeiPreMemSiliconPolicyInitLib + FILE_GUID = 1FB4B175-0BB6-4137-A4AC-EA48FCE83862 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = SiliconPolicyInitLib + +[LibraryClasses] + BaseLib + PeiServicesLib + DebugLib + SiPolicyLib + +[Packages] + MdePkg/MdePkg.dec + AlderlakeSiliconPkg/SiPkg.dec + +[Sources] + PeiPreMemSiliconPolicyInitLib.c + +[Pcd] + +[Ppis] + gSiPreMemDefaultPolicyInitPpiGuid + +[Depex] + gSiPreMemDefaultPolicyInitPpiGuid -- 2.36.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107568): https://edk2.groups.io/g/devel/message/107568 Mute This Topic: https://groups.io/mt/100551000/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [edk2-devel] [PATCH v2 2/7] AlderlakeSiliconPkg: Add Cpu modules 2023-08-04 17:37 [edk2-devel] [PATCH v2 1/7] AlderlakeSiliconPkg: Add package and library instances Saloni Kasbekar @ 2023-08-04 17:37 ` Saloni Kasbekar 2023-08-16 2:45 ` Chuang, Rosen 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 3/7] AlderlakeSiliconPkg/Pch: Add include headers Saloni Kasbekar ` (5 subsequent siblings) 6 siblings, 1 reply; 14+ messages in thread From: Saloni Kasbekar @ 2023-08-04 17:37 UTC (permalink / raw) To: devel Cc: Saloni Kasbekar, Sai Chaganty, Nate DeSimone, Isaac Oram, Rosen Chuang Add Cpu/Include, Cpu/IncludePrivate and Cpu/Library Cc: Sai Chaganty <rangasai.v.chaganty@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Isaac Oram <isaac.w.oram@intel.com> Cc: Rosen Chuang <rosen.chuang@intel.com> Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com> --- .../Cpu/Include/ConfigBlock/CpuConfig.h | 86 ++++++++ .../ConfigBlock/CpuConfigLibPreMemConfig.h | 195 ++++++++++++++++++ .../ConfigBlock/CpuSecurityPreMemConfig.h | 63 ++++++ .../AlderlakeSiliconPkg/Cpu/Include/CpuRegs.h | 63 ++++++ .../Cpu/Include/Library/CpuPlatformLib.h | 42 ++++ .../Cpu/Include/Register/CommonMsr.h | 60 ++++++ .../IncludePrivate/Library/CpuInfoFruLib.h | 64 ++++++ .../CpuPlatformLibrary.c | 55 +++++ .../CpuPlatformLibrary.h | 25 +++ .../PeiDxeSmmCpuPlatformLib.inf | 41 ++++ 10 files changed, 694 insertions(+) create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfig.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfigLibPreMemConfig.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuSecurityPreMemConfig.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/CpuRegs.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Library/CpuPlatformLib.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Register/CommonMsr.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/IncludePrivate/Library/CpuInfoFruLib.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/CpuPlatformLibrary.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/CpuPlatformLibrary.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/PeiDxeSmmCpuPlatformLib.inf diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfig.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfig.h new file mode 100644 index 0000000000..9815f8b185 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfig.h @@ -0,0 +1,86 @@ +/** @file + CPU Config Block. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _CPU_CONFIG_H_ +#define _CPU_CONFIG_H_ + +#define CPU_CONFIG_REVISION 1 + +extern EFI_GUID gCpuConfigGuid; + +#pragma pack (push,1) + +/** + CPU Configuration Structure. + + <b>Revision 1</b>: + - Initial version. +**/ +typedef struct { + CONFIG_BLOCK_HEADER Header; ///< Config Block Header + UINT32 MicrocodePatchRegionSize; + EFI_PHYSICAL_ADDRESS MicrocodePatchAddress; ///< Pointer to microcode patch that is suitable for this processor. + /** + Enable or Disable Advanced Encryption Standard (AES) feature. + For some countries, this should be disabled for legal reasons. + - 0: Disable + - <b>1: Enable</b> + **/ + UINT32 AesEnable : 1; + /** + Enable or Disable Trusted Execution Technology (TXT) feature. + - 0: Disable + - <b>1: Enable</b> + **/ + UINT32 TxtEnable : 1; + UINT32 SkipMpInit : 1; ///< For Fsp only, Silicon Initialization will skip MP Initialization (including BSP) if enabled. For non-FSP, this should always be 0. + /** + Enable or Disable or Auto for PPIN Support to view Protected Processor Inventory Number. + - <b>0: Disable</b> + - 1: Enable + - 2: Auto : Feature is based on End Of Manufacturing (EOM) flag. If EOM is set, it is disabled. + **/ + UINT32 PpinSupport : 2; + /** + Enable or Disable #AC machine check on split lock. + - <b>0: Disable</b> + - 1: Enable + **/ + UINT32 AcSplitLock : 1; + /** + Enable or Disable Avx. + - 1: Disable + - <b> 0: Enable</b> + **/ + UINT32 AvxDisable : 1; + /** + @deprecated + Enable or Disable Avx3. + - <b> 1: Disable</b> + - 0: Enable + **/ + UINT32 Avx3Disable : 1; + /** + Enable or Disable X2APIC Support. + - <b>0: Disable</b> + - 1: Enable + **/ + UINT32 X2ApicSupport : 1; + UINT32 RsvdBits : 23; ///< Reserved for future use + /** + Provide the option for platform to override the MaxSpeed field of Smbios Type 4. + Value 4000 means 4000MHz. + If this value is not zero, it dominates the field. + If this value is zero, CPU RC will update the field according to the max radio. + <b>default is 0.</b> + **/ + UINT16 SmbiosType4MaxSpeedOverride; + UINT8 Reserved0[2]; ///< Reserved for future use +} CPU_CONFIG; + +#pragma pack (pop) + +#endif // _CPU_CONFIG_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfigLibPreMemConfig.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfigLibPreMemConfig.h new file mode 100644 index 0000000000..68d4effe3f --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfigLibPreMemConfig.h @@ -0,0 +1,195 @@ +/** @file + CPU Security PreMemory Config Block. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _CPU_CONFIG_LIB_PREMEM_CONFIG_H_ +#define _CPU_CONFIG_LIB_PREMEM_CONFIG_H_ + +#define CPU_CONFIG_LIB_PREMEM_CONFIG_REVISION 1 + +extern EFI_GUID gCpuConfigLibPreMemConfigGuid; + + +#pragma pack (push,1) + +/** + CPU Config Library PreMemory Configuration Structure. + + <b>Revision 1</b>: + - Initial version. +**/ +typedef struct { + CONFIG_BLOCK_HEADER Header; ///< Config Block Header + UINT32 HyperThreading : 1; ///< Enable or Disable Hyper Threading; 0: Disable; <b>1: Enable</b>. + /** + Sets the boot frequency starting from reset vector. + - 0: Maximum battery performance. + - 1: Maximum non-turbo performance + -<b>2: Turbo performance</b>. + @note If Turbo is selected BIOS will start in max non-turbo mode and switch to Turbo mode. + **/ + UINT32 BootFrequency : 2; + /** + Number of processor cores to enable. + - <b> 0: All cores</b> + - 1: 1 core + - 2: 2 cores + - 3: 3 cores + **/ + UINT32 ActiveCoreCount : 3; ///< @deprecated due to core active number limitaion. + UINT32 JtagC10PowerGateDisable : 1; ///< False: JTAG is power gated in C10 state. True: keeps the JTAG power up during C10 and deeper power states for debug purpose. <b>0: False<\b>; 1: True. + UINT32 BistOnReset : 1; ///< <b>(Test)</b> Enable or Disable BIST on Reset; <b>0: Disable</b>; 1: Enable. + /** + Enable or Disable Virtual Machine Extensions (VMX) feature. + - 0: Disable + - <b>1: Enable</b> + **/ + UINT32 VmxEnable : 1; + /** + Processor Early Power On Configuration FCLK setting. + - <b>0: 800 MHz (ULT/ULX)</b>. + - <b>1: 1 GHz (DT/Halo)</b>. Not supported on ULT/ULX. + - 2: 400 MHz. + - 3: Reserved. + **/ + UINT32 FClkFrequency : 2; + /** + Enable or Disable CrashLog feature + - 0: Disable + - <b>1: Enable</b> + **/ + UINT32 CrashLogEnable : 1; + + /** + Enable or Disable Total Memory Encryption (TME) feature. + - 0: Disable + - <b>1: Enable</b> + **/ + UINT32 TmeEnable : 1; + + UINT32 DebugInterfaceEnable : 2; ///< Enable or Disable processor debug features; 0: Disable; 1: Enable; <b>2: No Change</b>. + UINT32 DebugInterfaceLockEnable : 1; ///< Lock or Unlock debug interface features; 0: Disable; <b>1: Enable</b>. + + /** + Number of big cores in processor to enable. + And support up to 15 cores. + - 0: Disable all cores for Hybrid CPU; Active all cores for Non-Hybrid CPU (MAX 16). + - 1: 1 core + - 2: 2 cores + - 3: 3 cores + **/ + UINT32 ActiveCoreCount1 : 4; + + /** + Enables a mailbox command to resolve rare PECI related Sx issues. + @note This should only be used on systems that observe PECI Sx issues. + - <b>0: Disable</b> + - 1: Enable + **/ + UINT32 PeciSxReset : 1; + + /** + Enables the mailbox command to resolve PECI reset issues during Pkg-C10 exit. + If Enabled, BIOS will send the CPU message to disable peci reset on C10 exit. + The default value <b>0: Disable</b> for CPU's + - 0: Disable + - 1: Enable + **/ + UINT32 PeciC10Reset : 1; ///< @deprecated no longer used. + + /** + Number of small cores in processor to enable. + And support up to 63 cores. + - 0: Disable all cores for Hybrid CPU; Active all cores for Non-Hybrid CPU (MAX 64). + - 1: 1 core + - 2: 2 cores + - 3: 3 cores + **/ + UINT32 ActiveSmallCoreCount : 6; + + /** + Enable or Disable CrashLog GPRs dump + - <b>0: Disable</b> + - 1: Gprs Enabled, Smm Gprs Enabled + 2: Gprs Enabled, Smm Gprs Disabled + **/ + UINT32 CrashLogGprs : 2; + + /** + Enable or Disable Compute Die SSC configuration. + - <b>0: Disable</b> + - 1: Enable + **/ + UINT32 ComputeDieSscEnable : 1; + + /** + Enable or Disable Soc Die SSC configuration. + - <b>0: Disable</b> + - 1: Enable + **/ + UINT32 SocDieSscEnable : 1; + + /** + CpuRatio - Max non-turbo ratio (Flexible Ratio Boot) is set to CpuRatio. <b>0: Disabled</b> If disabled, doesn't override max-non turbo ratio. + **/ + UINT8 CpuRatio; + + /** + Number of enabled atom cores on SoC. + Default is set to supported core number. + - 0 - all core disabled + - 1 - enable 1 core + - 2 - enable 2 cores + - others - reserved for future use + **/ + UINT8 ActiveSocNorthAtomCoreCount; + + /** + SSC configuration value of Compute Die. + SSC downspread field encoding. Downspread in percent = SSC_DOWNSPREAD / 100. + - <b>0 : invalid</b> + - 1 : 0.01% + - 2 : 0.02% + - 100 : 1% + **/ + UINT8 ComputeDieSscValue; + + /** + SSC configuration value of Soc Die. + SSC downspread field encoding. Downspread in percent = SSC_DOWNSPREAD / 100. + - <b>0 : invalid</b> + - 1 : 0.01% + - 2 : 0.02% + - 100 : 1% + **/ + UINT8 SocDieSscValue; + + /** + Clock source of BCLK OC Frequency + - 0: SOC + - <b>1: CPU</b> + - 2: PCH + - 3: Ext. Clock (optional) + **/ + UINT32 BclkSource : 2; + UINT32 RsvdBits : 30; + /** + Determine whether to keep or shutdown INF_DFX power rail. INF_DFX power is up from cold boot. + - <b>0 : INF_DFX shutdown</b> + - 1 : INF_DFX power up </b> + **/ + UINT8 InfDfxPwrEnable; + /** + Configuration for boot TDP selection; <b>0: TDP Nominal</b>; 1: TDP Down; 2: TDP Up. + **/ + UINT8 ConfigTdpLevel; + UINT8 RsvdByte[2]; + UINT32 CustomPowerLimit1; + +} CPU_CONFIG_LIB_PREMEM_CONFIG; + +#pragma pack (pop) + +#endif // _CPU_CONFIG_LIB_PREMEM_CONFIG_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuSecurityPreMemConfig.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuSecurityPreMemConfig.h new file mode 100644 index 0000000000..c9acd48c84 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuSecurityPreMemConfig.h @@ -0,0 +1,63 @@ +/** @file + CPU Security PreMemory Config Block. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _CPU_SECURITY_PREMEM_CONFIG_H_ +#define _CPU_SECURITY_PREMEM_CONFIG_H_ + +#define CPU_SECURITY_PREMEM_CONFIG_REVISION 1 + +extern EFI_GUID gCpuSecurityPreMemConfigGuid; + +#pragma pack (push,1) + +/** + CPU Security PreMemory Configuration Structure. + + <b>Revision 1</b>: + - Initial version. +**/ +typedef struct { + CONFIG_BLOCK_HEADER Header; ///< Config Block Header + UINT32 PrmrrSize; ///< PRMRR Size.<b>Software Control: 0x0</b> 32MB: 0x2000000, 64MB: 0x4000000, 128 MB: 0x8000000, 256 MB: 0x10000000, 512 MB: 0x20000000 + UINT16 BiosSize; ///< Flash information for BIOS Guard: BIOS Size in KB. + UINT8 Reserved[2]; ///< Reserved for future use +/** + Enable or Disable BIOS Guard; 0: Disable; <b>1: Enable</b>. + - This is an optional feature and can be opted out. + - If this policy is set to Disabled, the policies in the BIOS_GUARD_CONFIG will be ignored. + - If PeiBiosGuardLibNull is used, this policy will have no effect. +**/ + UINT32 BiosGuard : 1; + UINT32 BiosGuardToolsInterface : 1; ///< BIOS Guard Tools Interface; <b>0: Disable</b>, 1:Enable +/** + Enable or Disable Software Guard Extensions; <b>0: Disable</b>; 1: Enable. + - This is an optional feature and can be opted out. + - If this policy is set to Disabled, the policies in the CPU_SGX_CONFIG will be ignored. + - If BaseSoftwareGuardLibNull is used, this policy will have no effect. +**/ + UINT32 EnableSgx : 1; ///< @deprecated due to Non-POR feature. +/** + Enable or Disable Trusted Execution Technology; <b>0: Disable</b>; 1: Enable. + - This is an optional feature and can be opted out. + - If this policy is set to Disabled, the policies in the CPU_TXT_PREMEM_CONFIG will be ignored. + - If PeiTxtLibNull is used, this policy will have no effect. +**/ + UINT32 Txt : 1; + UINT32 SkipStopPbet : 1; ///< <b>(Test)</b> Skip Stop PBET Timer; <b>0: Disable</b>; 1: Enable. + /// + /// <b>(Test)</b> This policy indicates whether or not BIOS should allocate PRMRR memory for C6DRAM power gating feature. + /// - 0: Don't allocate any PRMRR memory for C6DRAM power gating feature. + /// - <b>1: Allocate PRMRR memory for C6DRAM power gating feature</b>. + /// + UINT32 EnableC6Dram : 1; + UINT32 ResetAux : 1; ///< <b>(Test)</b> Reset Auxiliary content, <b>0: Disabled</b>, 1: Enabled + UINT32 TxtAcheckRequest : 1; ///< <b>(Test)</b> AcheckRequest <b>0: Disabled</b>, 1: Enabled. When Enabled, it will call Acheck regardless of crashcode value + UINT32 RsvdBits : 24; ///< Reserved for future use +} CPU_SECURITY_PREMEM_CONFIG; + +#pragma pack (pop) + +#endif // _CPU_SECURITY_CONFIG_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/CpuRegs.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/CpuRegs.h new file mode 100644 index 0000000000..aac4e21e2a --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/CpuRegs.h @@ -0,0 +1,63 @@ +/** @file + Register names for CPU registers + + <b>Conventions</b> + - Definitions beginning with "MSR_" are MSRs + - Definitions beginning with "R_" are registers + - Definitions beginning with "B_" are bits within registers + - Definitions beginning with "V_" are meaningful values of bits within the registers + - Definitions beginning with "S_" are register sizes + - Definitions beginning with "N_" are the bit position + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _CPU_REGS_H_ +#define _CPU_REGS_H_ + +/// +/// Other defines +/// +#ifndef CPU_FEATURE_DISABLE +#define CPU_FEATURE_DISABLE 0 +#endif +#ifndef CPU_FEATURE_ENABLE +#define CPU_FEATURE_ENABLE 1 +#endif + +// +// Processor Definitions +// +#define CPUID_FULL_STEPPING 0x0000000F +#define CPUID_FULL_FAMILY_MODEL 0x0FFF0FF0 + +#define BITS(x) (1 << (x)) + +/** +Notes : + 1. Bit position always starts at 0. + 2. Following macros are applicable only for Word aligned integers. +**/ +#define BIT(Pos, Value) (1 << (Pos) & (Value)) + +typedef UINT32 CPU_FAMILY; + +/// +/// Enums for CPU SKU IDs +/// +typedef enum { + EnumCpuUlt = 0, + EnumCpuTrad, + EnumCpuUlx, + EnumCpuHalo, + EnumCpuUnknown +} CPU_SKU; + +/// +/// Enums for CPU Generation +/// +typedef enum { + EnumAdlCpu = 0, + EnumCpuUnknownGeneration = 255 +} CPU_GENERATION; +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Library/CpuPlatformLib.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Library/CpuPlatformLib.h new file mode 100644 index 0000000000..05afbf1db3 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Library/CpuPlatformLib.h @@ -0,0 +1,42 @@ +/** @file + Header file for CpuPlatform Lib. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _CPU_PLATFORM_LIB_H_ +#define _CPU_PLATFORM_LIB_H_ + +#include <Uefi.h> +#include <CpuRegs.h> +#include <CpuGenInfo.h> + +/// +/// Table to convert Seconds into equivalent MSR values +/// This table is used for PL1, Pl2 and RATL TDP Time Window programming +/// +extern GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mSecondsToMsrValueMapTable[][2]; + +/** + Return CPU Sku + + @retval UINT8 CPU Sku +**/ +UINT8 +EFIAPI +GetCpuSku ( + VOID + ); + +/** + This function returns the supported Physical Address Size + + @retval supported Physical Address Size. +**/ +UINT8 +GetMaxPhysicalAddressSize ( + VOID + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Register/CommonMsr.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Register/CommonMsr.h new file mode 100644 index 0000000000..caa0e67bf7 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Register/CommonMsr.h @@ -0,0 +1,60 @@ + +/** @file + CommonMsr.h + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _COMMONMSR_h +#define _COMMONMSR_h +#include <Base.h> + +/** + This is a Read Only MSR that is shared in the processor package and used to + determine the current count of enabled Cores and Threads. +**/ +#define MSR_CORE_THREAD_COUNT 0x00000035 + +typedef union { + /// + /// Individual bit fields + /// + struct { + UINT32 Threadcount : 16; + + /* Bits[15:0], Access Type=RO_V, default=None*/ + + /* + The Thread Count reflects the enabled threads + based on the factory-configured thread count and + the value of the RESOLVED_CORES_MASK register + for Server processors or the PCH Soft Reset Data + register for Client processors at reset time. + */ + UINT32 Corecount : 16; + + /* Bits[31:16], Access Type=RO_V, default=None*/ + + /* + The Core Count reflects the enabled cores based + on the factory-configured core count and the + value of the RESOLVED_CORES_MASK register for + Server processors or the PCH Soft Reset Data + register for Client processors at reset time. + */ + UINT32 Rsvd32 : 32; + + /* Bits[63:32], Access Type=RO, default=None*/ + + /* Reserved */ + + } Bits; + + UINT32 Uint32; + UINT64 Uint64; + +} MSR_CORE_THREAD_COUNT_REGISTER; + + +#endif /* _COMMONMSR_h */ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/IncludePrivate/Library/CpuInfoFruLib.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/IncludePrivate/Library/CpuInfoFruLib.h new file mode 100644 index 0000000000..4095c51efb --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/IncludePrivate/Library/CpuInfoFruLib.h @@ -0,0 +1,64 @@ + /** @file + This file contains Cpu Information for specific generation. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _CPU_INFO_FRU_LIB_H_ +#define _CPU_INFO_FRU_LIB_H_ + +#include <Uefi.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <CpuRegs.h> +#include <CpuGenInfo.h> +#include <Register/SaRegsHostBridge.h> +#include <Library/PciSegmentLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/PcdLib.h> + +/// +/// Override table structure for cTDP and non-cTDP skus. +/// Non-cTDP parts would have '0' data for TDP level information. +/// +typedef struct { + UINTN CpuIdentifier; + UINT16 SkuPackageTdp; + UINTN MsrPowerLimit1; + UINTN MsrPowerLimit2; + UINTN CtdpUpPowerLimit1; + UINTN CtdpUpPowerLimit2; + UINTN CtdpNominalPowerLimit1; + UINTN CtdpNominalPowerLimit2; + UINTN CtdpDownPowerLimit1; + UINTN CtdpDownPowerLimit2; + UINTN MsrPowerLimit4; /// PL4 value if FVM is enabled or system does not support FVM + UINTN MsrPowerLimit4DisableFvm; /// PL4 value if FVM is supported but disabled. +} PPM_OVERRIDE_TABLE; + +/** + Return CPU Sku + + @param[in] UINT32 CpuFamilyModel + @param[in] UINT16 CpuDid + + @retval UINT8 CPU Sku +**/ +UINT8 +GetCpuSkuInfo ( + IN UINT32 CpuFamilyModel, + IN UINT16 CpuDid + ); + +/** + This function returns the supported Physical Address Size + + @retval returns the supported Physical Address Size. +**/ +UINT8 +GetMaxPhysicalAddressSizeFru ( + VOID + ); + +#endif // _CPU_INFO_FRU_LIB_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/CpuPlatformLibrary.c b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/CpuPlatformLibrary.c new file mode 100644 index 0000000000..5245a49719 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/CpuPlatformLibrary.c @@ -0,0 +1,55 @@ +/** @file + CPU Platform Lib implementation. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "CpuPlatformLibrary.h" +#include <Library/PciSegmentLib.h> +#include <Register/SaRegsHostBridge.h> +#include <CpuRegs.h> +#include <Register/IgdRegs.h> +#include <Library/CpuInfoFruLib.h> +#include <Register/CommonMsr.h> +#include <CpuGenInfoFruLib.h> +#include <Pi/PiStatusCode.h> +#include <Library/ReportStatusCodeLib.h> + +/** + Return CPU Sku + + @retval UINT8 CPU Sku +**/ +UINT8 +EFIAPI +GetCpuSku ( + VOID + ) +{ + UINT16 CpuDid; + UINT32 CpuFamilyModel; + CPUID_VERSION_INFO_EAX Eax; + + /// + /// Read the CPUID & DID information + /// + AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL); + CpuFamilyModel = Eax.Uint32 & CPUID_FULL_FAMILY_MODEL; + CpuDid = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_MC_DEVICE_ID)); + + return GetCpuSkuInfo (CpuFamilyModel, CpuDid); + +} + +/** + This function returns the supported Physical Address Size + + @retval supported Physical Address Size. +**/ +UINT8 +GetMaxPhysicalAddressSize ( + VOID + ) +{ + return GetMaxPhysicalAddressSizeFru (); +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/CpuPlatformLibrary.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/CpuPlatformLibrary.h new file mode 100644 index 0000000000..a85fe62e81 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/CpuPlatformLibrary.h @@ -0,0 +1,25 @@ +/** @file + Header file for Cpu Platform Lib implementation. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _CPU_PLATFORM_LIBRARY_IMPLEMENTATION_H_ +#define _CPU_PLATFORM_LIBRARY_IMPLEMENTATION_H_ + +#include <Uefi.h> +#include <Library/BaseLib.h> +#include <Library/CpuLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/PcdLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/TimerLib.h> +#include <Library/SynchronizationLib.h> + +#include <Register/Cpuid.h> +#include <Register/Msr.h> +#include <Library/CpuPlatformLib.h> + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/PeiDxeSmmCpuPlatformLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/PeiDxeSmmCpuPlatformLib.inf new file mode 100644 index 0000000000..bacef9003b --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/PeiDxeSmmCpuPlatformLib.inf @@ -0,0 +1,41 @@ +## @file +# Component description file for CPU Platform Lib +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = PeiDxeSmmCpuPlatformLib +FILE_GUID = 11647130-6AA4-41A4-A3A8-5FA296ABD977 +VERSION_STRING = 1.0 +MODULE_TYPE = BASE +LIBRARY_CLASS = CpuPlatformLib + + +[LibraryClasses] +BaseLib +BaseMemoryLib +DebugLib +IoLib +PcdLib +CpuLib +TimerLib +SynchronizationLib +PciSegmentLib +CpuInfoFruLib +ReportStatusCodeLib + +[FixedPcd] + +[Packages] +MdePkg/MdePkg.dec +UefiCpuPkg/UefiCpuPkg.dec +AlderlakeSiliconPkg/SiPkg.dec + + +[Sources] +CpuPlatformLibrary.h +CpuPlatformLibrary.c -- 2.36.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107569): https://edk2.groups.io/g/devel/message/107569 Mute This Topic: https://groups.io/mt/100551001/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [edk2-devel] [PATCH v2 2/7] AlderlakeSiliconPkg: Add Cpu modules 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 2/7] AlderlakeSiliconPkg: Add Cpu modules Saloni Kasbekar @ 2023-08-16 2:45 ` Chuang, Rosen 0 siblings, 0 replies; 14+ messages in thread From: Chuang, Rosen @ 2023-08-16 2:45 UTC (permalink / raw) To: Kasbekar, Saloni, devel@edk2.groups.io Cc: Chaganty, Rangasai V, Desimone, Nathaniel L, Oram, Isaac W Reviewed-by: Rosen Chuang < rosen.chuang@intel.com> -----Original Message----- From: Kasbekar, Saloni <saloni.kasbekar@intel.com> Sent: Saturday, August 5, 2023 1:38 AM To: devel@edk2.groups.io Cc: Kasbekar, Saloni <saloni.kasbekar@intel.com>; Chaganty, Rangasai V <rangasai.v.chaganty@intel.com>; Desimone, Nathaniel L <nathaniel.l.desimone@intel.com>; Oram, Isaac W <isaac.w.oram@intel.com>; Chuang, Rosen <rosen.chuang@intel.com> Subject: [PATCH v2 2/7] AlderlakeSiliconPkg: Add Cpu modules Add Cpu/Include, Cpu/IncludePrivate and Cpu/Library Cc: Sai Chaganty <rangasai.v.chaganty@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Isaac Oram <isaac.w.oram@intel.com> Cc: Rosen Chuang <rosen.chuang@intel.com> Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com> --- .../Cpu/Include/ConfigBlock/CpuConfig.h | 86 ++++++++ .../ConfigBlock/CpuConfigLibPreMemConfig.h | 195 ++++++++++++++++++ .../ConfigBlock/CpuSecurityPreMemConfig.h | 63 ++++++ .../AlderlakeSiliconPkg/Cpu/Include/CpuRegs.h | 63 ++++++ .../Cpu/Include/Library/CpuPlatformLib.h | 42 ++++ .../Cpu/Include/Register/CommonMsr.h | 60 ++++++ .../IncludePrivate/Library/CpuInfoFruLib.h | 64 ++++++ .../CpuPlatformLibrary.c | 55 +++++ .../CpuPlatformLibrary.h | 25 +++ .../PeiDxeSmmCpuPlatformLib.inf | 41 ++++ 10 files changed, 694 insertions(+) create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfig.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfigLibPreMemConfig.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuSecurityPreMemConfig.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/CpuRegs.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Library/CpuPlatformLib.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Register/CommonMsr.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/IncludePrivate/Library/CpuInfoFruLib.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/CpuPlatformLibrary.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/CpuPlatformLibrary.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/PeiDxeSmmCpuPlatformLib.inf diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfig.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfig.h new file mode 100644 index 0000000000..9815f8b185 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfi +++ g.h @@ -0,0 +1,86 @@ +/** @file + CPU Config Block. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_CPU_CONFIG_H_ #define _CPU_CONFIG_H_ + +#define CPU_CONFIG_REVISION 1 + +extern EFI_GUID gCpuConfigGuid; + +#pragma pack (push,1) + +/** + CPU Configuration Structure. + + <b>Revision 1</b>: + - Initial version. +**/ +typedef struct { + CONFIG_BLOCK_HEADER Header; ///< Config Block Header + UINT32 MicrocodePatchRegionSize; + EFI_PHYSICAL_ADDRESS MicrocodePatchAddress; ///< Pointer to microcode patch that is suitable for this processor. + /** + Enable or Disable Advanced Encryption Standard (AES) feature. + For some countries, this should be disabled for legal reasons. + - 0: Disable + - <b>1: Enable</b> + **/ + UINT32 AesEnable : 1; + /** + Enable or Disable Trusted Execution Technology (TXT) feature. + - 0: Disable + - <b>1: Enable</b> + **/ + UINT32 TxtEnable : 1; + UINT32 SkipMpInit : 1; ///< For Fsp only, Silicon Initialization will skip MP Initialization (including BSP) if enabled. For non-FSP, this should always be 0. + /** + Enable or Disable or Auto for PPIN Support to view Protected Processor Inventory Number. + - <b>0: Disable</b> + - 1: Enable + - 2: Auto : Feature is based on End Of Manufacturing (EOM) flag. If EOM is set, it is disabled. + **/ + UINT32 PpinSupport : 2; + /** + Enable or Disable #AC machine check on split lock. + - <b>0: Disable</b> + - 1: Enable + **/ + UINT32 AcSplitLock : 1; + /** + Enable or Disable Avx. + - 1: Disable + - <b> 0: Enable</b> + **/ + UINT32 AvxDisable : 1; + /** + @deprecated + Enable or Disable Avx3. + - <b> 1: Disable</b> + - 0: Enable + **/ + UINT32 Avx3Disable : 1; + /** + Enable or Disable X2APIC Support. + - <b>0: Disable</b> + - 1: Enable + **/ + UINT32 X2ApicSupport : 1; + UINT32 RsvdBits : 23; ///< Reserved for future use + /** + Provide the option for platform to override the MaxSpeed field of Smbios Type 4. + Value 4000 means 4000MHz. + If this value is not zero, it dominates the field. + If this value is zero, CPU RC will update the field according to the max radio. + <b>default is 0.</b> + **/ + UINT16 SmbiosType4MaxSpeedOverride; + UINT8 Reserved0[2]; ///< Reserved for future use +} CPU_CONFIG; + +#pragma pack (pop) + +#endif // _CPU_CONFIG_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfigLibPreMemConfig.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfigLibPreMemConfig.h new file mode 100644 index 0000000000..68d4effe3f --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuConfi +++ gLibPreMemConfig.h @@ -0,0 +1,195 @@ +/** @file + CPU Security PreMemory Config Block. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_CPU_CONFIG_LIB_PREMEM_CONFIG_H_ #define +_CPU_CONFIG_LIB_PREMEM_CONFIG_H_ + +#define CPU_CONFIG_LIB_PREMEM_CONFIG_REVISION 1 + +extern EFI_GUID gCpuConfigLibPreMemConfigGuid; + + +#pragma pack (push,1) + +/** + CPU Config Library PreMemory Configuration Structure. + + <b>Revision 1</b>: + - Initial version. +**/ +typedef struct { + CONFIG_BLOCK_HEADER Header; ///< Config Block Header + UINT32 HyperThreading : 1; ///< Enable or Disable Hyper Threading; 0: Disable; <b>1: Enable</b>. + /** + Sets the boot frequency starting from reset vector. + - 0: Maximum battery performance. + - 1: Maximum non-turbo performance + -<b>2: Turbo performance</b>. + @note If Turbo is selected BIOS will start in max non-turbo mode and switch to Turbo mode. + **/ + UINT32 BootFrequency : 2; + /** + Number of processor cores to enable. + - <b> 0: All cores</b> + - 1: 1 core + - 2: 2 cores + - 3: 3 cores + **/ + UINT32 ActiveCoreCount : 3; ///< @deprecated due to core active number limitaion. + UINT32 JtagC10PowerGateDisable : 1; ///< False: JTAG is power gated in C10 state. True: keeps the JTAG power up during C10 and deeper power states for debug purpose. <b>0: False<\b>; 1: True. + UINT32 BistOnReset : 1; ///< <b>(Test)</b> Enable or Disable BIST on Reset; <b>0: Disable</b>; 1: Enable. + /** + Enable or Disable Virtual Machine Extensions (VMX) feature. + - 0: Disable + - <b>1: Enable</b> + **/ + UINT32 VmxEnable : 1; + /** + Processor Early Power On Configuration FCLK setting. + - <b>0: 800 MHz (ULT/ULX)</b>. + - <b>1: 1 GHz (DT/Halo)</b>. Not supported on ULT/ULX. + - 2: 400 MHz. + - 3: Reserved. + **/ + UINT32 FClkFrequency : 2; + /** + Enable or Disable CrashLog feature + - 0: Disable + - <b>1: Enable</b> + **/ + UINT32 CrashLogEnable : 1; + + /** + Enable or Disable Total Memory Encryption (TME) feature. + - 0: Disable + - <b>1: Enable</b> + **/ + UINT32 TmeEnable : 1; + + UINT32 DebugInterfaceEnable : 2; ///< Enable or Disable processor debug features; 0: Disable; 1: Enable; <b>2: No Change</b>. + UINT32 DebugInterfaceLockEnable : 1; ///< Lock or Unlock debug interface features; 0: Disable; <b>1: Enable</b>. + + /** + Number of big cores in processor to enable. + And support up to 15 cores. + - 0: Disable all cores for Hybrid CPU; Active all cores for Non-Hybrid CPU (MAX 16). + - 1: 1 core + - 2: 2 cores + - 3: 3 cores + **/ + UINT32 ActiveCoreCount1 : 4; + + /** + Enables a mailbox command to resolve rare PECI related Sx issues. + @note This should only be used on systems that observe PECI Sx issues. + - <b>0: Disable</b> + - 1: Enable + **/ + UINT32 PeciSxReset : 1; + + /** + Enables the mailbox command to resolve PECI reset issues during Pkg-C10 exit. + If Enabled, BIOS will send the CPU message to disable peci reset on C10 exit. + The default value <b>0: Disable</b> for CPU's + - 0: Disable + - 1: Enable + **/ + UINT32 PeciC10Reset : 1; ///< @deprecated no longer used. + + /** + Number of small cores in processor to enable. + And support up to 63 cores. + - 0: Disable all cores for Hybrid CPU; Active all cores for Non-Hybrid CPU (MAX 64). + - 1: 1 core + - 2: 2 cores + - 3: 3 cores + **/ + UINT32 ActiveSmallCoreCount : 6; + + /** + Enable or Disable CrashLog GPRs dump + - <b>0: Disable</b> + - 1: Gprs Enabled, Smm Gprs Enabled + 2: Gprs Enabled, Smm Gprs Disabled **/ + UINT32 CrashLogGprs : 2; + + /** + Enable or Disable Compute Die SSC configuration. + - <b>0: Disable</b> + - 1: Enable + **/ + UINT32 ComputeDieSscEnable : 1; + + /** + Enable or Disable Soc Die SSC configuration. + - <b>0: Disable</b> + - 1: Enable + **/ + UINT32 SocDieSscEnable : 1; + + /** + CpuRatio - Max non-turbo ratio (Flexible Ratio Boot) is set to CpuRatio. <b>0: Disabled</b> If disabled, doesn't override max-non turbo ratio. + **/ + UINT8 CpuRatio; + + /** + Number of enabled atom cores on SoC. + Default is set to supported core number. + - 0 - all core disabled + - 1 - enable 1 core + - 2 - enable 2 cores + - others - reserved for future use + **/ + UINT8 ActiveSocNorthAtomCoreCount; + + /** + SSC configuration value of Compute Die. + SSC downspread field encoding. Downspread in percent = SSC_DOWNSPREAD / 100. + - <b>0 : invalid</b> + - 1 : 0.01% + - 2 : 0.02% + - 100 : 1% + **/ + UINT8 ComputeDieSscValue; + + /** + SSC configuration value of Soc Die. + SSC downspread field encoding. Downspread in percent = SSC_DOWNSPREAD / 100. + - <b>0 : invalid</b> + - 1 : 0.01% + - 2 : 0.02% + - 100 : 1% + **/ + UINT8 SocDieSscValue; + + /** + Clock source of BCLK OC Frequency + - 0: SOC + - <b>1: CPU</b> + - 2: PCH + - 3: Ext. Clock (optional) + **/ + UINT32 BclkSource : 2; + UINT32 RsvdBits : 30; + /** + Determine whether to keep or shutdown INF_DFX power rail. INF_DFX power is up from cold boot. + - <b>0 : INF_DFX shutdown</b> + - 1 : INF_DFX power up </b> + **/ + UINT8 InfDfxPwrEnable; + /** + Configuration for boot TDP selection; <b>0: TDP Nominal</b>; 1: TDP Down; 2: TDP Up. + **/ + UINT8 ConfigTdpLevel; + UINT8 RsvdByte[2]; + UINT32 CustomPowerLimit1; + +} CPU_CONFIG_LIB_PREMEM_CONFIG; + +#pragma pack (pop) + +#endif // _CPU_CONFIG_LIB_PREMEM_CONFIG_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuSecurityPreMemConfig.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuSecurityPreMemConfig.h new file mode 100644 index 0000000000..c9acd48c84 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/ConfigBlock/CpuSecur +++ ityPreMemConfig.h @@ -0,0 +1,63 @@ +/** @file + CPU Security PreMemory Config Block. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_CPU_SECURITY_PREMEM_CONFIG_H_ #define _CPU_SECURITY_PREMEM_CONFIG_H_ + +#define CPU_SECURITY_PREMEM_CONFIG_REVISION 1 + +extern EFI_GUID gCpuSecurityPreMemConfigGuid; + +#pragma pack (push,1) + +/** + CPU Security PreMemory Configuration Structure. + + <b>Revision 1</b>: + - Initial version. +**/ +typedef struct { + CONFIG_BLOCK_HEADER Header; ///< Config Block Header + UINT32 PrmrrSize; ///< PRMRR Size.<b>Software Control: 0x0</b> 32MB: 0x2000000, 64MB: 0x4000000, 128 MB: 0x8000000, 256 MB: 0x10000000, 512 MB: 0x20000000 + UINT16 BiosSize; ///< Flash information for BIOS Guard: BIOS Size in KB. + UINT8 Reserved[2]; ///< Reserved for future use +/** + Enable or Disable BIOS Guard; 0: Disable; <b>1: Enable</b>. + - This is an optional feature and can be opted out. + - If this policy is set to Disabled, the policies in the BIOS_GUARD_CONFIG will be ignored. + - If PeiBiosGuardLibNull is used, this policy will have no effect. +**/ + UINT32 BiosGuard : 1; + UINT32 BiosGuardToolsInterface : 1; ///< BIOS Guard Tools Interface; <b>0: Disable</b>, 1:Enable +/** + Enable or Disable Software Guard Extensions; <b>0: Disable</b>; 1: Enable. + - This is an optional feature and can be opted out. + - If this policy is set to Disabled, the policies in the CPU_SGX_CONFIG will be ignored. + - If BaseSoftwareGuardLibNull is used, this policy will have no effect. +**/ + UINT32 EnableSgx : 1; ///< @deprecated due to Non-POR feature. +/** + Enable or Disable Trusted Execution Technology; <b>0: Disable</b>; 1: Enable. + - This is an optional feature and can be opted out. + - If this policy is set to Disabled, the policies in the CPU_TXT_PREMEM_CONFIG will be ignored. + - If PeiTxtLibNull is used, this policy will have no effect. +**/ + UINT32 Txt : 1; + UINT32 SkipStopPbet : 1; ///< <b>(Test)</b> Skip Stop PBET Timer; <b>0: Disable</b>; 1: Enable. + /// + /// <b>(Test)</b> This policy indicates whether or not BIOS should allocate PRMRR memory for C6DRAM power gating feature. + /// - 0: Don't allocate any PRMRR memory for C6DRAM power gating feature. + /// - <b>1: Allocate PRMRR memory for C6DRAM power gating feature</b>. + /// + UINT32 EnableC6Dram : 1; + UINT32 ResetAux : 1; ///< <b>(Test)</b> Reset Auxiliary content, <b>0: Disabled</b>, 1: Enabled + UINT32 TxtAcheckRequest : 1; ///< <b>(Test)</b> AcheckRequest <b>0: Disabled</b>, 1: Enabled. When Enabled, it will call Acheck regardless of crashcode value + UINT32 RsvdBits : 24; ///< Reserved for future use +} CPU_SECURITY_PREMEM_CONFIG; + +#pragma pack (pop) + +#endif // _CPU_SECURITY_CONFIG_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/CpuRegs.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/CpuRegs.h new file mode 100644 index 0000000000..aac4e21e2a --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/CpuRegs.h @@ -0,0 +1,63 @@ +/** @file + Register names for CPU registers + + <b>Conventions</b> + - Definitions beginning with "MSR_" are MSRs + - Definitions beginning with "R_" are registers + - Definitions beginning with "B_" are bits within registers + - Definitions beginning with "V_" are meaningful values of bits + within the registers + - Definitions beginning with "S_" are register sizes + - Definitions beginning with "N_" are the bit position + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_CPU_REGS_H_ #define _CPU_REGS_H_ + +/// +/// Other defines +/// +#ifndef CPU_FEATURE_DISABLE +#define CPU_FEATURE_DISABLE 0 +#endif +#ifndef CPU_FEATURE_ENABLE +#define CPU_FEATURE_ENABLE 1 +#endif + +// +// Processor Definitions +// +#define CPUID_FULL_STEPPING 0x0000000F +#define CPUID_FULL_FAMILY_MODEL 0x0FFF0FF0 + +#define BITS(x) (1 << (x)) + +/** +Notes : + 1. Bit position always starts at 0. + 2. Following macros are applicable only for Word aligned integers. +**/ +#define BIT(Pos, Value) (1 << (Pos) & (Value)) + +typedef UINT32 CPU_FAMILY; + +/// +/// Enums for CPU SKU IDs +/// +typedef enum { + EnumCpuUlt = 0, + EnumCpuTrad, + EnumCpuUlx, + EnumCpuHalo, + EnumCpuUnknown +} CPU_SKU; + +/// +/// Enums for CPU Generation +/// +typedef enum { + EnumAdlCpu = 0, + EnumCpuUnknownGeneration = 255 +} CPU_GENERATION; +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Library/CpuPlatformLib.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Library/CpuPlatformLib.h new file mode 100644 index 0000000000..05afbf1db3 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Library/CpuPlatformL +++ ib.h @@ -0,0 +1,42 @@ +/** @file + Header file for CpuPlatform Lib. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ + +#ifndef _CPU_PLATFORM_LIB_H_ +#define _CPU_PLATFORM_LIB_H_ + +#include <Uefi.h> +#include <CpuRegs.h> +#include <CpuGenInfo.h> + +/// +/// Table to convert Seconds into equivalent MSR values /// This table +is used for PL1, Pl2 and RATL TDP Time Window programming /// extern +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mSecondsToMsrValueMapTable[][2]; + +/** + Return CPU Sku + + @retval UINT8 CPU Sku +**/ +UINT8 +EFIAPI +GetCpuSku ( + VOID + ); + +/** + This function returns the supported Physical Address Size + + @retval supported Physical Address Size. +**/ +UINT8 +GetMaxPhysicalAddressSize ( + VOID + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Register/CommonMsr.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Register/CommonMsr.h new file mode 100644 index 0000000000..caa0e67bf7 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Include/Register/CommonMsr.h @@ -0,0 +1,60 @@ + +/** @file + CommonMsr.h + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ + +#ifndef _COMMONMSR_h +#define _COMMONMSR_h +#include <Base.h> + +/** + This is a Read Only MSR that is shared in the processor package and +used to + determine the current count of enabled Cores and Threads. +**/ +#define MSR_CORE_THREAD_COUNT 0x00000035 + +typedef union { + /// + /// Individual bit fields + /// + struct { + UINT32 Threadcount : 16; + + /* Bits[15:0], Access Type=RO_V, + default=None*/ + + /* + The Thread Count reflects the enabled threads + based on the factory-configured thread count and + the value of the RESOLVED_CORES_MASK register + for Server processors or the PCH Soft Reset Data + register for Client processors at reset time. + */ + UINT32 Corecount : 16; + + /* Bits[31:16], Access Type=RO_V, + default=None*/ + + /* + The Core Count reflects the enabled cores based + on the factory-configured core count and the + value of the RESOLVED_CORES_MASK register for + Server processors or the PCH Soft Reset Data + register for Client processors at reset time. + */ + UINT32 Rsvd32 : 32; + + /* Bits[63:32], Access Type=RO, + default=None*/ + + /* Reserved */ + + } Bits; + + UINT32 Uint32; + UINT64 Uint64; + +} MSR_CORE_THREAD_COUNT_REGISTER; + + +#endif /* _COMMONMSR_h */ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/IncludePrivate/Library/CpuInfoFruLib.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/IncludePrivate/Library/CpuInfoFruLib.h new file mode 100644 index 0000000000..4095c51efb --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/IncludePrivate/Library/CpuIn +++ foFruLib.h @@ -0,0 +1,64 @@ + /** @file + This file contains Cpu Information for specific generation. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_CPU_INFO_FRU_LIB_H_ #define _CPU_INFO_FRU_LIB_H_ + +#include <Uefi.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <CpuRegs.h> +#include <CpuGenInfo.h> +#include <Register/SaRegsHostBridge.h> +#include <Library/PciSegmentLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/PcdLib.h> + +/// +/// Override table structure for cTDP and non-cTDP skus. +/// Non-cTDP parts would have '0' data for TDP level information. +/// +typedef struct { + UINTN CpuIdentifier; + UINT16 SkuPackageTdp; + UINTN MsrPowerLimit1; + UINTN MsrPowerLimit2; + UINTN CtdpUpPowerLimit1; + UINTN CtdpUpPowerLimit2; + UINTN CtdpNominalPowerLimit1; + UINTN CtdpNominalPowerLimit2; + UINTN CtdpDownPowerLimit1; + UINTN CtdpDownPowerLimit2; + UINTN MsrPowerLimit4; /// PL4 value if FVM is enabled or system does not support FVM + UINTN MsrPowerLimit4DisableFvm; /// PL4 value if FVM is supported but disabled. +} PPM_OVERRIDE_TABLE; + +/** + Return CPU Sku + + @param[in] UINT32 CpuFamilyModel + @param[in] UINT16 CpuDid + + @retval UINT8 CPU Sku +**/ +UINT8 +GetCpuSkuInfo ( + IN UINT32 CpuFamilyModel, + IN UINT16 CpuDid + ); + +/** + This function returns the supported Physical Address Size + + @retval returns the supported Physical Address Size. +**/ +UINT8 +GetMaxPhysicalAddressSizeFru ( + VOID + ); + +#endif // _CPU_INFO_FRU_LIB_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/CpuPlatformLibrary.c b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/CpuPlatformLibrary.c new file mode 100644 index 0000000000..5245a49719 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatform +++ Lib/CpuPlatformLibrary.c @@ -0,0 +1,55 @@ +/** @file + CPU Platform Lib implementation. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include +"CpuPlatformLibrary.h" +#include <Library/PciSegmentLib.h> +#include <Register/SaRegsHostBridge.h> +#include <CpuRegs.h> +#include <Register/IgdRegs.h> +#include <Library/CpuInfoFruLib.h> +#include <Register/CommonMsr.h> +#include <CpuGenInfoFruLib.h> +#include <Pi/PiStatusCode.h> +#include <Library/ReportStatusCodeLib.h> + +/** + Return CPU Sku + + @retval UINT8 CPU Sku +**/ +UINT8 +EFIAPI +GetCpuSku ( + VOID + ) +{ + UINT16 CpuDid; + UINT32 CpuFamilyModel; + CPUID_VERSION_INFO_EAX Eax; + + /// + /// Read the CPUID & DID information + /// + AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL); + CpuFamilyModel = Eax.Uint32 & CPUID_FULL_FAMILY_MODEL; CpuDid = + PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, + SA_MC_DEV, SA_MC_FUN, R_SA_MC_DEVICE_ID)); + + return GetCpuSkuInfo (CpuFamilyModel, CpuDid); + +} + +/** + This function returns the supported Physical Address Size + + @retval supported Physical Address Size. +**/ +UINT8 +GetMaxPhysicalAddressSize ( + VOID + ) +{ + return GetMaxPhysicalAddressSizeFru (); } diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/CpuPlatformLibrary.h b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/CpuPlatformLibrary.h new file mode 100644 index 0000000000..a85fe62e81 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatform +++ Lib/CpuPlatformLibrary.h @@ -0,0 +1,25 @@ +/** @file + Header file for Cpu Platform Lib implementation. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ + +#ifndef _CPU_PLATFORM_LIBRARY_IMPLEMENTATION_H_ +#define _CPU_PLATFORM_LIBRARY_IMPLEMENTATION_H_ + +#include <Uefi.h> +#include <Library/BaseLib.h> +#include <Library/CpuLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/PcdLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/TimerLib.h> +#include <Library/SynchronizationLib.h> + +#include <Register/Cpuid.h> +#include <Register/Msr.h> +#include <Library/CpuPlatformLib.h> + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/PeiDxeSmmCpuPlatformLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatformLib/PeiDxeSmmCpuPlatformLib.inf new file mode 100644 index 0000000000..bacef9003b --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Cpu/Library/PeiDxeSmmCpuPlatform +++ Lib/PeiDxeSmmCpuPlatformLib.inf @@ -0,0 +1,41 @@ +## @file +# Component description file for CPU Platform Lib # +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = PeiDxeSmmCpuPlatformLib +FILE_GUID = 11647130-6AA4-41A4-A3A8-5FA296ABD977 +VERSION_STRING = 1.0 +MODULE_TYPE = BASE +LIBRARY_CLASS = CpuPlatformLib + + +[LibraryClasses] +BaseLib +BaseMemoryLib +DebugLib +IoLib +PcdLib +CpuLib +TimerLib +SynchronizationLib +PciSegmentLib +CpuInfoFruLib +ReportStatusCodeLib + +[FixedPcd] + +[Packages] +MdePkg/MdePkg.dec +UefiCpuPkg/UefiCpuPkg.dec +AlderlakeSiliconPkg/SiPkg.dec + + +[Sources] +CpuPlatformLibrary.h +CpuPlatformLibrary.c -- 2.36.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107781): https://edk2.groups.io/g/devel/message/107781 Mute This Topic: https://groups.io/mt/100551001/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [edk2-devel] [PATCH v2 3/7] AlderlakeSiliconPkg/Pch: Add include headers 2023-08-04 17:37 [edk2-devel] [PATCH v2 1/7] AlderlakeSiliconPkg: Add package and library instances Saloni Kasbekar 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 2/7] AlderlakeSiliconPkg: Add Cpu modules Saloni Kasbekar @ 2023-08-04 17:37 ` Saloni Kasbekar 2023-08-16 2:44 ` Chuang, Rosen 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 4/7] AlderlakeSiliconPkg/Pch: Add libraries Saloni Kasbekar ` (4 subsequent siblings) 6 siblings, 1 reply; 14+ messages in thread From: Saloni Kasbekar @ 2023-08-04 17:37 UTC (permalink / raw) To: devel Cc: Saloni Kasbekar, Sai Chaganty, Nate DeSimone, Isaac Oram, Rosen Chuang Adds the following header files: * Pch/Include Cc: Sai Chaganty <rangasai.v.chaganty@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Isaac Oram <isaac.w.oram@intel.com> Cc: Rosen Chuang <rosen.chuang@intel.com> Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com> --- .../Include/ConfigBlock/PchGeneralConfig.h | 86 ++++++++ .../Pch/Include/Library/PchCycleDecodingLib.h | 59 ++++++ .../Pch/Include/Library/PchInfoDefs.h | 19 ++ .../Pch/Include/Library/PchInfoLib.h | 108 ++++++++++ .../Pch/Include/Library/PchPciBdfLib.h | 187 ++++++++++++++++++ .../Pch/Include/PchPolicyCommon.h | 30 +++ .../Pch/Include/PchPreMemPolicyCommon.h | 53 +++++ .../Pch/Include/PchResetPlatformSpecific.h | 21 ++ .../Pch/Include/Protocol/PchAcpiSmiDispatch.h | 134 +++++++++++++ .../Pch/Include/Protocol/PchPcieSmiDispatch.h | 166 ++++++++++++++++ .../Pch/Include/Protocol/PchSmiDispatch.h | 132 +++++++++++++ .../Include/Protocol/PchSmmIoTrapControl.h | 65 ++++++ .../Protocol/PchSmmPeriodicTimerControl.h | 65 ++++++ .../Pch/Include/Protocol/PchTcoSmiDispatch.h | 150 ++++++++++++++ .../Pch/Include/Protocol/SmmSmbus.h | 13 ++ .../Pch/Include/Register/PchRegs.h | 45 +++++ 16 files changed, 1333 insertions(+) create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/ConfigBlock/PchGeneralConfig.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchCycleDecodingLib.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoDefs.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoLib.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchPciBdfLib.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPolicyCommon.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPreMemPolicyCommon.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchResetPlatformSpecific.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchAcpiSmiDispatch.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchPcieSmiDispatch.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmiDispatch.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmIoTrapControl.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmPeriodicTimerControl.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchTcoSmiDispatch.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/SmmSmbus.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Register/PchRegs.h diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/ConfigBlock/PchGeneralConfig.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/ConfigBlock/PchGeneralConfig.h new file mode 100644 index 0000000000..4501537fe2 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/ConfigBlock/PchGeneralConfig.h @@ -0,0 +1,86 @@ +/** @file + PCH General policy + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_GENERAL_CONFIG_H_ +#define _PCH_GENERAL_CONFIG_H_ + + +extern EFI_GUID gPchGeneralConfigGuid; +extern EFI_GUID gPchGeneralPreMemConfigGuid; + +#pragma pack (push,1) + +enum PCH_RESERVED_PAGE_ROUTE { + PchReservedPageToLpc, ///< Port 80h cycles are sent to LPC. + PchReservedPageToPcie ///< Port 80h cycles are sent to PCIe. +}; + +/** + PCH General Configuration + <b>Revision 1</b>: - Initial version. + <b>Revision 2</b>: - Added AcpiL6dPmeHandling +**/ +typedef struct { + CONFIG_BLOCK_HEADER Header; ///< Config Block Header + /** + This member describes whether or not the Compatibility Revision ID (CRID) feature + of PCH should be enabled. <b>0: Disable</b>; 1: Enable + **/ + UINT32 Crid : 1; + /** + Set to enable low latency of legacy IO. + Some systems require lower IO latency irrespective of power. + This is a tradeoff between power and IO latency. + @note: Once this is enabled, DmiAspm, Pcie DmiAspm in SystemAgent + and ITSS Clock Gating are forced to disabled. + <b>0: Disable</b>, 1: Enable + **/ + UINT32 LegacyIoLowLatency : 1; + /** + Enables _L6D ACPI handler. + PME GPE is shared by multiple devices So BIOS must verify the same in the ASL handler by reading offset for PMEENABLE and PMESTATUS bit + <b>0: Disable</b>, 1: Enable + **/ + UINT32 AcpiL6dPmeHandling : 1; + UINT32 RsvdBits0 : 29; ///< Reserved bits +} PCH_GENERAL_CONFIG; + +/** + PCH General Pre-Memory Configuration + <b>Revision 1</b>: - Initial version. + <b>Revision 2</b>: - Added GpioOverride. + <b>Revision 3</b>: - Added IoeDebugEn, PmodeClkEn +**/ +typedef struct { + CONFIG_BLOCK_HEADER Header; ///< Config Block Header + /** + Control where the Port 80h cycles are sent, <b>0: LPC</b>; 1: PCI. + **/ + UINT32 Port80Route : 1; + UINT32 IotgPllSscEn : 1; ///< Need to disable CPU Side SSC for A0 PO + /** + Gpio override Level + -- <b>0: Disable</b>; + - 1: Override Level 1 - Skips GPIO configuration in PEI/FSPM/FSPT phase + - 2: Override Level 2 - Reserved for future use + **/ + UINT32 GpioOverride : 3; + /** + Enable/Disable IOE Debug. When enabled, IOE D2D Dfx link and clock will keep up for debug + <b>0: Disable</b>; 1: Enable + **/ + UINT32 IoeDebugEn : 1; + /** + Enable/Disable PMODE clock. When enabled, Pmode clock will toggle for XDP use + <b>0: Disable</b>; 1: Enable + **/ + UINT32 PmodeClkEn : 1; + UINT32 RsvdBits0 : 25; ///< Reserved bits +} PCH_GENERAL_PREMEM_CONFIG; + +#pragma pack (pop) + +#endif // _PCH_GENERAL_CONFIG_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchCycleDecodingLib.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchCycleDecodingLib.h new file mode 100644 index 0000000000..65ecd58de1 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchCycleDecodingLib.h @@ -0,0 +1,59 @@ +/** @file + Header file for PchCycleDecodingLib. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_CYCLE_DECODING_LIB_H_ +#define _PCH_CYCLE_DECODING_LIB_H_ + +/** + Get PCH TCO base address. + + @param[out] Address Address of TCO base address. + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_INVALID_PARAMETER Invalid pointer passed. +**/ +EFI_STATUS +PchTcoBaseGet ( + OUT UINT16 *Address + ); + +/** + Set PCH LPC IO decode ranges. + Program LPC I/O Decode Ranges, PCR[DMI] + 2770h[15:0] to the same value programmed in LPC offset 80h. + Please check EDS for detail of Lpc IO decode ranges bit definition. + Bit 12: FDD range + Bit 9:8: LPT range + Bit 6:4: ComB range + Bit 2:0: ComA range + + @param[in] LpcIoDecodeRanges Lpc IO decode ranges bit settings. + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_UNSUPPORTED DMIC.SRL is set. +**/ +EFI_STATUS +PchLpcIoDecodeRangesSet ( + IN UINT16 LpcIoDecodeRanges + ); + +/** + Set PCH LPC and eSPI CS0# IO enable decoding. + Setup I/O Enables in DMI to the same value program in LPC/eSPI PCI offset 82h. + Note: Bit[15:10] of the source decode register is Read-Only. The IO range indicated by the Enables field + in LPC/eSPI PCI offset 82h[13:10] is always forwarded by DMI to subtractive agent for handling. + Please check EDS for detail of LPC/eSPI IO decode ranges bit definition. + + @param[in] LpcIoEnableDecoding LPC IO enable decoding bit settings. + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_UNSUPPORTED DMIC.SRL is set. +**/ +EFI_STATUS +PchLpcIoEnableDecodingSet ( + IN UINT16 LpcIoEnableDecoding + ); + +#endif // _PCH_CYCLE_DECODING_LIB_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoDefs.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoDefs.h new file mode 100644 index 0000000000..9328e1899c --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoDefs.h @@ -0,0 +1,19 @@ +/** @file + Header file for PchInfoDefs. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_INFO_DEFS_H_ +#define _PCH_INFO_DEFS_H_ + +#define PCH_STEPPING_MAX 0xFF + +#define PCH_LP 2 +#define PCH_N 3 +#define PCH_S 4 +#define PCH_P 5 +#define PCH_M 6 +#define PCH_UNKNOWN_SERIES 0xFF + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoLib.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoLib.h new file mode 100644 index 0000000000..d5d412c9f2 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoLib.h @@ -0,0 +1,108 @@ +/** @file + Header file for PchInfoLib. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_INFO_LIB_H_ +#define _PCH_INFO_LIB_H_ + +#include <Uefi/UefiBaseType.h> +#include "PchInfoDefs.h" + +typedef UINT8 PCH_STEPPING; +typedef UINT8 PCH_SERIES; +typedef UINT8 PCH_GENERATION; + +typedef enum { + RstUnsupported = 0, + RstPremium, + RstOptane, + RstMaxMode +} RST_MODE; + +/** + Return LPC Device Id + + @retval PCH_LPC_DEVICE_ID PCH Lpc Device ID +**/ +UINT16 +PchGetLpcDid ( + VOID + ); + +/** + Return Pch stepping type + + @retval PCH_STEPPING Pch stepping type +**/ +PCH_STEPPING +PchStepping ( + VOID + ); + +/** + Return Pch Series + + @retval PCH_SERIES Pch Series +**/ +PCH_SERIES +PchSeries ( + VOID + ); + +/** + Check if this is PCH LP series + + @retval TRUE It's PCH LP series + @retval FALSE It's not PCH LP series +**/ +BOOLEAN +IsPchLp ( + VOID + ); + + +/** + Check if this is PCH P series + + @retval TRUE It's PCH P series + @retval FALSE It's not PCH P series +**/ +BOOLEAN +IsPchP ( + VOID + ); + +/** + Get Pch Maximum Pcie Root Port Number + + @retval PcieMaxRootPort Pch Maximum Pcie Root Port Number +**/ +UINT8 +GetPchMaxPciePortNum ( + VOID + ); + +/** + Get Pch Maximum Serial IO I2C controllers number + + @retval Pch Maximum Serial IO I2C controllers number +**/ +UINT8 +GetPchMaxSerialIoI2cControllersNum ( + VOID + ); + +/** + return support status for P2SB PCR 20-bit addressing + + @retval TRUE + @retval FALSE +**/ +BOOLEAN +IsP2sb20bPcrSupported ( + VOID + ); + +#endif // _PCH_INFO_LIB_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchPciBdfLib.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchPciBdfLib.h new file mode 100644 index 0000000000..0c8e4d21a1 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchPciBdfLib.h @@ -0,0 +1,187 @@ +/** @file + Header file for PchPciBdfLib. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_PCI_BDF_LIB_H_ +#define _PCH_PCI_BDF_LIB_H_ + +/** + Get P2SB controller address that can be passed to the PCI Segment Library functions. + + @retval P2SB controller address in PCI Segment Library representation +**/ +UINT64 +P2sbPciCfgBase ( + VOID + ); + +/** + Get P2SB PCI device number + + @retval PCI dev number +**/ +UINT8 +P2sbDevNumber ( + VOID + ); + +/** + Get P2SB PCI function number + + @retval PCI fun number +**/ +UINT8 +P2sbFuncNumber ( + VOID + ); + +/** + Returns SPI PCI Config Space base address + + @retval UINT64 SPI Config Space base address +**/ +UINT64 +SpiPciCfgBase ( + VOID + ); + +/** + Returns SPI Device number + + @retval UINT8 PCH SPI Device number +**/ +UINT8 +SpiDevNumber ( + VOID + ); + +/** + Returns SPI Function number + + @retval UINT8 PCH SPI Function number +**/ +UINT8 +SpiFuncNumber ( + VOID + ); + +/** + Get XHCI controller address that can be passed to the PCI Segment Library functions. + + @retval XHCI controller address in PCI Segment Library representation +**/ +UINT64 +PchXhciPciCfgBase ( + VOID + ); + +/** + Get XHCI controller PCIe Device Number + + @retval XHCI controller PCIe Device Number +**/ +UINT8 +PchXhciDevNumber ( + VOID + ); + +/** + Get XHCI controller PCIe Function Number + + @retval XHCI controller PCIe Function Number +**/ +UINT8 +PchXhciFuncNumber ( + VOID + ); + +/** + Returns PCH LPC device PCI base address. + + @retval PCH LPC PCI base address. +**/ +UINT64 +LpcPciCfgBase ( + VOID + ); + +/** + Get LPC controller PCIe Device Number + + @retval LPC controller PCIe Device Number +**/ +UINT8 +LpcDevNumber ( + VOID + ); + + +/** + Get LPC controller PCIe Function Number + + @retval LPC controller PCIe Function Number +**/ +UINT8 +LpcFuncNumber ( + VOID + ); + + +/** + Get PCH PCIe controller PCIe Device Number + + @param[in] RpIndex Root port physical number. (0-based) + + @retval PCH PCIe controller PCIe Device Number +**/ +UINT8 +PchPcieRpDevNumber ( + IN UINTN RpIndex + ); + +/** + Get PCH PCIe controller PCIe Function Number + + @param[in] RpIndex Root port physical number. (0-based) + + @retval PCH PCIe controller PCIe Function Number +**/ +UINT8 +PchPcieRpFuncNumber ( + IN UINTN RpIndex + ); + +/** + Get HECI1 controller address that can be passed to the PCI Segment Library functions. + + @retval HECI1 controller address in PCI Segment Library representation +**/ +UINT64 +PchHeci1PciCfgBase ( + VOID + ); + +/** + Get HECI3 PCI device number + + @retval PCI dev number +**/ +UINT8 +PchHeci3DevNumber ( + VOID + ); + +/** + Get HECI3 PCI function number + + @retval PCI fun number +**/ +UINT8 +PchHeci3FuncNumber ( + VOID + ); + + +#endif //_PCH_PCI_BDF_LIB_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPolicyCommon.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPolicyCommon.h new file mode 100644 index 0000000000..f8a07098f0 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPolicyCommon.h @@ -0,0 +1,30 @@ +/** @file + PCH configuration based on PCH policy + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_POLICY_COMMON_H_ +#define _PCH_POLICY_COMMON_H_ + +#include <ConfigBlock.h> + +#include "PchLimits.h" +#include "ConfigBlock/PchGeneralConfig.h" +#include <PchPcieRpConfig.h> +#include <PchDmiConfig.h> +#include <PmConfig.h> +#include <SerialIoConfig.h> + +#ifndef FORCE_ENABLE +#define FORCE_ENABLE 1 +#endif +#ifndef FORCE_DISABLE +#define FORCE_DISABLE 2 +#endif +#ifndef PLATFORM_POR +#define PLATFORM_POR 0 +#endif + + +#endif // _PCH_POLICY_COMMON_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPreMemPolicyCommon.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPreMemPolicyCommon.h new file mode 100644 index 0000000000..2100a01071 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPreMemPolicyCommon.h @@ -0,0 +1,53 @@ +/** @file + PCH configuration based on PCH policy + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_PREMEM_POLICY_COMMON_H_ +#define _PCH_PREMEM_POLICY_COMMON_H_ + +#include <ConfigBlock.h> + +#include "PchLimits.h" +#include "ConfigBlock/PchGeneralConfig.h" +#include <WatchDogConfig.h> +#include <SmbusConfig.h> +#include <LpcConfig.h> +#include <PchDmiConfig.h> + +#pragma pack (push,1) + +#ifndef FORCE_ENABLE +#define FORCE_ENABLE 1 +#endif +#ifndef FORCE_DISABLE +#define FORCE_DISABLE 2 +#endif +#ifndef PLATFORM_POR +#define PLATFORM_POR 0 +#endif + +/** + PCH Policy revision number + Any backwards compatible changes to this structure will result in an update in the revision number +**/ +#define PCH_PREMEM_POLICY_REVISION 1 + +/** + PCH Policy PPI\n + All PCH config block change history will be listed here\n\n + + - <b>Revision 1</b>: + - Initial version.\n +**/ +typedef struct _PCH_PREMEM_POLICY { + CONFIG_BLOCK_TABLE_HEADER TableHeader; +/* + Individual Config Block Structures are added here in memory as part of AddConfigBlock() +*/ +} PCH_PREMEM_POLICY; + +#pragma pack (pop) + +#endif // _PCH_PREMEM_POLICY_COMMON_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchResetPlatformSpecific.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchResetPlatformSpecific.h new file mode 100644 index 0000000000..88884cac25 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchResetPlatformSpecific.h @@ -0,0 +1,21 @@ +/** @file + PCH Reset Platform Specific definitions. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_RESET_PLATFORM_SPECIFIC_H_ +#define _PCH_RESET_PLATFORM_SPECIFIC_H_ + +#define PCH_PLATFORM_SPECIFIC_RESET_STRING L"PCH_RESET" +#define PCH_RESET_DATA_STRING_MAX_LENGTH (sizeof (PCH_PLATFORM_SPECIFIC_RESET_STRING) / sizeof (UINT16)) + +extern EFI_GUID gPchGlobalResetGuid; + +typedef struct _RESET_DATA { + CHAR16 Description[PCH_RESET_DATA_STRING_MAX_LENGTH]; + EFI_GUID Guid; +} PCH_RESET_DATA; + +#endif // _PCH_RESET_PLATFORM_SPECIFIC_H_ + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchAcpiSmiDispatch.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchAcpiSmiDispatch.h new file mode 100644 index 0000000000..f22da50262 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchAcpiSmiDispatch.h @@ -0,0 +1,134 @@ +/** @file + APIs of PCH ACPI SMI Dispatch Protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_ACPI_SMI_DISPATCH_PROTOCOL_H_ +#define _PCH_ACPI_SMI_DISPATCH_PROTOCOL_H_ + +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gPchAcpiSmiDispatchProtocolGuid; + +// +// Forward reference for ANSI C compatibility +// +typedef struct _PCH_ACPI_SMI_DISPATCH_PROTOCOL PCH_ACPI_SMI_DISPATCH_PROTOCOL; + +// +// Member functions +// + +/** + Callback function for an PCH ACPI SMI handler dispatch. + + @param[in] DispatchHandle The unique handle assigned to this handler by register function. + +**/ +typedef +VOID +(EFIAPI *PCH_ACPI_SMI_DISPATCH_CALLBACK) ( + IN EFI_HANDLE DispatchHandle + ); + +/** + Register a child SMI source dispatch function for PCH ACPI SMI events. + + @param[in] This Protocol instance pointer. + @param[in] DispatchFunction Pointer to dispatch function to be invoked for + this SMI source + @param[out] DispatchHandle Handle of dispatch function, for when interfacing + with the parent SMM driver. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI source. + @retval EFI_OUT_OF_RESOURCES Not enough memory (system or SMM) to manage this child. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_ACPI_SMI_DISPATCH_REGISTER) ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function with a parent ACPI SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_ACPI_SMI_DISPATCH_UNREGISTER) ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +/** + Interface structure for PCH ACPI SMIs Dispatch Protocol + The PCH ACPI SMI DISPATCH PROTOCOL provides the ability to dispatch function for PCH ACPI related SMIs. + It contains SMI types of Pme, RtcAlarm, PmeB0, and Time overflow. +**/ +struct _PCH_ACPI_SMI_DISPATCH_PROTOCOL { + /** + This member specifies the revision of this structure. This field is used to + indicate backwards compatible changes to the protocol. + **/ + UINT8 Revision; + /** + Smi unregister function for PCH ACPI SMI DISPATCH PROTOCOL. + **/ + PCH_ACPI_SMI_DISPATCH_UNREGISTER UnRegister; + /** + Pme + The event is triggered by hardware when the PME# signal goes active. + Additionally, the event is only triggered when SCI_EN is not set. + **/ + PCH_ACPI_SMI_DISPATCH_REGISTER PmeRegister; + /** + PmeB0 + The event is triggered PCH when any internal device with PCI Power Management + capabilities on bus 0 asserts the equivalent of the PME# signal. + Additionally, the event is only triggered when SCI_EN is not set. + The following are internal devices which can set this bit: + Intel HD Audio, Intel Management Engine "maskable" wake events, Integrated LAN, + SATA, xHCI, Intel SST + **/ + PCH_ACPI_SMI_DISPATCH_REGISTER PmeB0Register; + /** + RtcAlarm + The event is triggered by hardware when the RTC generates an alarm + (assertion of the IRQ8# signal). + **/ + PCH_ACPI_SMI_DISPATCH_REGISTER RtcAlarmRegister; + /** + TmrOverflow + The event is triggered any time bit 22 of the 24-bit timer goes high + (bits are numbered from 0 to 23). + This will occur every 2.3435 seconds. When the TMROF_EN bit (ABASE + 02h, bit 0) is set, + then the setting of the TMROF_STS bit will additionally generate an SMI# + Additionally, the event is only triggered when SCI_EN is not set. + **/ + PCH_ACPI_SMI_DISPATCH_REGISTER TmrOverflowRegister; +}; + +/** + PCH ACPI SMI dispatch revision number + + Revision 1: Initial version +**/ +#define PCH_ACPI_SMI_DISPATCH_REVISION 1 + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchPcieSmiDispatch.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchPcieSmiDispatch.h new file mode 100644 index 0000000000..0c0f1ab962 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchPcieSmiDispatch.h @@ -0,0 +1,166 @@ +/** @file + APIs of PCH PCIE SMI Dispatch Protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_PCIE_SMI_DISPATCH_PROTOCOL_H_ +#define _PCH_PCIE_SMI_DISPATCH_PROTOCOL_H_ + +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gPchPcieSmiDispatchProtocolGuid; + +// +// Forward reference for ANSI C compatibility +// +typedef struct _PCH_PCIE_SMI_DISPATCH_PROTOCOL PCH_PCIE_SMI_DISPATCH_PROTOCOL; + +typedef enum { + PchRpIndex0 = 0, + PchRpIndex1 = 1, + PchRpIndex2 = 2, + PchRpIndex3 = 3, + PchRpIndex4 = 4, + PchRpIndex5 = 5, + PchRpIndex6 = 6, + PchRpIndex7 = 7, + PchRpIndex8 = 8, + PchRpIndex9 = 9, + PchRpIndex10 = 10, + PchRpIndex11 = 11, + PchRpIndex12 = 12, + PchRpIndex13 = 13, + PchRpIndex14 = 14, + PchRpIndex15 = 15, + PchRpIndex16 = 16, + PchRpIndex17 = 17, + PchRpIndex18 = 18, + PchRpIndex19 = 19, + PchRpIndex20 = 20, + PchRpIndex21 = 21, + PchRpIndex22 = 22, + PchRpIndex23 = 23, + /** + Quantity of PCH and CPU PCIe ports, as well as their encoding in this enum, may change between + silicon generations and series. Do not assume that PCH port 0 will be always encoded by 0. + Instead, it is recommended to use (PchRpIndex0 + PchPortIndex) style to be forward-compatible + **/ + CpuRpIndex0 = 0x40, + CpuRpIndex1 = 0x41, + CpuRpIndex2 = 0x42, + CpuRpIndex3 = 0x43 +} PCIE_COMBINED_RPINDEX; + +// +// Member functions +// + +typedef struct { + UINT8 RpIndex; ///< Root port index (0-based), 0: RP1, 1: RP2, n: RP(N+1) + UINT8 BusNum; ///< Root port pci bus number + UINT8 DevNum; ///< Root port pci device number + UINT8 FuncNum; ///< Root port pci function number +} PCH_PCIE_SMI_RP_CONTEXT; + +/** + Callback function for an PCH PCIE RP SMI handler dispatch. + + @param[in] DispatchHandle The unique handle assigned to this handler by register function. + @param[in] RpContext Pointer of PCH PCIE Root Port context. + +**/ +typedef +VOID +(EFIAPI *PCH_PCIE_SMI_RP_DISPATCH_CALLBACK) ( + IN EFI_HANDLE DispatchHandle, + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext + ); + +/** + Register a child SMI source dispatch function for PCH PCIERP SMI events. + + @param[in] This Protocol instance pointer. + @param[in] DispatchFunction Pointer to dispatch function to be invoked for + this SMI source + @param[in] RpIndex Refer PCIE_COMBINED_RPINDEX for PCH RP index and CPU RP index. + 0: RP1, 1: RP2, n: RP(N+1) + @param[out] DispatchHandle Handle of dispatch function, for when interfacing + with the parent SMM driver. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI source. + @retval EFI_OUT_OF_RESOURCES Not enough memory (system or SMM) to manage this child. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_PCIE_SMI_RP_DISPATCH_REGISTER) ( + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This, + IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction, + IN UINTN RpIndex, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function with a parent PCIE SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_PCIE_SMI_DISPATCH_UNREGISTER) ( + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +/** + Interface structure for PCH PCIE SMIs Dispatch Protocol + The PCH PCIE SMI DISPATCH PROTOCOL provides the ability to dispatch function for PCH PCIE related SMIs. + It contains SMI types of HotPlug, LinkActive, and Link EQ. +**/ +struct _PCH_PCIE_SMI_DISPATCH_PROTOCOL { + /** + This member specifies the revision of this structure. This field is used to + indicate backwards compatible changes to the protocol. + **/ + UINT8 Revision; + /** + Smi unregister function for PCH PCIE SMI DISPATCH PROTOCOL. + **/ + PCH_PCIE_SMI_DISPATCH_UNREGISTER UnRegister; + /** + PcieRpXHotPlug + The event is triggered when PCIE root port Hot-Plug Presence Detect. + **/ + PCH_PCIE_SMI_RP_DISPATCH_REGISTER HotPlugRegister; + /** + PcieRpXLinkActive + The event is triggered when Hot-Plug Link Active State Changed. + **/ + PCH_PCIE_SMI_RP_DISPATCH_REGISTER LinkActiveRegister; + /** + PcieRpXLinkEq + The event is triggered when Device Requests Software Link Equalization. + **/ + PCH_PCIE_SMI_RP_DISPATCH_REGISTER LinkEqRegister; +}; + +/** + PCH PCIE SMI dispatch revision number + + Revision 1: Initial version +**/ +#define PCH_PCIE_SMI_DISPATCH_REVISION 1 + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmiDispatch.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmiDispatch.h new file mode 100644 index 0000000000..fd270fe72a --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmiDispatch.h @@ -0,0 +1,132 @@ +/** @file + APIs of PCH SMI Dispatch Protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_SMI_DISPATCH_PROTOCOL_H_ +#define _PCH_SMI_DISPATCH_PROTOCOL_H_ + +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gPchSmiDispatchProtocolGuid; + +// +// Forward reference for ANSI C compatibility +// +typedef struct _PCH_SMI_DISPATCH_PROTOCOL PCH_SMI_DISPATCH_PROTOCOL; + +// +// Member functions +// + +/** + Callback function for an PCH SMI handler dispatch. + + @param[in] DispatchHandle The unique handle assigned to this handler by register function. + +**/ +typedef +VOID +(EFIAPI *PCH_SMI_DISPATCH_CALLBACK) ( + IN EFI_HANDLE DispatchHandle + ); + +/** + Register a child SMI source dispatch function for specific PCH SMI dispatch event. + + @param[in] This Protocol instance pointer. + @param[in] DispatchFunction Pointer to dispatch function to be invoked for + this SMI source + @param[out] DispatchHandle Handle of dispatch function, for when interfacing + with the parent SMM driver. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI source. + @retval EFI_OUT_OF_RESOURCES Not enough memory (system or SMM) to manage this child. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_SMI_DISPATCH_REGISTER) ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_SMI_DISPATCH_UNREGISTER) ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +/** + Interface structure for PCH specific SMIs Dispatch Protocol + The PCH SMI DISPATCH PROTOCOL provides the ability to dispatch function for PCH misc SMIs. + It contains legacy SMIs and new PCH SMI types like: + SerialIrq, McSmi, Smbus, ... +**/ +struct _PCH_SMI_DISPATCH_PROTOCOL { + /** + This member specifies the revision of this structure. This field is used to + indicate backwards compatible changes to the protocol. + **/ + UINT8 Revision; + /** + Smi unregister function for PCH SMI DISPATCH PROTOCOL. + **/ + PCH_SMI_DISPATCH_UNREGISTER UnRegister; + /** + SerialIrq + The event is triggered while the SMI# was caused by the SERIRQ decoder. + **/ + PCH_SMI_DISPATCH_REGISTER SerialIrqRegister; + /** + McSmi + The event is triggered if there has been an access to the power management + microcontroller range (62h or 66h) and the Microcontroller Decode Enable #1 bit + in the LPC Bridge I/O Enables configuration register is 1 . + **/ + PCH_SMI_DISPATCH_REGISTER McSmiRegister; + /** + SmBus + The event is triggered while the SMI# was caused by: + 1. The SMBus target receiving a message that an SMI# should be caused, or + 2. The SMBALERT# signal goes active and the SMB_SMI_EN bit is set and the + SMBALERT_DIS bit is cleared, or + 3. The SMBus target receiving a Host Notify message and the HOST_NOTIFY_INTREN and + the SMB_SMI_EN bits are set, or + 4. The PCH detecting the SMLINK_SLAVE_SMI command while in the S0 state. + **/ + PCH_SMI_DISPATCH_REGISTER SmbusRegister; + /** + SPI Asynchronous + When registered, the flash controller will generate an SMI when it blocks a BIOS write or erase. + **/ + PCH_SMI_DISPATCH_REGISTER SpiAsyncRegister; +}; + +/** + PCH SMI dispatch revision number + + Revision 1: Initial version +**/ +#define PCH_SMI_DISPATCH_REVISION 1 + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmIoTrapControl.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmIoTrapControl.h new file mode 100644 index 0000000000..87c301901e --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmIoTrapControl.h @@ -0,0 +1,65 @@ +/** @file + PCH SMM IO Trap Control Protocol + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_SMM_IO_TRAP_CONTROL_H_ +#define _PCH_SMM_IO_TRAP_CONTROL_H_ + + +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gPchSmmIoTrapControlGuid; + +// +// Forward reference for ANSI C compatibility +// +typedef struct _PCH_SMM_IO_TRAP_CONTROL_PROTOCOL PCH_SMM_IO_TRAP_CONTROL_PROTOCOL; + +// +// Related Definitions +// + +// +// Member functions +// + +/** + The Prototype of Pause and Resume IoTrap callback function. + + @param[in] This Pointer to the PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance. + @param[in] DispatchHandle Handle of the child service to change state. + + @retval EFI_SUCCESS This operation is complete. + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. + @retval EFI_ACCESS_DENIED The SMI status is alrady PAUSED/RESUMED. +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_SMM_IO_TRAP_CONTROL_FUNCTION) ( + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL * This, + IN EFI_HANDLE DispatchHandle + ); + +/** + Interface structure for the SMM IO trap pause and resume protocol + This protocol provides the functions to runtime control the IoTrap SMI enabled/disable. + This applys the capability to the DispatchHandle which returned by IoTrap callback + registration, and the DispatchHandle which must be MergeDisable = TRUE and Address != 0. + Besides, when S3 resuem, it only restores the state of IoTrap callback registration. + The Paused/Resume state won't be restored after S3 resume. +**/ +struct _PCH_SMM_IO_TRAP_CONTROL_PROTOCOL { + /** + This runtime pauses a registered IoTrap handler. + **/ + PCH_SMM_IO_TRAP_CONTROL_FUNCTION Pause; + /** + This runtime resumes a registered IoTrap handler. + **/ + PCH_SMM_IO_TRAP_CONTROL_FUNCTION Resume; +}; + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmPeriodicTimerControl.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmPeriodicTimerControl.h new file mode 100644 index 0000000000..f4773c3dd3 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmPeriodicTimerControl.h @@ -0,0 +1,65 @@ +/** @file + PCH SMM Periodic Timer Control Protocol + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_SMM_PERIODIC_TIMER_CONTROL_H_ +#define _PCH_SMM_PERIODIC_TIMER_CONTROL_H_ + + +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gPchSmmPeriodicTimerControlGuid; + +// +// Forward reference for ANSI C compatibility +// +typedef struct _PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL; + +// +// Related Definitions +// + +// +// Member functions +// + +/** + The Prototype of Pause and Resume SMM PERIODIC TIMER function. + + @param[in] This Pointer to the PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL instance. + @param[in] DispatchHandle Handle of the child service to change state. + + @retval EFI_SUCCESS This operation is complete. + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. + @retval EFI_ACCESS_DENIED The SMI status is alrady PAUSED/RESUMED. +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_SMM_PERIODIC_TIMER_CONTROL_FUNCTION) ( + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +/** + Interface structure for the SMM PERIODIC TIMER pause and resume protocol + This protocol provides the functions to runtime control the SM periodic timer enabled/disable. + This applies the capability to the DispatchHandle which returned by SMM periodic timer callback + registration. + Besides, when S3 resume, it only restores the state of callback registration. + The Paused/Resume state won't be restored after S3 resume. +**/ +struct _PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL { + /** + This runtime pauses the registered periodic timer handler. + **/ + PCH_SMM_PERIODIC_TIMER_CONTROL_FUNCTION Pause; + /** + This runtime resumes the registered periodic timer handler. + **/ + PCH_SMM_PERIODIC_TIMER_CONTROL_FUNCTION Resume; +}; + +#endif // _PCH_SMM_PERIODIC_TIMER_CONTROL_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchTcoSmiDispatch.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchTcoSmiDispatch.h new file mode 100644 index 0000000000..f39773e420 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchTcoSmiDispatch.h @@ -0,0 +1,150 @@ +/** @file + APIs of PCH TCO SMI Dispatch Protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_TCO_SMI_DISPATCH_PROTOCOL_H_ +#define _PCH_TCO_SMI_DISPATCH_PROTOCOL_H_ + +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gPchTcoSmiDispatchProtocolGuid; + +// +// Forward reference for ANSI C compatibility +// +typedef struct _PCH_TCO_SMI_DISPATCH_PROTOCOL PCH_TCO_SMI_DISPATCH_PROTOCOL; + +// +// Member functions +// + +/** + Callback function for an PCH TCO SMI handler dispatch. + + @param[in] DispatchHandle The unique handle assigned to this handler by register function. + +**/ +typedef +VOID +(EFIAPI *PCH_TCO_SMI_DISPATCH_CALLBACK) ( + IN EFI_HANDLE DispatchHandle + ); + +/** + Register a child SMI source dispatch function for PCH TCO SMI events. + + @param[in] This Protocol instance pointer. + @param[in] DispatchFunction Pointer to dispatch function to be invoked for + this SMI source + @param[out] DispatchHandle Handle of dispatch function, for when interfacing + with the parent SMM driver. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI source. + @retval EFI_OUT_OF_RESOURCES Not enough memory (system or SMM) to manage this child. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_TCO_SMI_DISPATCH_REGISTER) ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function with a parent TCO SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_TCO_SMI_DISPATCH_UNREGISTER) ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +/** + Interface structure for PCH TCO SMIs Dispatch Protocol + The PCH TCO SMI DISPATCH PROTOCOL provides the ability to dispatch function for PCH TCO related SMIs. + It contains SMI types of Mch, TcoTimeout, OsTco, Nmi, IntruderDectect, and BiowWp. +**/ +struct _PCH_TCO_SMI_DISPATCH_PROTOCOL { + /** + This member specifies the revision of this structure. This field is used to + indicate backwards compatible changes to the protocol. + **/ + UINT8 Revision; + /** + Smi unregister function for PCH TCO SMI DISPATCH PROTOCOL. + **/ + PCH_TCO_SMI_DISPATCH_UNREGISTER UnRegister; + /** + Mch + The event is triggered when PCH received a DMI special cycle message using DMI indicating that + it wants to cause an SMI. + The software must read the processor to determine the reason for the SMI. + **/ + PCH_TCO_SMI_DISPATCH_REGISTER MchRegister; + /** + TcoTimeout + The event is triggered by PCH to indicate that the SMI was caused by the TCO timer reaching 0. + **/ + PCH_TCO_SMI_DISPATCH_REGISTER TcoTimeoutRegister; + /** + OsTco + The event is triggered when software caused an SMI# by writing to the TCO_DAT_IN register (TCOBASE + 02h). + **/ + PCH_TCO_SMI_DISPATCH_REGISTER OsTcoRegister; + /** + Nmi + The event is triggered by the PCH when an SMI# occurs because an event occurred that would otherwise have + caused an NMI (because NMI2SMI_EN is set) + **/ + PCH_TCO_SMI_DISPATCH_REGISTER NmiRegister; + /** + IntruderDectect + The event is triggered by PCH to indicate that an intrusion was detected. + **/ + PCH_TCO_SMI_DISPATCH_REGISTER IntruderDetRegister; + /** + SpiBiosWp + This event is triggered when SMI# was caused by the TCO logic and + SPI flash controller asserted Synchronous SMI by BIOS lock enable set. + **/ + PCH_TCO_SMI_DISPATCH_REGISTER SpiBiosWpRegister; + /** + LpcBiosWp + This event is triggered when SMI# was caused by the TCO logic and + LPC/eSPI BIOS lock enable set. + **/ + PCH_TCO_SMI_DISPATCH_REGISTER LpcBiosWpRegister; + /** + NewCentury + This event is triggered when SMI# was caused by the TCO logic and + year of RTC date rolls over a century (99 to 00). + **/ + PCH_TCO_SMI_DISPATCH_REGISTER NewCenturyRegister; +}; + +/** + PCH TCO SMI dispatch revision number + + Revision 1: Initial version + Revision 2: Add NEWCENTURY support +**/ +#define PCH_TCO_SMI_DISPATCH_REVISION 2 + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/SmmSmbus.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/SmmSmbus.h new file mode 100644 index 0000000000..fa1a79ca84 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/SmmSmbus.h @@ -0,0 +1,13 @@ +/** @file + SmmSmbus Protocol + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef __EFI_SMM_SMBUS_PROTOCOL_H__ +#define __EFI_SMM_SMBUS_PROTOCOL_H__ + +extern EFI_GUID gEfiSmmSmbusProtocolGuid; + +#endif + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Register/PchRegs.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Register/PchRegs.h new file mode 100644 index 0000000000..33b75e82fd --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Register/PchRegs.h @@ -0,0 +1,45 @@ +/** @file + Generic register definitions for PCH. + +Conventions: + + - Register definition format: + Prefix_[GenerationName]_[ComponentName]_SubsystemName_RegisterSpace_RegisterName + - Prefix: + Definitions beginning with "R_" are registers + Definitions beginning with "B_" are bits within registers + Definitions beginning with "V_" are meaningful values within the bits + Definitions beginning with "S_" are register size + Definitions beginning with "N_" are the bit position + - [GenerationName]: + Three letter acronym of the generation is used (e.g. SKL,KBL,CNL etc.). + Register name without GenerationName applies to all generations. + - [ComponentName]: + This field indicates the component name that the register belongs to (e.g. PCH, SA etc.) + Register name without ComponentName applies to all components. + Register that is specific to -H denoted by "_PCH_H_" in component name. + Register that is specific to -LP denoted by "_PCH_LP_" in component name. + - SubsystemName: + This field indicates the subsystem name of the component that the register belongs to + (e.g. PCIE, USB, SATA, GPIO, PMC etc.). + - RegisterSpace: + MEM - MMIO space register of subsystem. + IO - IO space register of subsystem. + PCR - Private configuration register of subsystem. + CFG - PCI configuration space register of subsystem. + - RegisterName: + Full register name. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_REGS_H_ +#define _PCH_REGS_H_ + +/// +/// The default PCH PCI segment and bus number +/// +#define DEFAULT_PCI_SEGMENT_NUMBER_PCH 0 +#define DEFAULT_PCI_BUS_NUMBER_PCH 0 + +#endif //_PCH_REGS_H_ -- 2.36.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107570): https://edk2.groups.io/g/devel/message/107570 Mute This Topic: https://groups.io/mt/100551002/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [edk2-devel] [PATCH v2 3/7] AlderlakeSiliconPkg/Pch: Add include headers 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 3/7] AlderlakeSiliconPkg/Pch: Add include headers Saloni Kasbekar @ 2023-08-16 2:44 ` Chuang, Rosen 0 siblings, 0 replies; 14+ messages in thread From: Chuang, Rosen @ 2023-08-16 2:44 UTC (permalink / raw) To: Kasbekar, Saloni, devel@edk2.groups.io Cc: Chaganty, Rangasai V, Desimone, Nathaniel L, Oram, Isaac W Reviewed-by: Rosen Chuang < rosen.chuang@intel.com> -----Original Message----- From: Kasbekar, Saloni <saloni.kasbekar@intel.com> Sent: Saturday, August 5, 2023 1:38 AM To: devel@edk2.groups.io Cc: Kasbekar, Saloni <saloni.kasbekar@intel.com>; Chaganty, Rangasai V <rangasai.v.chaganty@intel.com>; Desimone, Nathaniel L <nathaniel.l.desimone@intel.com>; Oram, Isaac W <isaac.w.oram@intel.com>; Chuang, Rosen <rosen.chuang@intel.com> Subject: [PATCH v2 3/7] AlderlakeSiliconPkg/Pch: Add include headers Adds the following header files: * Pch/Include Cc: Sai Chaganty <rangasai.v.chaganty@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Isaac Oram <isaac.w.oram@intel.com> Cc: Rosen Chuang <rosen.chuang@intel.com> Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com> --- .../Include/ConfigBlock/PchGeneralConfig.h | 86 ++++++++ .../Pch/Include/Library/PchCycleDecodingLib.h | 59 ++++++ .../Pch/Include/Library/PchInfoDefs.h | 19 ++ .../Pch/Include/Library/PchInfoLib.h | 108 ++++++++++ .../Pch/Include/Library/PchPciBdfLib.h | 187 ++++++++++++++++++ .../Pch/Include/PchPolicyCommon.h | 30 +++ .../Pch/Include/PchPreMemPolicyCommon.h | 53 +++++ .../Pch/Include/PchResetPlatformSpecific.h | 21 ++ .../Pch/Include/Protocol/PchAcpiSmiDispatch.h | 134 +++++++++++++ .../Pch/Include/Protocol/PchPcieSmiDispatch.h | 166 ++++++++++++++++ .../Pch/Include/Protocol/PchSmiDispatch.h | 132 +++++++++++++ .../Include/Protocol/PchSmmIoTrapControl.h | 65 ++++++ .../Protocol/PchSmmPeriodicTimerControl.h | 65 ++++++ .../Pch/Include/Protocol/PchTcoSmiDispatch.h | 150 ++++++++++++++ .../Pch/Include/Protocol/SmmSmbus.h | 13 ++ .../Pch/Include/Register/PchRegs.h | 45 +++++ 16 files changed, 1333 insertions(+) create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/ConfigBlock/PchGeneralConfig.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchCycleDecodingLib.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoDefs.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoLib.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchPciBdfLib.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPolicyCommon.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPreMemPolicyCommon.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchResetPlatformSpecific.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchAcpiSmiDispatch.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchPcieSmiDispatch.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmiDispatch.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmIoTrapControl.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmPeriodicTimerControl.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchTcoSmiDispatch.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/SmmSmbus.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Register/PchRegs.h diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/ConfigBlock/PchGeneralConfig.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/ConfigBlock/PchGeneralConfig.h new file mode 100644 index 0000000000..4501537fe2 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/ConfigBlock/PchGener +++ alConfig.h @@ -0,0 +1,86 @@ +/** @file + PCH General policy + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PCH_GENERAL_CONFIG_H_ #define _PCH_GENERAL_CONFIG_H_ + + +extern EFI_GUID gPchGeneralConfigGuid; +extern EFI_GUID gPchGeneralPreMemConfigGuid; + +#pragma pack (push,1) + +enum PCH_RESERVED_PAGE_ROUTE { + PchReservedPageToLpc, ///< Port 80h cycles are sent to LPC. + PchReservedPageToPcie ///< Port 80h cycles are sent to PCIe. +}; + +/** + PCH General Configuration + <b>Revision 1</b>: - Initial version. + <b>Revision 2</b>: - Added AcpiL6dPmeHandling **/ typedef struct { + CONFIG_BLOCK_HEADER Header; ///< Config Block Header + /** + This member describes whether or not the Compatibility Revision ID (CRID) feature + of PCH should be enabled. <b>0: Disable</b>; 1: Enable + **/ + UINT32 Crid : 1; + /** + Set to enable low latency of legacy IO. + Some systems require lower IO latency irrespective of power. + This is a tradeoff between power and IO latency. + @note: Once this is enabled, DmiAspm, Pcie DmiAspm in SystemAgent + and ITSS Clock Gating are forced to disabled. + <b>0: Disable</b>, 1: Enable + **/ + UINT32 LegacyIoLowLatency : 1; + /** + Enables _L6D ACPI handler. + PME GPE is shared by multiple devices So BIOS must verify the same in +the ASL handler by reading offset for PMEENABLE and PMESTATUS bit + <b>0: Disable</b>, 1: Enable + **/ + UINT32 AcpiL6dPmeHandling : 1; + UINT32 RsvdBits0 : 29; ///< Reserved bits +} PCH_GENERAL_CONFIG; + +/** + PCH General Pre-Memory Configuration + <b>Revision 1</b>: - Initial version. + <b>Revision 2</b>: - Added GpioOverride. + <b>Revision 3</b>: - Added IoeDebugEn, PmodeClkEn **/ typedef struct +{ + CONFIG_BLOCK_HEADER Header; ///< Config Block Header + /** + Control where the Port 80h cycles are sent, <b>0: LPC</b>; 1: PCI. + **/ + UINT32 Port80Route : 1; + UINT32 IotgPllSscEn : 1; ///< Need to disable CPU Side SSC for A0 PO + /** + Gpio override Level + -- <b>0: Disable</b>; + - 1: Override Level 1 - Skips GPIO configuration in PEI/FSPM/FSPT phase + - 2: Override Level 2 - Reserved for future use + **/ + UINT32 GpioOverride : 3; + /** + Enable/Disable IOE Debug. When enabled, IOE D2D Dfx link and clock will keep up for debug + <b>0: Disable</b>; 1: Enable + **/ + UINT32 IoeDebugEn : 1; + /** + Enable/Disable PMODE clock. When enabled, Pmode clock will toggle for XDP use + <b>0: Disable</b>; 1: Enable + **/ + UINT32 PmodeClkEn : 1; + UINT32 RsvdBits0 : 25; ///< Reserved bits +} PCH_GENERAL_PREMEM_CONFIG; + +#pragma pack (pop) + +#endif // _PCH_GENERAL_CONFIG_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchCycleDecodingLib.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchCycleDecodingLib.h new file mode 100644 index 0000000000..65ecd58de1 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchCycleDeco +++ dingLib.h @@ -0,0 +1,59 @@ +/** @file + Header file for PchCycleDecodingLib. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PCH_CYCLE_DECODING_LIB_H_ #define _PCH_CYCLE_DECODING_LIB_H_ + +/** + Get PCH TCO base address. + + @param[out] Address Address of TCO base address. + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_INVALID_PARAMETER Invalid pointer passed. +**/ +EFI_STATUS +PchTcoBaseGet ( + OUT UINT16 *Address + ); + +/** + Set PCH LPC IO decode ranges. + Program LPC I/O Decode Ranges, PCR[DMI] + 2770h[15:0] to the same value programmed in LPC offset 80h. + Please check EDS for detail of Lpc IO decode ranges bit definition. + Bit 12: FDD range + Bit 9:8: LPT range + Bit 6:4: ComB range + Bit 2:0: ComA range + + @param[in] LpcIoDecodeRanges Lpc IO decode ranges bit settings. + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_UNSUPPORTED DMIC.SRL is set. +**/ +EFI_STATUS +PchLpcIoDecodeRangesSet ( + IN UINT16 LpcIoDecodeRanges + ); + +/** + Set PCH LPC and eSPI CS0# IO enable decoding. + Setup I/O Enables in DMI to the same value program in LPC/eSPI PCI offset 82h. + Note: Bit[15:10] of the source decode register is Read-Only. The IO +range indicated by the Enables field + in LPC/eSPI PCI offset 82h[13:10] is always forwarded by DMI to subtractive agent for handling. + Please check EDS for detail of LPC/eSPI IO decode ranges bit definition. + + @param[in] LpcIoEnableDecoding LPC IO enable decoding bit settings. + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_UNSUPPORTED DMIC.SRL is set. +**/ +EFI_STATUS +PchLpcIoEnableDecodingSet ( + IN UINT16 LpcIoEnableDecoding + ); + +#endif // _PCH_CYCLE_DECODING_LIB_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoDefs.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoDefs.h new file mode 100644 index 0000000000..9328e1899c --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoDefs. +++ h @@ -0,0 +1,19 @@ +/** @file + Header file for PchInfoDefs. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PCH_INFO_DEFS_H_ #define _PCH_INFO_DEFS_H_ + +#define PCH_STEPPING_MAX 0xFF + +#define PCH_LP 2 +#define PCH_N 3 +#define PCH_S 4 +#define PCH_P 5 +#define PCH_M 6 +#define PCH_UNKNOWN_SERIES 0xFF + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoLib.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoLib.h new file mode 100644 index 0000000000..d5d412c9f2 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchInfoLib.h @@ -0,0 +1,108 @@ +/** @file + Header file for PchInfoLib. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PCH_INFO_LIB_H_ #define _PCH_INFO_LIB_H_ + +#include <Uefi/UefiBaseType.h> +#include "PchInfoDefs.h" + +typedef UINT8 PCH_STEPPING; +typedef UINT8 PCH_SERIES; +typedef UINT8 PCH_GENERATION; + +typedef enum { + RstUnsupported = 0, + RstPremium, + RstOptane, + RstMaxMode +} RST_MODE; + +/** + Return LPC Device Id + + @retval PCH_LPC_DEVICE_ID PCH Lpc Device ID +**/ +UINT16 +PchGetLpcDid ( + VOID + ); + +/** + Return Pch stepping type + + @retval PCH_STEPPING Pch stepping type +**/ +PCH_STEPPING +PchStepping ( + VOID + ); + +/** + Return Pch Series + + @retval PCH_SERIES Pch Series +**/ +PCH_SERIES +PchSeries ( + VOID + ); + +/** + Check if this is PCH LP series + + @retval TRUE It's PCH LP series + @retval FALSE It's not PCH LP series +**/ +BOOLEAN +IsPchLp ( + VOID + ); + + +/** + Check if this is PCH P series + + @retval TRUE It's PCH P series + @retval FALSE It's not PCH P series +**/ +BOOLEAN +IsPchP ( + VOID + ); + +/** + Get Pch Maximum Pcie Root Port Number + + @retval PcieMaxRootPort Pch Maximum Pcie Root Port Number +**/ +UINT8 +GetPchMaxPciePortNum ( + VOID + ); + +/** + Get Pch Maximum Serial IO I2C controllers number + + @retval Pch Maximum Serial IO I2C controllers number **/ +UINT8 +GetPchMaxSerialIoI2cControllersNum ( + VOID + ); + +/** + return support status for P2SB PCR 20-bit addressing + + @retval TRUE + @retval FALSE +**/ +BOOLEAN +IsP2sb20bPcrSupported ( + VOID + ); + +#endif // _PCH_INFO_LIB_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchPciBdfLib.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchPciBdfLib.h new file mode 100644 index 0000000000..0c8e4d21a1 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Library/PchPciBdfLib +++ .h @@ -0,0 +1,187 @@ +/** @file + Header file for PchPciBdfLib. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PCH_PCI_BDF_LIB_H_ #define _PCH_PCI_BDF_LIB_H_ + +/** + Get P2SB controller address that can be passed to the PCI Segment Library functions. + + @retval P2SB controller address in PCI Segment Library representation +**/ +UINT64 +P2sbPciCfgBase ( + VOID + ); + +/** + Get P2SB PCI device number + + @retval PCI dev number +**/ +UINT8 +P2sbDevNumber ( + VOID + ); + +/** + Get P2SB PCI function number + + @retval PCI fun number +**/ +UINT8 +P2sbFuncNumber ( + VOID + ); + +/** + Returns SPI PCI Config Space base address + + @retval UINT64 SPI Config Space base address **/ +UINT64 +SpiPciCfgBase ( + VOID + ); + +/** + Returns SPI Device number + + @retval UINT8 PCH SPI Device number +**/ +UINT8 +SpiDevNumber ( + VOID + ); + +/** + Returns SPI Function number + + @retval UINT8 PCH SPI Function number +**/ +UINT8 +SpiFuncNumber ( + VOID + ); + +/** + Get XHCI controller address that can be passed to the PCI Segment Library functions. + + @retval XHCI controller address in PCI Segment Library representation +**/ +UINT64 +PchXhciPciCfgBase ( + VOID + ); + +/** + Get XHCI controller PCIe Device Number + + @retval XHCI controller PCIe Device Number **/ +UINT8 +PchXhciDevNumber ( + VOID + ); + +/** + Get XHCI controller PCIe Function Number + + @retval XHCI controller PCIe Function Number **/ +UINT8 +PchXhciFuncNumber ( + VOID + ); + +/** + Returns PCH LPC device PCI base address. + + @retval PCH LPC PCI base address. +**/ +UINT64 +LpcPciCfgBase ( + VOID + ); + +/** + Get LPC controller PCIe Device Number + + @retval LPC controller PCIe Device Number **/ +UINT8 +LpcDevNumber ( + VOID + ); + + +/** + Get LPC controller PCIe Function Number + + @retval LPC controller PCIe Function Number **/ +UINT8 +LpcFuncNumber ( + VOID + ); + + +/** + Get PCH PCIe controller PCIe Device Number + + @param[in] RpIndex Root port physical number. (0-based) + + @retval PCH PCIe controller PCIe Device Number **/ +UINT8 +PchPcieRpDevNumber ( + IN UINTN RpIndex + ); + +/** + Get PCH PCIe controller PCIe Function Number + + @param[in] RpIndex Root port physical number. (0-based) + + @retval PCH PCIe controller PCIe Function Number **/ +UINT8 +PchPcieRpFuncNumber ( + IN UINTN RpIndex + ); + +/** + Get HECI1 controller address that can be passed to the PCI Segment Library functions. + + @retval HECI1 controller address in PCI Segment Library +representation **/ +UINT64 +PchHeci1PciCfgBase ( + VOID + ); + +/** + Get HECI3 PCI device number + + @retval PCI dev number +**/ +UINT8 +PchHeci3DevNumber ( + VOID + ); + +/** + Get HECI3 PCI function number + + @retval PCI fun number +**/ +UINT8 +PchHeci3FuncNumber ( + VOID + ); + + +#endif //_PCH_PCI_BDF_LIB_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPolicyCommon.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPolicyCommon.h new file mode 100644 index 0000000000..f8a07098f0 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPolicyCommon.h @@ -0,0 +1,30 @@ +/** @file + PCH configuration based on PCH policy + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PCH_POLICY_COMMON_H_ #define _PCH_POLICY_COMMON_H_ + +#include <ConfigBlock.h> + +#include "PchLimits.h" +#include "ConfigBlock/PchGeneralConfig.h" +#include <PchPcieRpConfig.h> +#include <PchDmiConfig.h> +#include <PmConfig.h> +#include <SerialIoConfig.h> + +#ifndef FORCE_ENABLE +#define FORCE_ENABLE 1 +#endif +#ifndef FORCE_DISABLE +#define FORCE_DISABLE 2 +#endif +#ifndef PLATFORM_POR +#define PLATFORM_POR 0 +#endif + + +#endif // _PCH_POLICY_COMMON_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPreMemPolicyCommon.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPreMemPolicyCommon.h new file mode 100644 index 0000000000..2100a01071 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchPreMemPolicyCommo +++ n.h @@ -0,0 +1,53 @@ +/** @file + PCH configuration based on PCH policy + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PCH_PREMEM_POLICY_COMMON_H_ #define _PCH_PREMEM_POLICY_COMMON_H_ + +#include <ConfigBlock.h> + +#include "PchLimits.h" +#include "ConfigBlock/PchGeneralConfig.h" +#include <WatchDogConfig.h> +#include <SmbusConfig.h> +#include <LpcConfig.h> +#include <PchDmiConfig.h> + +#pragma pack (push,1) + +#ifndef FORCE_ENABLE +#define FORCE_ENABLE 1 +#endif +#ifndef FORCE_DISABLE +#define FORCE_DISABLE 2 +#endif +#ifndef PLATFORM_POR +#define PLATFORM_POR 0 +#endif + +/** + PCH Policy revision number + Any backwards compatible changes to this structure will result in an +update in the revision number **/ #define PCH_PREMEM_POLICY_REVISION 1 + +/** + PCH Policy PPI\n + All PCH config block change history will be listed here\n\n + + - <b>Revision 1</b>: + - Initial version.\n +**/ +typedef struct _PCH_PREMEM_POLICY { + CONFIG_BLOCK_TABLE_HEADER TableHeader; +/* + Individual Config Block Structures are added here in memory as part +of AddConfigBlock() */ } PCH_PREMEM_POLICY; + +#pragma pack (pop) + +#endif // _PCH_PREMEM_POLICY_COMMON_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchResetPlatformSpecific.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchResetPlatformSpecific.h new file mode 100644 index 0000000000..88884cac25 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/PchResetPlatformSpec +++ ific.h @@ -0,0 +1,21 @@ +/** @file + PCH Reset Platform Specific definitions. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PCH_RESET_PLATFORM_SPECIFIC_H_ #define _PCH_RESET_PLATFORM_SPECIFIC_H_ + +#define PCH_PLATFORM_SPECIFIC_RESET_STRING L"PCH_RESET" +#define PCH_RESET_DATA_STRING_MAX_LENGTH (sizeof (PCH_PLATFORM_SPECIFIC_RESET_STRING) / sizeof (UINT16)) + +extern EFI_GUID gPchGlobalResetGuid; + +typedef struct _RESET_DATA { + CHAR16 Description[PCH_RESET_DATA_STRING_MAX_LENGTH]; + EFI_GUID Guid; +} PCH_RESET_DATA; + +#endif // _PCH_RESET_PLATFORM_SPECIFIC_H_ + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchAcpiSmiDispatch.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchAcpiSmiDispatch.h new file mode 100644 index 0000000000..f22da50262 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchAcpiSmiD +++ ispatch.h @@ -0,0 +1,134 @@ +/** @file + APIs of PCH ACPI SMI Dispatch Protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PCH_ACPI_SMI_DISPATCH_PROTOCOL_H_ +#define _PCH_ACPI_SMI_DISPATCH_PROTOCOL_H_ + +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gPchAcpiSmiDispatchProtocolGuid; + +// +// Forward reference for ANSI C compatibility // +typedef struct _PCH_ACPI_SMI_DISPATCH_PROTOCOL PCH_ACPI_SMI_DISPATCH_PROTOCOL; + +// +// Member functions +// + +/** + Callback function for an PCH ACPI SMI handler dispatch. + + @param[in] DispatchHandle The unique handle assigned to this handler by register function. + +**/ +typedef +VOID +(EFIAPI *PCH_ACPI_SMI_DISPATCH_CALLBACK) ( + IN EFI_HANDLE DispatchHandle + ); + +/** + Register a child SMI source dispatch function for PCH ACPI SMI events. + + @param[in] This Protocol instance pointer. + @param[in] DispatchFunction Pointer to dispatch function to be invoked for + this SMI source + @param[out] DispatchHandle Handle of dispatch function, for when interfacing + with the parent SMM driver. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI source. + @retval EFI_OUT_OF_RESOURCES Not enough memory (system or SMM) to manage this child. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_ACPI_SMI_DISPATCH_REGISTER) ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function with a parent ACPI +SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_ACPI_SMI_DISPATCH_UNREGISTER) ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +/** + Interface structure for PCH ACPI SMIs Dispatch Protocol + The PCH ACPI SMI DISPATCH PROTOCOL provides the ability to dispatch function for PCH ACPI related SMIs. + It contains SMI types of Pme, RtcAlarm, PmeB0, and Time overflow. +**/ +struct _PCH_ACPI_SMI_DISPATCH_PROTOCOL { + /** + This member specifies the revision of this structure. This field is used to + indicate backwards compatible changes to the protocol. + **/ + UINT8 Revision; + /** + Smi unregister function for PCH ACPI SMI DISPATCH PROTOCOL. + **/ + PCH_ACPI_SMI_DISPATCH_UNREGISTER UnRegister; + /** + Pme + The event is triggered by hardware when the PME# signal goes active. + Additionally, the event is only triggered when SCI_EN is not set. + **/ + PCH_ACPI_SMI_DISPATCH_REGISTER PmeRegister; + /** + PmeB0 + The event is triggered PCH when any internal device with PCI Power Management + capabilities on bus 0 asserts the equivalent of the PME# signal. + Additionally, the event is only triggered when SCI_EN is not set. + The following are internal devices which can set this bit: + Intel HD Audio, Intel Management Engine "maskable" wake events, Integrated LAN, + SATA, xHCI, Intel SST + **/ + PCH_ACPI_SMI_DISPATCH_REGISTER PmeB0Register; + /** + RtcAlarm + The event is triggered by hardware when the RTC generates an alarm + (assertion of the IRQ8# signal). + **/ + PCH_ACPI_SMI_DISPATCH_REGISTER RtcAlarmRegister; + /** + TmrOverflow + The event is triggered any time bit 22 of the 24-bit timer goes high + (bits are numbered from 0 to 23). + This will occur every 2.3435 seconds. When the TMROF_EN bit (ABASE + 02h, bit 0) is set, + then the setting of the TMROF_STS bit will additionally generate an SMI# + Additionally, the event is only triggered when SCI_EN is not set. + **/ + PCH_ACPI_SMI_DISPATCH_REGISTER TmrOverflowRegister; +}; + +/** + PCH ACPI SMI dispatch revision number + + Revision 1: Initial version +**/ +#define PCH_ACPI_SMI_DISPATCH_REVISION 1 + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchPcieSmiDispatch.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchPcieSmiDispatch.h new file mode 100644 index 0000000000..0c0f1ab962 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchPcieSmiD +++ ispatch.h @@ -0,0 +1,166 @@ +/** @file + APIs of PCH PCIE SMI Dispatch Protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PCH_PCIE_SMI_DISPATCH_PROTOCOL_H_ +#define _PCH_PCIE_SMI_DISPATCH_PROTOCOL_H_ + +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gPchPcieSmiDispatchProtocolGuid; + +// +// Forward reference for ANSI C compatibility // +typedef struct _PCH_PCIE_SMI_DISPATCH_PROTOCOL PCH_PCIE_SMI_DISPATCH_PROTOCOL; + +typedef enum { + PchRpIndex0 = 0, + PchRpIndex1 = 1, + PchRpIndex2 = 2, + PchRpIndex3 = 3, + PchRpIndex4 = 4, + PchRpIndex5 = 5, + PchRpIndex6 = 6, + PchRpIndex7 = 7, + PchRpIndex8 = 8, + PchRpIndex9 = 9, + PchRpIndex10 = 10, + PchRpIndex11 = 11, + PchRpIndex12 = 12, + PchRpIndex13 = 13, + PchRpIndex14 = 14, + PchRpIndex15 = 15, + PchRpIndex16 = 16, + PchRpIndex17 = 17, + PchRpIndex18 = 18, + PchRpIndex19 = 19, + PchRpIndex20 = 20, + PchRpIndex21 = 21, + PchRpIndex22 = 22, + PchRpIndex23 = 23, + /** + Quantity of PCH and CPU PCIe ports, as well as their encoding in this enum, may change between + silicon generations and series. Do not assume that PCH port 0 will be always encoded by 0. + Instead, it is recommended to use (PchRpIndex0 + PchPortIndex) +style to be forward-compatible + **/ + CpuRpIndex0 = 0x40, + CpuRpIndex1 = 0x41, + CpuRpIndex2 = 0x42, + CpuRpIndex3 = 0x43 +} PCIE_COMBINED_RPINDEX; + +// +// Member functions +// + +typedef struct { + UINT8 RpIndex; ///< Root port index (0-based), 0: RP1, 1: RP2, n: RP(N+1) + UINT8 BusNum; ///< Root port pci bus number + UINT8 DevNum; ///< Root port pci device number + UINT8 FuncNum; ///< Root port pci function number +} PCH_PCIE_SMI_RP_CONTEXT; + +/** + Callback function for an PCH PCIE RP SMI handler dispatch. + + @param[in] DispatchHandle The unique handle assigned to this handler by register function. + @param[in] RpContext Pointer of PCH PCIE Root Port context. + +**/ +typedef +VOID +(EFIAPI *PCH_PCIE_SMI_RP_DISPATCH_CALLBACK) ( + IN EFI_HANDLE DispatchHandle, + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext + ); + +/** + Register a child SMI source dispatch function for PCH PCIERP SMI events. + + @param[in] This Protocol instance pointer. + @param[in] DispatchFunction Pointer to dispatch function to be invoked for + this SMI source + @param[in] RpIndex Refer PCIE_COMBINED_RPINDEX for PCH RP index and CPU RP index. + 0: RP1, 1: RP2, n: RP(N+1) + @param[out] DispatchHandle Handle of dispatch function, for when interfacing + with the parent SMM driver. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI source. + @retval EFI_OUT_OF_RESOURCES Not enough memory (system or SMM) to manage this child. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_PCIE_SMI_RP_DISPATCH_REGISTER) ( + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This, + IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction, + IN UINTN RpIndex, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function with a parent PCIE +SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_PCIE_SMI_DISPATCH_UNREGISTER) ( + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +/** + Interface structure for PCH PCIE SMIs Dispatch Protocol + The PCH PCIE SMI DISPATCH PROTOCOL provides the ability to dispatch function for PCH PCIE related SMIs. + It contains SMI types of HotPlug, LinkActive, and Link EQ. +**/ +struct _PCH_PCIE_SMI_DISPATCH_PROTOCOL { + /** + This member specifies the revision of this structure. This field is used to + indicate backwards compatible changes to the protocol. + **/ + UINT8 Revision; + /** + Smi unregister function for PCH PCIE SMI DISPATCH PROTOCOL. + **/ + PCH_PCIE_SMI_DISPATCH_UNREGISTER UnRegister; + /** + PcieRpXHotPlug + The event is triggered when PCIE root port Hot-Plug Presence Detect. + **/ + PCH_PCIE_SMI_RP_DISPATCH_REGISTER HotPlugRegister; + /** + PcieRpXLinkActive + The event is triggered when Hot-Plug Link Active State Changed. + **/ + PCH_PCIE_SMI_RP_DISPATCH_REGISTER LinkActiveRegister; + /** + PcieRpXLinkEq + The event is triggered when Device Requests Software Link Equalization. + **/ + PCH_PCIE_SMI_RP_DISPATCH_REGISTER LinkEqRegister; +}; + +/** + PCH PCIE SMI dispatch revision number + + Revision 1: Initial version +**/ +#define PCH_PCIE_SMI_DISPATCH_REVISION 1 + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmiDispatch.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmiDispatch.h new file mode 100644 index 0000000000..fd270fe72a --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmiDispa +++ tch.h @@ -0,0 +1,132 @@ +/** @file + APIs of PCH SMI Dispatch Protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PCH_SMI_DISPATCH_PROTOCOL_H_ #define _PCH_SMI_DISPATCH_PROTOCOL_H_ + +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gPchSmiDispatchProtocolGuid; + +// +// Forward reference for ANSI C compatibility // +typedef struct _PCH_SMI_DISPATCH_PROTOCOL PCH_SMI_DISPATCH_PROTOCOL; + +// +// Member functions +// + +/** + Callback function for an PCH SMI handler dispatch. + + @param[in] DispatchHandle The unique handle assigned to this handler by register function. + +**/ +typedef +VOID +(EFIAPI *PCH_SMI_DISPATCH_CALLBACK) ( + IN EFI_HANDLE DispatchHandle + ); + +/** + Register a child SMI source dispatch function for specific PCH SMI dispatch event. + + @param[in] This Protocol instance pointer. + @param[in] DispatchFunction Pointer to dispatch function to be invoked for + this SMI source + @param[out] DispatchHandle Handle of dispatch function, for when interfacing + with the parent SMM driver. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI source. + @retval EFI_OUT_OF_RESOURCES Not enough memory (system or SMM) to manage this child. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_SMI_DISPATCH_REGISTER) ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function with a parent SMM +driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_SMI_DISPATCH_UNREGISTER) ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +/** + Interface structure for PCH specific SMIs Dispatch Protocol + The PCH SMI DISPATCH PROTOCOL provides the ability to dispatch function for PCH misc SMIs. + It contains legacy SMIs and new PCH SMI types like: + SerialIrq, McSmi, Smbus, ... +**/ +struct _PCH_SMI_DISPATCH_PROTOCOL { + /** + This member specifies the revision of this structure. This field is used to + indicate backwards compatible changes to the protocol. + **/ + UINT8 Revision; + /** + Smi unregister function for PCH SMI DISPATCH PROTOCOL. + **/ + PCH_SMI_DISPATCH_UNREGISTER UnRegister; + /** + SerialIrq + The event is triggered while the SMI# was caused by the SERIRQ decoder. + **/ + PCH_SMI_DISPATCH_REGISTER SerialIrqRegister; + /** + McSmi + The event is triggered if there has been an access to the power management + microcontroller range (62h or 66h) and the Microcontroller Decode Enable #1 bit + in the LPC Bridge I/O Enables configuration register is 1 . + **/ + PCH_SMI_DISPATCH_REGISTER McSmiRegister; + /** + SmBus + The event is triggered while the SMI# was caused by: + 1. The SMBus target receiving a message that an SMI# should be caused, or + 2. The SMBALERT# signal goes active and the SMB_SMI_EN bit is set and the + SMBALERT_DIS bit is cleared, or + 3. The SMBus target receiving a Host Notify message and the HOST_NOTIFY_INTREN and + the SMB_SMI_EN bits are set, or + 4. The PCH detecting the SMLINK_SLAVE_SMI command while in the S0 state. + **/ + PCH_SMI_DISPATCH_REGISTER SmbusRegister; + /** + SPI Asynchronous + When registered, the flash controller will generate an SMI when it blocks a BIOS write or erase. + **/ + PCH_SMI_DISPATCH_REGISTER SpiAsyncRegister; +}; + +/** + PCH SMI dispatch revision number + + Revision 1: Initial version +**/ +#define PCH_SMI_DISPATCH_REVISION 1 + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmIoTrapControl.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmIoTrapControl.h new file mode 100644 index 0000000000..87c301901e --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmIoTra +++ pControl.h @@ -0,0 +1,65 @@ +/** @file + PCH SMM IO Trap Control Protocol + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PCH_SMM_IO_TRAP_CONTROL_H_ #define _PCH_SMM_IO_TRAP_CONTROL_H_ + + +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gPchSmmIoTrapControlGuid; + +// +// Forward reference for ANSI C compatibility // typedef struct +_PCH_SMM_IO_TRAP_CONTROL_PROTOCOL PCH_SMM_IO_TRAP_CONTROL_PROTOCOL; + +// +// Related Definitions +// + +// +// Member functions +// + +/** + The Prototype of Pause and Resume IoTrap callback function. + + @param[in] This Pointer to the PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance. + @param[in] DispatchHandle Handle of the child service to change state. + + @retval EFI_SUCCESS This operation is complete. + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. + @retval EFI_ACCESS_DENIED The SMI status is alrady PAUSED/RESUMED. +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_SMM_IO_TRAP_CONTROL_FUNCTION) ( + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL * This, + IN EFI_HANDLE DispatchHandle + ); + +/** + Interface structure for the SMM IO trap pause and resume protocol + This protocol provides the functions to runtime control the IoTrap SMI enabled/disable. + This applys the capability to the DispatchHandle which returned by +IoTrap callback + registration, and the DispatchHandle which must be MergeDisable = TRUE and Address != 0. + Besides, when S3 resuem, it only restores the state of IoTrap callback registration. + The Paused/Resume state won't be restored after S3 resume. +**/ +struct _PCH_SMM_IO_TRAP_CONTROL_PROTOCOL { + /** + This runtime pauses a registered IoTrap handler. + **/ + PCH_SMM_IO_TRAP_CONTROL_FUNCTION Pause; + /** + This runtime resumes a registered IoTrap handler. + **/ + PCH_SMM_IO_TRAP_CONTROL_FUNCTION Resume; +}; + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmPeriodicTimerControl.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmPeriodicTimerControl.h new file mode 100644 index 0000000000..f4773c3dd3 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchSmmPerio +++ dicTimerControl.h @@ -0,0 +1,65 @@ +/** @file + PCH SMM Periodic Timer Control Protocol + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PCH_SMM_PERIODIC_TIMER_CONTROL_H_ +#define _PCH_SMM_PERIODIC_TIMER_CONTROL_H_ + + +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gPchSmmPeriodicTimerControlGuid; + +// +// Forward reference for ANSI C compatibility // +typedef struct _PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL; + +// +// Related Definitions +// + +// +// Member functions +// + +/** + The Prototype of Pause and Resume SMM PERIODIC TIMER function. + + @param[in] This Pointer to the PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL instance. + @param[in] DispatchHandle Handle of the child service to change state. + + @retval EFI_SUCCESS This operation is complete. + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. + @retval EFI_ACCESS_DENIED The SMI status is alrady PAUSED/RESUMED. +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_SMM_PERIODIC_TIMER_CONTROL_FUNCTION) ( + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +/** + Interface structure for the SMM PERIODIC TIMER pause and resume +protocol + This protocol provides the functions to runtime control the SM periodic timer enabled/disable. + This applies the capability to the DispatchHandle which returned by +SMM periodic timer callback + registration. + Besides, when S3 resume, it only restores the state of callback registration. + The Paused/Resume state won't be restored after S3 resume. +**/ +struct _PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL { + /** + This runtime pauses the registered periodic timer handler. + **/ + PCH_SMM_PERIODIC_TIMER_CONTROL_FUNCTION Pause; + /** + This runtime resumes the registered periodic timer handler. + **/ + PCH_SMM_PERIODIC_TIMER_CONTROL_FUNCTION Resume; +}; + +#endif // _PCH_SMM_PERIODIC_TIMER_CONTROL_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchTcoSmiDispatch.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchTcoSmiDispatch.h new file mode 100644 index 0000000000..f39773e420 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/PchTcoSmiDi +++ spatch.h @@ -0,0 +1,150 @@ +/** @file + APIs of PCH TCO SMI Dispatch Protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PCH_TCO_SMI_DISPATCH_PROTOCOL_H_ +#define _PCH_TCO_SMI_DISPATCH_PROTOCOL_H_ + +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gPchTcoSmiDispatchProtocolGuid; + +// +// Forward reference for ANSI C compatibility // +typedef struct _PCH_TCO_SMI_DISPATCH_PROTOCOL PCH_TCO_SMI_DISPATCH_PROTOCOL; + +// +// Member functions +// + +/** + Callback function for an PCH TCO SMI handler dispatch. + + @param[in] DispatchHandle The unique handle assigned to this handler by register function. + +**/ +typedef +VOID +(EFIAPI *PCH_TCO_SMI_DISPATCH_CALLBACK) ( + IN EFI_HANDLE DispatchHandle + ); + +/** + Register a child SMI source dispatch function for PCH TCO SMI events. + + @param[in] This Protocol instance pointer. + @param[in] DispatchFunction Pointer to dispatch function to be invoked for + this SMI source + @param[out] DispatchHandle Handle of dispatch function, for when interfacing + with the parent SMM driver. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI source. + @retval EFI_OUT_OF_RESOURCES Not enough memory (system or SMM) to manage this child. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_TCO_SMI_DISPATCH_REGISTER) ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function with a parent TCO SMM +driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the EndOfDxe event has been triggered +**/ +typedef +EFI_STATUS +(EFIAPI *PCH_TCO_SMI_DISPATCH_UNREGISTER) ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +/** + Interface structure for PCH TCO SMIs Dispatch Protocol + The PCH TCO SMI DISPATCH PROTOCOL provides the ability to dispatch function for PCH TCO related SMIs. + It contains SMI types of Mch, TcoTimeout, OsTco, Nmi, IntruderDectect, and BiowWp. +**/ +struct _PCH_TCO_SMI_DISPATCH_PROTOCOL { + /** + This member specifies the revision of this structure. This field is used to + indicate backwards compatible changes to the protocol. + **/ + UINT8 Revision; + /** + Smi unregister function for PCH TCO SMI DISPATCH PROTOCOL. + **/ + PCH_TCO_SMI_DISPATCH_UNREGISTER UnRegister; + /** + Mch + The event is triggered when PCH received a DMI special cycle message using DMI indicating that + it wants to cause an SMI. + The software must read the processor to determine the reason for the SMI. + **/ + PCH_TCO_SMI_DISPATCH_REGISTER MchRegister; + /** + TcoTimeout + The event is triggered by PCH to indicate that the SMI was caused by the TCO timer reaching 0. + **/ + PCH_TCO_SMI_DISPATCH_REGISTER TcoTimeoutRegister; + /** + OsTco + The event is triggered when software caused an SMI# by writing to the TCO_DAT_IN register (TCOBASE + 02h). + **/ + PCH_TCO_SMI_DISPATCH_REGISTER OsTcoRegister; + /** + Nmi + The event is triggered by the PCH when an SMI# occurs because an event occurred that would otherwise have + caused an NMI (because NMI2SMI_EN is set) + **/ + PCH_TCO_SMI_DISPATCH_REGISTER NmiRegister; + /** + IntruderDectect + The event is triggered by PCH to indicate that an intrusion was detected. + **/ + PCH_TCO_SMI_DISPATCH_REGISTER IntruderDetRegister; + /** + SpiBiosWp + This event is triggered when SMI# was caused by the TCO logic and + SPI flash controller asserted Synchronous SMI by BIOS lock enable set. + **/ + PCH_TCO_SMI_DISPATCH_REGISTER SpiBiosWpRegister; + /** + LpcBiosWp + This event is triggered when SMI# was caused by the TCO logic and + LPC/eSPI BIOS lock enable set. + **/ + PCH_TCO_SMI_DISPATCH_REGISTER LpcBiosWpRegister; + /** + NewCentury + This event is triggered when SMI# was caused by the TCO logic and + year of RTC date rolls over a century (99 to 00). + **/ + PCH_TCO_SMI_DISPATCH_REGISTER NewCenturyRegister; +}; + +/** + PCH TCO SMI dispatch revision number + + Revision 1: Initial version + Revision 2: Add NEWCENTURY support +**/ +#define PCH_TCO_SMI_DISPATCH_REVISION 2 + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/SmmSmbus.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/SmmSmbus.h new file mode 100644 index 0000000000..fa1a79ca84 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Protocol/SmmSmbus.h @@ -0,0 +1,13 @@ +/** @file + SmmSmbus Protocol + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +__EFI_SMM_SMBUS_PROTOCOL_H__ #define __EFI_SMM_SMBUS_PROTOCOL_H__ + +extern EFI_GUID gEfiSmmSmbusProtocolGuid; + +#endif + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Register/PchRegs.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Register/PchRegs.h new file mode 100644 index 0000000000..33b75e82fd --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Include/Register/PchRegs.h @@ -0,0 +1,45 @@ +/** @file + Generic register definitions for PCH. + +Conventions: + + - Register definition format: + + Prefix_[GenerationName]_[ComponentName]_SubsystemName_RegisterSpace_Re + gisterName + - Prefix: + Definitions beginning with "R_" are registers + Definitions beginning with "B_" are bits within registers + Definitions beginning with "V_" are meaningful values within the bits + Definitions beginning with "S_" are register size + Definitions beginning with "N_" are the bit position + - [GenerationName]: + Three letter acronym of the generation is used (e.g. SKL,KBL,CNL etc.). + Register name without GenerationName applies to all generations. + - [ComponentName]: + This field indicates the component name that the register belongs to (e.g. PCH, SA etc.) + Register name without ComponentName applies to all components. + Register that is specific to -H denoted by "_PCH_H_" in component name. + Register that is specific to -LP denoted by "_PCH_LP_" in component name. + - SubsystemName: + This field indicates the subsystem name of the component that the register belongs to + (e.g. PCIE, USB, SATA, GPIO, PMC etc.). + - RegisterSpace: + MEM - MMIO space register of subsystem. + IO - IO space register of subsystem. + PCR - Private configuration register of subsystem. + CFG - PCI configuration space register of subsystem. + - RegisterName: + Full register name. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PCH_REGS_H_ #define _PCH_REGS_H_ + +/// +/// The default PCH PCI segment and bus number /// #define +DEFAULT_PCI_SEGMENT_NUMBER_PCH 0 +#define DEFAULT_PCI_BUS_NUMBER_PCH 0 + +#endif //_PCH_REGS_H_ -- 2.36.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107780): https://edk2.groups.io/g/devel/message/107780 Mute This Topic: https://groups.io/mt/100551002/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [edk2-devel] [PATCH v2 4/7] AlderlakeSiliconPkg/Pch: Add libraries 2023-08-04 17:37 [edk2-devel] [PATCH v2 1/7] AlderlakeSiliconPkg: Add package and library instances Saloni Kasbekar 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 2/7] AlderlakeSiliconPkg: Add Cpu modules Saloni Kasbekar 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 3/7] AlderlakeSiliconPkg/Pch: Add include headers Saloni Kasbekar @ 2023-08-04 17:37 ` Saloni Kasbekar 2023-08-16 2:42 ` Chuang, Rosen 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 5/7] AlderlakeSiliconPkg/Pch: Add drivers Saloni Kasbekar ` (3 subsequent siblings) 6 siblings, 1 reply; 14+ messages in thread From: Saloni Kasbekar @ 2023-08-04 17:37 UTC (permalink / raw) To: devel Cc: Saloni Kasbekar, Sai Chaganty, Nate DeSimone, Isaac Oram, Rosen Chuang Adds the following libraries: - BasePchPciBdfLib - BaseResetSystemLib - PeiDxeSmmPchCycleDecodingLib Cc: Sai Chaganty <rangasai.v.chaganty@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Isaac Oram <isaac.w.oram@intel.com> Cc: Rosen Chuang <rosen.chuang@intel.com> Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com> --- .../BasePchPciBdfLib/BasePchPciBdfLib.inf | 32 ++ .../Library/BasePchPciBdfLib/PchPciBdfLib.c | 308 ++++++++++++++++++ .../BaseResetSystemLib/BaseResetSystemLib.c | 114 +++++++ .../BaseResetSystemLib/BaseResetSystemLib.inf | 37 +++ .../PchCycleDecodingLib.c | 194 +++++++++++ .../PeiDxeSmmPchCycleDecodingLib.inf | 41 +++ 6 files changed, 726 insertions(+) create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/BasePchPciBdfLib.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/PchPciBdfLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/BaseResetSystemLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/BaseResetSystemLib.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PeiDxeSmmPchCycleDecodingLib.inf diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/BasePchPciBdfLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/BasePchPciBdfLib.inf new file mode 100644 index 0000000000..e65f564c1b --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/BasePchPciBdfLib.inf @@ -0,0 +1,32 @@ +## @file +# PCH PCIe Bus Device Function Library. +# +# All functions from this library are available in PEI, DXE, and SMM, +# But do not support UEFI RUNTIME environment call. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = PeiDxeSmmPchPciBdfLib +FILE_GUID = A36363FC-2951-4DCF-AC81-16F4ED3FDA47 +VERSION_STRING = 1.0 +MODULE_TYPE = BASE +LIBRARY_CLASS = PchPciBdfLib + +[LibraryClasses] +BaseLib +IoLib +DebugLib +PciSegmentLib +PchInfoLib +PchPcieRpLib + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + +[Sources] +PchPciBdfLib.c diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/PchPciBdfLib.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/PchPciBdfLib.c new file mode 100644 index 0000000000..c26625e2eb --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/PchPciBdfLib.c @@ -0,0 +1,308 @@ +/** @file + PCH PCIe Bus Device Function Library. + All functions from this library are available in PEI, DXE, and SMM, + But do not support UEFI RUNTIME environment call. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Base.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/PciSegmentLib.h> +#include <Library/PchInfoLib.h> +#include <Library/PchPcieRpLib.h> +#include <Register/PchRegs.h> +#include <PchBdfAssignment.h> + +/** + Check if a Device is present for PCH FRU + If the data is defined for PCH RFU return it + If the data is not defined (Device is NOT present) assert. + + @param[in] DataToCheck Device or Function number to check + + @retval Device or Function number value if defined for PCH FRU + 0xFF if not present in PCH FRU +**/ +UINT8 +CheckAndReturn ( + UINT8 DataToCheck + ) +{ + if (DataToCheck == NOT_PRESENT) { + ASSERT (FALSE); + } + return DataToCheck; +} + +/** + Get P2SB PCI device number + + @retval PCI dev number +**/ +UINT8 +P2sbDevNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_P2SB); +} + +/** + Get P2SB PCI function number + + @retval PCI fun number +**/ +UINT8 +P2sbFuncNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_FUNCTION_NUMBER_PCH_P2SB); +} + +/** + Get P2SB controller address that can be passed to the PCI Segment Library functions. + + @retval P2SB controller address in PCI Segment Library representation +**/ +UINT64 +P2sbPciCfgBase ( + VOID + ) +{ + return PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + P2sbDevNumber (), + P2sbFuncNumber (), + 0 + ); +} + + + +/** + Returns PCH SPI Device number + + @retval UINT8 PCH SPI Device number +**/ +UINT8 +SpiDevNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_SPI); +} + +/** + Returns PCH SPI Function number + + @retval UINT8 PCH SPI Function number +**/ +UINT8 +SpiFuncNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_FUNCTION_NUMBER_PCH_SPI); +} + +/** + Returns PCH SPI PCI Config Space base address + + @retval UINT64 PCH SPI Config Space base address +**/ +UINT64 +SpiPciCfgBase ( + VOID + ) +{ + return PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + SpiDevNumber (), + SpiFuncNumber (), + 0 + ); +} + +/** + Get XHCI controller PCIe Device Number + + @retval XHCI controller PCIe Device Number +**/ +UINT8 +PchXhciDevNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_XHCI); +} + +/** + Get XHCI controller PCIe Function Number + + @retval XHCI controller PCIe Function Number +**/ +UINT8 +PchXhciFuncNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_FUNCTION_NUMBER_PCH_XHCI); +} + +/** + Get LPC controller PCIe Device Number + + @retval LPC controller PCIe Device Number +**/ +UINT8 +LpcDevNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_LPC); +} + +/** + Get LPC controller PCIe Function Number + + @retval LPC controller PCIe Function Number +**/ +UINT8 +LpcFuncNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_FUNCTION_NUMBER_PCH_LPC); +} + +/** + Returns PCH LPC device PCI base address. + + @retval PCH LPC PCI base address. +**/ +UINT64 +LpcPciCfgBase ( + VOID + ) +{ + return PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + LpcDevNumber (), + LpcFuncNumber (), + 0 + ); +} + + + +/** + Get PCH PCIe controller PCIe Device Number + + @param[in] RpIndex Root port physical number. (0-based) + + @retval PCH PCIe controller PCIe Device Number +**/ +UINT8 +PchPcieRpDevNumber ( + IN UINTN RpIndex + ) +{ + switch (RpIndex) { + case 0: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_1); + case 1: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_2); + case 2: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_3); + case 3: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_4); + case 4: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_5); + case 5: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_6); + case 6: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_7); + case 7: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_8); + case 8: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_9); + case 9: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_10); + case 10: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_11); + case 11: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_12); + case 12: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_13); + case 13: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_14); + case 14: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_15); + case 15: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_16); + case 16: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_17); + case 17: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_18); + case 18: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_19); + case 19: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_20); + case 20: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_21); + case 21: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_22); + case 22: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_23); + case 23: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_24); + case 24: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_25); + case 25: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_26); + case 26: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_27); + case 27: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_28); + + default: + ASSERT (FALSE); + return 0xFF; + } +} + +/** + Get PCH PCIe controller PCIe Function Number + Note: + For Client PCH generations Function Number can be various + depending on "Root Port Function Swapping". For such cases + Function Number MUST be obtain from proper register. + For Server PCHs we have no "Root Port Function Swapping" + and we can return fixed Function Number. + To address this difference in this, PCH generation independent, + library we should call specific function in PchPcieRpLib. + + @param[in] RpIndex Root port physical number. (0-based) + + @retval PCH PCIe controller PCIe Function Number +**/ +UINT8 +PchPcieRpFuncNumber ( + IN UINTN RpIndex + ) +{ + UINTN Device; + UINTN Function; + + GetPchPcieRpDevFun (RpIndex, &Device, &Function); + + return (UINT8)Function; +} + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/BaseResetSystemLib.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/BaseResetSystemLib.c new file mode 100644 index 0000000000..86eeff9407 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/BaseResetSystemLib.c @@ -0,0 +1,114 @@ +/** @file + System reset library services. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <Uefi.h> +#include <Library/IoLib.h> +#include <Library/DebugLib.h> +#include <Library/ResetSystemLib.h> +#include <Library/PmcLib.h> +#include <Library/BaseLib.h> +#include <Register/PchRegsLpc.h> +#include <Register/PmcRegs.h> + +/** + Calling this function causes a system-wide reset. This sets + all circuitry within the system to its initial state. This type of reset + is asynchronous to system operation and operates without regard to + cycle boundaries. + + System reset should not return, if it returns, it means the system does + not support cold reset. +**/ +VOID +EFIAPI +ResetCold ( + VOID + ) +{ + IoWrite8 (R_PCH_IO_RST_CNT, V_PCH_IO_RST_CNT_FULLRESET); +} + +/** + Calling this function causes a system-wide initialization. The processors + are set to their initial state, and pending cycles are not corrupted. + + System reset should not return, if it returns, it means the system does + not support warm reset. +**/ +VOID +EFIAPI +ResetWarm ( + VOID + ) +{ + IoWrite8 (R_PCH_IO_RST_CNT, V_PCH_IO_RST_CNT_HARDRESET); +} + +/** + Calling this function causes the system to enter a power state equivalent + to the ACPI G2/S5 or G3 states. + + System shutdown should not return, if it returns, it means the system does + not support shut down reset. +**/ +VOID +EFIAPI +ResetShutdown ( + VOID + ) +{ + UINT16 ABase; + UINT32 Data32; + + ABase = PmcGetAcpiBase (); + + /// + /// Firstly, GPE0_EN should be disabled to avoid any GPI waking up the system from S5 + /// + IoWrite32 (ABase + R_ACPI_IO_GPE0_EN_127_96, 0); + + /// + /// Secondly, PwrSts register must be cleared + /// + /// Write a "1" to bit[8] of power button status register at + /// (PM_BASE + PM1_STS_OFFSET) to clear this bit + /// + IoWrite16 (ABase + R_ACPI_IO_PM1_STS, B_ACPI_IO_PM1_STS_PWRBTN); + + /// + /// Finally, transform system into S5 sleep state + /// + Data32 = IoRead32 (ABase + R_ACPI_IO_PM1_CNT); + + Data32 = (UINT32) ((Data32 &~(B_ACPI_IO_PM1_CNT_SLP_TYP + B_ACPI_IO_PM1_CNT_SLP_EN)) | V_ACPI_IO_PM1_CNT_S5); + + IoWrite32 (ABase + R_ACPI_IO_PM1_CNT, Data32); + + Data32 = Data32 | B_ACPI_IO_PM1_CNT_SLP_EN; + + IoWrite32 (ABase + R_ACPI_IO_PM1_CNT, Data32); + + return; +} + +/** + Calling this function causes the system to enter a power state for platform specific. + + @param[in] DataSize The size of ResetData in bytes. + @param[in] ResetData Optional element used to introduce a platform specific reset. + The exact type of the reset is defined by the EFI_GUID that follows + the Null-terminated Unicode string. + +**/ +VOID +EFIAPI +ResetPlatformSpecific ( + IN UINTN DataSize, + IN VOID *ResetData OPTIONAL + ) +{ + IoWrite8 (R_PCH_IO_RST_CNT, V_PCH_IO_RST_CNT_FULLRESET); +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/BaseResetSystemLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/BaseResetSystemLib.inf new file mode 100644 index 0000000000..f0a987d671 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/BaseResetSystemLib.inf @@ -0,0 +1,37 @@ +## @file +# Component description file for Intel Ich7 Reset System Library. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = BaseResetSystemLib +FILE_GUID = D4FF05AA-3C7D-4B8A-A1EE-AA5EFA0B1732 +VERSION_STRING = 1.0 +MODULE_TYPE = BASE +UEFI_SPECIFICATION_VERSION = 2.00 +LIBRARY_CLASS = ResetSystemLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF +# + +[LibraryClasses] +IoLib +BaseLib +DebugLib +PmcLib + + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + + +[Sources] +BaseResetSystemLib.c + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c new file mode 100644 index 0000000000..ccdac7c5ab --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c @@ -0,0 +1,194 @@ +/** @file + PCH cycle decoding configuration and query library. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <Base.h> +#include <Uefi/UefiBaseType.h> +#include <Library/IoLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseLib.h> +#include <Library/PciSegmentLib.h> +#include <Library/PchInfoLib.h> +#include <Library/PchPcrLib.h> +#include <Library/PchCycleDecodingLib.h> +#include <Library/PchDmiLib.h> +#include <Library/BaseMemoryLib.h> +#include <Register/PchRegs.h> +#include <Register/PchRegsLpc.h> +#include <Register/SpiRegs.h> +#include <Library/EspiLib.h> +#include <Library/PchPciBdfLib.h> + +typedef enum { + SlaveLpcEspiCS0, + SlaveEspiCS1, + SlaveId_Max +} SLAVE_ID_INDEX; + +/** + Get PCH TCO base address. + + @param[out] Address Address of TCO base address. + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_INVALID_PARAMETER Invalid pointer passed. +**/ +EFI_STATUS +PchTcoBaseGet ( + OUT UINT16 *Address + ) +{ + if (Address == NULL) { + DEBUG ((DEBUG_ERROR, "PchTcoBaseGet Error. Invalid pointer.\n")); + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + // + // Read "TCO Base Address" from DMI + // Don't read TCO base address from SMBUS PCI register since SMBUS might be disabled. + // + *Address = PchDmiGetTcoBase (); + + return EFI_SUCCESS; +} + +/** + Set PCH LPC/eSPI IO decode ranges. + Program LPC/eSPI I/O Decode Ranges in DMI to the same value programmed in LPC/eSPI PCI offset 80h. + Please check EDS for detail of LPC/eSPI IO decode ranges bit definition. + Bit 12: FDD range + Bit 9:8: LPT range + Bit 6:4: ComB range + Bit 2:0: ComA range + + @param[in] LpcIoDecodeRanges LPC/eSPI IO decode ranges bit settings. + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_UNSUPPORTED DMIC.SRL is set. +**/ +EFI_STATUS +PchLpcIoDecodeRangesSet ( + IN UINT16 LpcIoDecodeRanges + ) +{ + UINT64 LpcBaseAddr; + EFI_STATUS Status; + + // + // Note: Inside this function, don't use debug print since it's could used before debug print ready. + // + + LpcBaseAddr = LpcPciCfgBase (); + + // + // check if setting is identical + // + if (LpcIoDecodeRanges == PciSegmentRead16 (LpcBaseAddr + R_LPC_CFG_IOD)) { + return EFI_SUCCESS; + } + + Status = PchDmiSetLpcIoDecodeRanges (LpcIoDecodeRanges); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // + // program LPC/eSPI PCI offset 80h. + // + PciSegmentWrite16 (LpcBaseAddr + R_LPC_CFG_IOD, LpcIoDecodeRanges); + + return Status; +} + +/** + Set PCH LPC/eSPI and eSPI CS1# IO enable decoding. + Setup I/O Enables in DMI to the same value program in LPC/eSPI PCI offset 82h (LPC, eSPI CS0#) or A0h (eSPI CS1#). + Note: Bit[15:10] of the source decode register is Read-Only. The IO range indicated by the Enables field + in LPC/eSPI PCI offset 82h[13:10] or A0h[13:10] is always forwarded by DMI to subtractive agent for handling. + Please check EDS for detail of Lpc/eSPI IO decode ranges bit definition. + + @param[in] IoEnableDecoding LPC/eSPI IO enable decoding bit settings. + @param[in] SlaveId Target ID (refer to SLAVE_ID_INDEX) + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_UNSUPPORTED DMI configuration is locked +**/ +EFI_STATUS +LpcEspiIoEnableDecodingSetHelper ( + IN UINT16 IoEnableDecoding, + IN SLAVE_ID_INDEX SlaveId + ) +{ + UINT64 LpcBaseAddr; + EFI_STATUS Status; + UINT16 Cs1IoEnableDecodingOrg; + UINT16 Cs0IoEnableDecodingOrg; + UINT16 IoEnableDecodingMerged; + + LpcBaseAddr = LpcPciCfgBase (); + + Cs0IoEnableDecodingOrg = PciSegmentRead16 (LpcBaseAddr + R_LPC_CFG_IOE); + + if (IsEspiSecondSlaveSupported ()) { + Cs1IoEnableDecodingOrg = PciSegmentRead16 (LpcBaseAddr + R_ESPI_CFG_CS1IORE); + } else { + Cs1IoEnableDecodingOrg = 0; + } + + if (SlaveId == SlaveEspiCS1) { + if (IoEnableDecoding == Cs1IoEnableDecodingOrg) { + return EFI_SUCCESS; + } else { + IoEnableDecodingMerged = (Cs0IoEnableDecodingOrg | IoEnableDecoding); + } + } else { + if ((IoEnableDecoding | Cs1IoEnableDecodingOrg) == Cs0IoEnableDecodingOrg) { + return EFI_SUCCESS; + } else { + IoEnableDecodingMerged = (Cs1IoEnableDecodingOrg | IoEnableDecoding); + } + } + + Status = PchDmiSetLpcIoEnable (IoEnableDecodingMerged); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // + // program PCI offset 82h for LPC/eSPI. + // + PciSegmentWrite16 (LpcBaseAddr + R_LPC_CFG_IOE, IoEnableDecodingMerged); + + if (SlaveId == SlaveEspiCS1) { + // + // For eSPI CS1# device program eSPI PCI offset A0h. + // + PciSegmentWrite16 (LpcBaseAddr + R_ESPI_CFG_CS1IORE, IoEnableDecoding); + } + + return Status; +} + +/** + Set PCH LPC and eSPI CS0# IO enable decoding. + Setup I/O Enables in DMI to the same value program in LPC/eSPI PCI offset 82h. + Note: Bit[15:10] of the source decode register is Read-Only. The IO range indicated by the Enables field + in LPC/eSPI PCI offset 82h[13:10] is always forwarded by DMI to subtractive agent for handling. + Please check EDS for detail of LPC/eSPI IO decode ranges bit definition. + + @param[in] LpcIoEnableDecoding LPC IO enable decoding bit settings. + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_UNSUPPORTED DMIC.SRL is set. +**/ +EFI_STATUS +PchLpcIoEnableDecodingSet ( + IN UINT16 LpcIoEnableDecoding + ) +{ + return LpcEspiIoEnableDecodingSetHelper (LpcIoEnableDecoding, SlaveLpcEspiCS0); +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PeiDxeSmmPchCycleDecodingLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PeiDxeSmmPchCycleDecodingLib.inf new file mode 100644 index 0000000000..a381c0f0f7 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PeiDxeSmmPchCycleDecodingLib.inf @@ -0,0 +1,41 @@ +## @file +# PCH cycle decoding Lib. +# +# All function in this library is available for PEI, DXE, and SMM, +# But do not support UEFI RUNTIME environment call. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = PeiDxeSmmPchCycleDecodingLib +FILE_GUID = 676C749F-9CD1-46B7-BAFD-4B1BC36B4C8E +VERSION_STRING = 1.0 +MODULE_TYPE = BASE +LIBRARY_CLASS = PchCycleDecodingLib + + +[LibraryClasses] +BaseLib +IoLib +DebugLib +PciSegmentLib +PchInfoLib +PchPcrLib +PchDmiLib +EspiLib +PchPciBdfLib + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + +[Sources] +PchCycleDecodingLib.c + +[Pcd] +gSiPkgTokenSpaceGuid.PcdSiHpetBaseAddress ## CONSUMES +gSiPkgTokenSpaceGuid.PcdSiIoApicBaseAddress ## CONSUMES -- 2.36.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107571): https://edk2.groups.io/g/devel/message/107571 Mute This Topic: https://groups.io/mt/100551003/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [edk2-devel] [PATCH v2 4/7] AlderlakeSiliconPkg/Pch: Add libraries 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 4/7] AlderlakeSiliconPkg/Pch: Add libraries Saloni Kasbekar @ 2023-08-16 2:42 ` Chuang, Rosen 0 siblings, 0 replies; 14+ messages in thread From: Chuang, Rosen @ 2023-08-16 2:42 UTC (permalink / raw) To: Kasbekar, Saloni, devel@edk2.groups.io Cc: Chaganty, Rangasai V, Desimone, Nathaniel L, Oram, Isaac W Reviewed-by: Rosen Chuang < rosen.chuang@intel.com> Thanks, Rosen -----Original Message----- From: Kasbekar, Saloni <saloni.kasbekar@intel.com> Sent: Saturday, August 5, 2023 1:38 AM To: devel@edk2.groups.io Cc: Kasbekar, Saloni <saloni.kasbekar@intel.com>; Chaganty, Rangasai V <rangasai.v.chaganty@intel.com>; Desimone, Nathaniel L <nathaniel.l.desimone@intel.com>; Oram, Isaac W <isaac.w.oram@intel.com>; Chuang, Rosen <rosen.chuang@intel.com> Subject: [PATCH v2 4/7] AlderlakeSiliconPkg/Pch: Add libraries Adds the following libraries: - BasePchPciBdfLib - BaseResetSystemLib - PeiDxeSmmPchCycleDecodingLib Cc: Sai Chaganty <rangasai.v.chaganty@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Isaac Oram <isaac.w.oram@intel.com> Cc: Rosen Chuang <rosen.chuang@intel.com> Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com> --- .../BasePchPciBdfLib/BasePchPciBdfLib.inf | 32 ++ .../Library/BasePchPciBdfLib/PchPciBdfLib.c | 308 ++++++++++++++++++ .../BaseResetSystemLib/BaseResetSystemLib.c | 114 +++++++ .../BaseResetSystemLib/BaseResetSystemLib.inf | 37 +++ .../PchCycleDecodingLib.c | 194 +++++++++++ .../PeiDxeSmmPchCycleDecodingLib.inf | 41 +++ 6 files changed, 726 insertions(+) create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/BasePchPciBdfLib.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/PchPciBdfLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/BaseResetSystemLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/BaseResetSystemLib.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PeiDxeSmmPchCycleDecodingLib.inf diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/BasePchPciBdfLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/BasePchPciBdfLib.inf new file mode 100644 index 0000000000..e65f564c1b --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/Bas +++ ePchPciBdfLib.inf @@ -0,0 +1,32 @@ +## @file +# PCH PCIe Bus Device Function Library. +# +# All functions from this library are available in PEI, DXE, and SMM, # +But do not support UEFI RUNTIME environment call. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = PeiDxeSmmPchPciBdfLib +FILE_GUID = A36363FC-2951-4DCF-AC81-16F4ED3FDA47 +VERSION_STRING = 1.0 +MODULE_TYPE = BASE +LIBRARY_CLASS = PchPciBdfLib + +[LibraryClasses] +BaseLib +IoLib +DebugLib +PciSegmentLib +PchInfoLib +PchPcieRpLib + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + +[Sources] +PchPciBdfLib.c diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/PchPciBdfLib.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/PchPciBdfLib.c new file mode 100644 index 0000000000..c26625e2eb --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BasePchPciBdfLib/Pch +++ PciBdfLib.c @@ -0,0 +1,308 @@ +/** @file + PCH PCIe Bus Device Function Library. + All functions from this library are available in PEI, DXE, and SMM, + But do not support UEFI RUNTIME environment call. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ + +#include <Base.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/PciSegmentLib.h> +#include <Library/PchInfoLib.h> +#include <Library/PchPcieRpLib.h> +#include <Register/PchRegs.h> +#include <PchBdfAssignment.h> + +/** + Check if a Device is present for PCH FRU + If the data is defined for PCH RFU return it + If the data is not defined (Device is NOT present) assert. + + @param[in] DataToCheck Device or Function number to check + + @retval Device or Function number value if defined for PCH FRU + 0xFF if not present in PCH FRU **/ +UINT8 +CheckAndReturn ( + UINT8 DataToCheck + ) +{ + if (DataToCheck == NOT_PRESENT) { + ASSERT (FALSE); + } + return DataToCheck; +} + +/** + Get P2SB PCI device number + + @retval PCI dev number +**/ +UINT8 +P2sbDevNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_P2SB); } + +/** + Get P2SB PCI function number + + @retval PCI fun number +**/ +UINT8 +P2sbFuncNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_FUNCTION_NUMBER_PCH_P2SB); } + +/** + Get P2SB controller address that can be passed to the PCI Segment Library functions. + + @retval P2SB controller address in PCI Segment Library representation +**/ +UINT64 +P2sbPciCfgBase ( + VOID + ) +{ + return PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + P2sbDevNumber (), + P2sbFuncNumber (), + 0 + ); +} + + + +/** + Returns PCH SPI Device number + + @retval UINT8 PCH SPI Device number +**/ +UINT8 +SpiDevNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_SPI); } + +/** + Returns PCH SPI Function number + + @retval UINT8 PCH SPI Function number +**/ +UINT8 +SpiFuncNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_FUNCTION_NUMBER_PCH_SPI); } + +/** + Returns PCH SPI PCI Config Space base address + + @retval UINT64 PCH SPI Config Space base address **/ +UINT64 +SpiPciCfgBase ( + VOID + ) +{ + return PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + SpiDevNumber (), + SpiFuncNumber (), + 0 + ); +} + +/** + Get XHCI controller PCIe Device Number + + @retval XHCI controller PCIe Device Number **/ +UINT8 +PchXhciDevNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_XHCI); } + +/** + Get XHCI controller PCIe Function Number + + @retval XHCI controller PCIe Function Number **/ +UINT8 +PchXhciFuncNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_FUNCTION_NUMBER_PCH_XHCI); } + +/** + Get LPC controller PCIe Device Number + + @retval LPC controller PCIe Device Number **/ +UINT8 +LpcDevNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_LPC); } + +/** + Get LPC controller PCIe Function Number + + @retval LPC controller PCIe Function Number **/ +UINT8 +LpcFuncNumber ( + VOID + ) +{ + return CheckAndReturn (PCI_FUNCTION_NUMBER_PCH_LPC); } + +/** + Returns PCH LPC device PCI base address. + + @retval PCH LPC PCI base address. +**/ +UINT64 +LpcPciCfgBase ( + VOID + ) +{ + return PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + LpcDevNumber (), + LpcFuncNumber (), + 0 + ); +} + + + +/** + Get PCH PCIe controller PCIe Device Number + + @param[in] RpIndex Root port physical number. (0-based) + + @retval PCH PCIe controller PCIe Device Number **/ +UINT8 +PchPcieRpDevNumber ( + IN UINTN RpIndex + ) +{ + switch (RpIndex) { + case 0: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_1); + case 1: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_2); + case 2: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_3); + case 3: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_4); + case 4: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_5); + case 5: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_6); + case 6: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_7); + case 7: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_8); + case 8: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_9); + case 9: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_10); + case 10: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_11); + case 11: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_12); + case 12: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_13); + case 13: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_14); + case 14: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_15); + case 15: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_16); + case 16: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_17); + case 17: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_18); + case 18: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_19); + case 19: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_20); + case 20: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_21); + case 21: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_22); + case 22: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_23); + case 23: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_24); + case 24: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_25); + case 25: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_26); + case 26: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_27); + case 27: + return CheckAndReturn (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_28); + + default: + ASSERT (FALSE); + return 0xFF; + } +} + +/** + Get PCH PCIe controller PCIe Function Number + Note: + For Client PCH generations Function Number can be various + depending on "Root Port Function Swapping". For such cases + Function Number MUST be obtain from proper register. + For Server PCHs we have no "Root Port Function Swapping" + and we can return fixed Function Number. + To address this difference in this, PCH generation independent, + library we should call specific function in PchPcieRpLib. + + @param[in] RpIndex Root port physical number. (0-based) + + @retval PCH PCIe controller PCIe Function Number **/ +UINT8 +PchPcieRpFuncNumber ( + IN UINTN RpIndex + ) +{ + UINTN Device; + UINTN Function; + + GetPchPcieRpDevFun (RpIndex, &Device, &Function); + + return (UINT8)Function; +} + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/BaseResetSystemLib.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/BaseResetSystemLib.c new file mode 100644 index 0000000000..86eeff9407 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/B +++ aseResetSystemLib.c @@ -0,0 +1,114 @@ +/** @file + System reset library services. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include <Uefi.h> +#include <Library/IoLib.h> #include <Library/DebugLib.h> #include +<Library/ResetSystemLib.h> #include <Library/PmcLib.h> #include +<Library/BaseLib.h> #include <Register/PchRegsLpc.h> #include +<Register/PmcRegs.h> + +/** + Calling this function causes a system-wide reset. This sets + all circuitry within the system to its initial state. This type of +reset + is asynchronous to system operation and operates without regard to + cycle boundaries. + + System reset should not return, if it returns, it means the system +does + not support cold reset. +**/ +VOID +EFIAPI +ResetCold ( + VOID + ) +{ + IoWrite8 (R_PCH_IO_RST_CNT, V_PCH_IO_RST_CNT_FULLRESET); } + +/** + Calling this function causes a system-wide initialization. The +processors + are set to their initial state, and pending cycles are not corrupted. + + System reset should not return, if it returns, it means the system +does + not support warm reset. +**/ +VOID +EFIAPI +ResetWarm ( + VOID + ) +{ + IoWrite8 (R_PCH_IO_RST_CNT, V_PCH_IO_RST_CNT_HARDRESET); } + +/** + Calling this function causes the system to enter a power state +equivalent + to the ACPI G2/S5 or G3 states. + + System shutdown should not return, if it returns, it means the system +does + not support shut down reset. +**/ +VOID +EFIAPI +ResetShutdown ( + VOID + ) +{ + UINT16 ABase; + UINT32 Data32; + + ABase = PmcGetAcpiBase (); + + /// + /// Firstly, GPE0_EN should be disabled to avoid any GPI waking up + the system from S5 /// + IoWrite32 (ABase + R_ACPI_IO_GPE0_EN_127_96, 0); + + /// + /// Secondly, PwrSts register must be cleared /// /// Write a "1" + to bit[8] of power button status register at /// (PM_BASE + + PM1_STS_OFFSET) to clear this bit /// + IoWrite16 (ABase + R_ACPI_IO_PM1_STS, B_ACPI_IO_PM1_STS_PWRBTN); + + /// + /// Finally, transform system into S5 sleep state /// + Data32 = IoRead32 (ABase + R_ACPI_IO_PM1_CNT); + + Data32 = (UINT32) ((Data32 &~(B_ACPI_IO_PM1_CNT_SLP_TYP + + B_ACPI_IO_PM1_CNT_SLP_EN)) | V_ACPI_IO_PM1_CNT_S5); + + IoWrite32 (ABase + R_ACPI_IO_PM1_CNT, Data32); + + Data32 = Data32 | B_ACPI_IO_PM1_CNT_SLP_EN; + + IoWrite32 (ABase + R_ACPI_IO_PM1_CNT, Data32); + + return; +} + +/** + Calling this function causes the system to enter a power state for platform specific. + + @param[in] DataSize The size of ResetData in bytes. + @param[in] ResetData Optional element used to introduce a platform specific reset. + The exact type of the reset is defined by the EFI_GUID that follows + the Null-terminated Unicode string. + +**/ +VOID +EFIAPI +ResetPlatformSpecific ( + IN UINTN DataSize, + IN VOID *ResetData OPTIONAL + ) +{ + IoWrite8 (R_PCH_IO_RST_CNT, V_PCH_IO_RST_CNT_FULLRESET); } diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/BaseResetSystemLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/BaseResetSystemLib.inf new file mode 100644 index 0000000000..f0a987d671 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/BaseResetSystemLib/B +++ aseResetSystemLib.inf @@ -0,0 +1,37 @@ +## @file +# Component description file for Intel Ich7 Reset System Library. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = BaseResetSystemLib +FILE_GUID = D4FF05AA-3C7D-4B8A-A1EE-AA5EFA0B1732 +VERSION_STRING = 1.0 +MODULE_TYPE = BASE +UEFI_SPECIFICATION_VERSION = 2.00 +LIBRARY_CLASS = ResetSystemLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF +# + +[LibraryClasses] +IoLib +BaseLib +DebugLib +PmcLib + + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + + +[Sources] +BaseResetSystemLib.c + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c new file mode 100644 index 0000000000..ccdac7c5ab --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDec +++ odingLib/PchCycleDecodingLib.c @@ -0,0 +1,194 @@ +/** @file + PCH cycle decoding configuration and query library. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include <Base.h> +#include <Uefi/UefiBaseType.h> #include <Library/IoLib.h> #include +<Library/DebugLib.h> #include <Library/BaseLib.h> #include +<Library/PciSegmentLib.h> #include <Library/PchInfoLib.h> #include +<Library/PchPcrLib.h> #include <Library/PchCycleDecodingLib.h> #include +<Library/PchDmiLib.h> #include <Library/BaseMemoryLib.h> #include +<Register/PchRegs.h> #include <Register/PchRegsLpc.h> #include +<Register/SpiRegs.h> #include <Library/EspiLib.h> #include +<Library/PchPciBdfLib.h> + +typedef enum { + SlaveLpcEspiCS0, + SlaveEspiCS1, + SlaveId_Max +} SLAVE_ID_INDEX; + +/** + Get PCH TCO base address. + + @param[out] Address Address of TCO base address. + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_INVALID_PARAMETER Invalid pointer passed. +**/ +EFI_STATUS +PchTcoBaseGet ( + OUT UINT16 *Address + ) +{ + if (Address == NULL) { + DEBUG ((DEBUG_ERROR, "PchTcoBaseGet Error. Invalid pointer.\n")); + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + // + // Read "TCO Base Address" from DMI + // Don't read TCO base address from SMBUS PCI register since SMBUS might be disabled. + // + *Address = PchDmiGetTcoBase (); + + return EFI_SUCCESS; +} + +/** + Set PCH LPC/eSPI IO decode ranges. + Program LPC/eSPI I/O Decode Ranges in DMI to the same value programmed in LPC/eSPI PCI offset 80h. + Please check EDS for detail of LPC/eSPI IO decode ranges bit definition. + Bit 12: FDD range + Bit 9:8: LPT range + Bit 6:4: ComB range + Bit 2:0: ComA range + + @param[in] LpcIoDecodeRanges LPC/eSPI IO decode ranges bit settings. + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_UNSUPPORTED DMIC.SRL is set. +**/ +EFI_STATUS +PchLpcIoDecodeRangesSet ( + IN UINT16 LpcIoDecodeRanges + ) +{ + UINT64 LpcBaseAddr; + EFI_STATUS Status; + + // + // Note: Inside this function, don't use debug print since it's could used before debug print ready. + // + + LpcBaseAddr = LpcPciCfgBase (); + + // + // check if setting is identical + // + if (LpcIoDecodeRanges == PciSegmentRead16 (LpcBaseAddr + R_LPC_CFG_IOD)) { + return EFI_SUCCESS; + } + + Status = PchDmiSetLpcIoDecodeRanges (LpcIoDecodeRanges); if + (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // + // program LPC/eSPI PCI offset 80h. + // + PciSegmentWrite16 (LpcBaseAddr + R_LPC_CFG_IOD, LpcIoDecodeRanges); + + return Status; +} + +/** + Set PCH LPC/eSPI and eSPI CS1# IO enable decoding. + Setup I/O Enables in DMI to the same value program in LPC/eSPI PCI offset 82h (LPC, eSPI CS0#) or A0h (eSPI CS1#). + Note: Bit[15:10] of the source decode register is Read-Only. The IO +range indicated by the Enables field + in LPC/eSPI PCI offset 82h[13:10] or A0h[13:10] is always forwarded by DMI to subtractive agent for handling. + Please check EDS for detail of Lpc/eSPI IO decode ranges bit definition. + + @param[in] IoEnableDecoding LPC/eSPI IO enable decoding bit settings. + @param[in] SlaveId Target ID (refer to SLAVE_ID_INDEX) + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_UNSUPPORTED DMI configuration is locked +**/ +EFI_STATUS +LpcEspiIoEnableDecodingSetHelper ( + IN UINT16 IoEnableDecoding, + IN SLAVE_ID_INDEX SlaveId + ) +{ + UINT64 LpcBaseAddr; + EFI_STATUS Status; + UINT16 Cs1IoEnableDecodingOrg; + UINT16 Cs0IoEnableDecodingOrg; + UINT16 IoEnableDecodingMerged; + + LpcBaseAddr = LpcPciCfgBase (); + + Cs0IoEnableDecodingOrg = PciSegmentRead16 (LpcBaseAddr + + R_LPC_CFG_IOE); + + if (IsEspiSecondSlaveSupported ()) { + Cs1IoEnableDecodingOrg = PciSegmentRead16 (LpcBaseAddr + + R_ESPI_CFG_CS1IORE); } else { + Cs1IoEnableDecodingOrg = 0; + } + + if (SlaveId == SlaveEspiCS1) { + if (IoEnableDecoding == Cs1IoEnableDecodingOrg) { + return EFI_SUCCESS; + } else { + IoEnableDecodingMerged = (Cs0IoEnableDecodingOrg | IoEnableDecoding); + } + } else { + if ((IoEnableDecoding | Cs1IoEnableDecodingOrg) == Cs0IoEnableDecodingOrg) { + return EFI_SUCCESS; + } else { + IoEnableDecodingMerged = (Cs1IoEnableDecodingOrg | IoEnableDecoding); + } + } + + Status = PchDmiSetLpcIoEnable (IoEnableDecodingMerged); if + (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // + // program PCI offset 82h for LPC/eSPI. + // + PciSegmentWrite16 (LpcBaseAddr + R_LPC_CFG_IOE, + IoEnableDecodingMerged); + + if (SlaveId == SlaveEspiCS1) { + // + // For eSPI CS1# device program eSPI PCI offset A0h. + // + PciSegmentWrite16 (LpcBaseAddr + R_ESPI_CFG_CS1IORE, + IoEnableDecoding); } + + return Status; +} + +/** + Set PCH LPC and eSPI CS0# IO enable decoding. + Setup I/O Enables in DMI to the same value program in LPC/eSPI PCI offset 82h. + Note: Bit[15:10] of the source decode register is Read-Only. The IO +range indicated by the Enables field + in LPC/eSPI PCI offset 82h[13:10] is always forwarded by DMI to subtractive agent for handling. + Please check EDS for detail of LPC/eSPI IO decode ranges bit definition. + + @param[in] LpcIoEnableDecoding LPC IO enable decoding bit settings. + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_UNSUPPORTED DMIC.SRL is set. +**/ +EFI_STATUS +PchLpcIoEnableDecodingSet ( + IN UINT16 LpcIoEnableDecoding + ) +{ + return LpcEspiIoEnableDecodingSetHelper (LpcIoEnableDecoding, +SlaveLpcEspiCS0); } diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PeiDxeSmmPchCycleDecodingLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PeiDxeSmmPchCycleDecodingLib.inf new file mode 100644 index 0000000000..a381c0f0f7 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDec +++ odingLib/PeiDxeSmmPchCycleDecodingLib.inf @@ -0,0 +1,41 @@ +## @file +# PCH cycle decoding Lib. +# +# All function in this library is available for PEI, DXE, and SMM, # +But do not support UEFI RUNTIME environment call. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = PeiDxeSmmPchCycleDecodingLib FILE_GUID = +676C749F-9CD1-46B7-BAFD-4B1BC36B4C8E +VERSION_STRING = 1.0 +MODULE_TYPE = BASE +LIBRARY_CLASS = PchCycleDecodingLib + + +[LibraryClasses] +BaseLib +IoLib +DebugLib +PciSegmentLib +PchInfoLib +PchPcrLib +PchDmiLib +EspiLib +PchPciBdfLib + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + +[Sources] +PchCycleDecodingLib.c + +[Pcd] +gSiPkgTokenSpaceGuid.PcdSiHpetBaseAddress ## CONSUMES +gSiPkgTokenSpaceGuid.PcdSiIoApicBaseAddress ## CONSUMES -- 2.36.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107778): https://edk2.groups.io/g/devel/message/107778 Mute This Topic: https://groups.io/mt/100551003/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply [flat|nested] 14+ messages in thread
* [edk2-devel] [PATCH v2 5/7] AlderlakeSiliconPkg/Pch: Add drivers 2023-08-04 17:37 [edk2-devel] [PATCH v2 1/7] AlderlakeSiliconPkg: Add package and library instances Saloni Kasbekar ` (2 preceding siblings ...) 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 4/7] AlderlakeSiliconPkg/Pch: Add libraries Saloni Kasbekar @ 2023-08-04 17:37 ` Saloni Kasbekar 2023-08-16 2:46 ` Chuang, Rosen 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 6/7] AlderlakeSiliconPkg/SystemAgent: Add include headers Saloni Kasbekar ` (2 subsequent siblings) 6 siblings, 1 reply; 14+ messages in thread From: Saloni Kasbekar @ 2023-08-04 17:37 UTC (permalink / raw) To: devel Cc: Saloni Kasbekar, Sai Chaganty, Nate DeSimone, Isaac Oram, Rosen Chuang Adds the following drivers: - PchSmiDispatcher - SmmControl Cc: Sai Chaganty <rangasai.v.chaganty@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Isaac Oram <isaac.w.oram@intel.com> Cc: Rosen Chuang <rosen.chuang@intel.com> Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com> --- .../Pch/PchSmiDispatcher/Smm/PchSmiDispatch.c | 1857 +++++++++++++++++ .../PchSmiDispatcher/Smm/PchSmiDispatcher.inf | 106 + .../Pch/PchSmiDispatcher/Smm/PchSmiHelper.h | 34 + .../Pch/PchSmiDispatcher/Smm/PchSmm.h | 1028 +++++++++ .../Pch/PchSmiDispatcher/Smm/PchSmmCore.c | 905 ++++++++ .../Pch/PchSmiDispatcher/Smm/PchSmmGpi.c | 255 +++ .../Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c | 332 +++ .../Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h | 163 ++ .../Smm/PchSmmPeriodicTimer.c | 670 ++++++ .../PchSmiDispatcher/Smm/PchSmmPowerButton.c | 77 + .../Pch/PchSmiDispatcher/Smm/PchSmmSw.c | 381 ++++ .../Pch/PchSmiDispatcher/Smm/PchSmmSx.c | 117 ++ .../Pch/PchSmiDispatcher/Smm/PchSmmUsb.c | 244 +++ .../Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.c | 682 ++++++ .../Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.h | 107 + .../Pch/PchSmiDispatcher/Smm/PcieSmmClient.c | 38 + .../Pch/PchSmiDispatcher/Smm/SmmGlobalsPch.c | 20 + .../Pch/SmmControl/RuntimeDxe/SmmControl.inf | 53 + .../SmmControl/RuntimeDxe/SmmControlDriver.c | 338 +++ .../SmmControl/RuntimeDxe/SmmControlDriver.h | 122 ++ 20 files changed, 7529 insertions(+) create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatch.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatcher.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowerButton.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PcieSmmClient.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/SmmGlobalsPch.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatch.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatch.c new file mode 100644 index 0000000000..637b9bb437 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatch.c @@ -0,0 +1,1857 @@ +/** @file + This function handle the register/unregister of PCH specific SMI events. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include <Library/SmiHandlerProfileLib.h> +#include <Register/PchRegs.h> +#include <Register/PmcRegs.h> +#include <Register/TcoRegs.h> +#include <Register/PchRegsLpc.h> +#include <Register/SpiRegs.h> +#include <Library/PchPciBdfLib.h> +#include <Library/S3BootScriptLib.h> +#include "PchSmiHelper.h" + + +/** + The internal function used to create and insert a database record + for SMI record of Pch Smi types. + + @param[in] SrcDesc The pointer to the SMI source description + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[in] PchSmiType Specific SMI type of PCH SMI + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. +**/ +EFI_STATUS +PchSmiRecordInsert ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc, + IN PCH_SMI_CALLBACK_FUNCTIONS DispatchFunction, + IN PCH_SMI_TYPES PchSmiType, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD Record; + + if (SrcDesc == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&Record, sizeof (DATABASE_RECORD)); + // + // Gather information about the registration request + // + Record.Signature = DATABASE_RECORD_SIGNATURE; + Record.PchSmiCallback = DispatchFunction; + Record.ProtocolType = PchSmiDispatchType; + Record.PchSmiType = PchSmiType; + + CopyMem (&Record.SrcDesc, SrcDesc, sizeof (PCH_SMM_SOURCE_DESC)); + Status = SmmCoreInsertRecord ( + &Record, + DispatchHandle + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + + +// +// TCO_STS bit that needs to be cleared +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mDescSrcTcoSts = { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } + }, + NULL_BIT_DESC_INITIALIZER +}; + +/** + Clear the TCO SMI status bit and block after the SMI handling is done + + @param[in] SrcDesc Pointer to the PCH SMI source description table + +**/ +VOID +EFIAPI +PchTcoSmiClearSourceAndBlock ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + PchSmmClearSourceAndBlock (SrcDesc); + // + // Any TCO-based status bits require special handling. + // SMI_STS.TCO_STS must be cleared in addition to the status bit in the TCO registers + // + PchSmmClearSource (&mDescSrcTcoSts); +} + +/** + Clear the TCO SMI status bit after the SMI handling is done + + @param[in] SrcDesc Pointer to the PCH SMI source description table + +**/ +VOID +EFIAPI +PchTcoSmiClearSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + PchSmmClearSource (SrcDesc); + // + // Any TCO-based status bits require special handling. + // SMI_STS.TCO_STS must be cleared in addition to the status bit in the TCO registers + // + PchSmmClearSource (&mDescSrcTcoSts); +} + +/** + Initialize Source descriptor structure + + @param[in] SrcDesc Pointer to the PCH SMI source description table + +**/ +VOID +EFIAPI +NullInitSourceDesc ( + PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + ZeroMem (SrcDesc, sizeof (PCH_SMM_SOURCE_DESC)); + SrcDesc->En[0].Reg.Type = PCH_SMM_ADDR_TYPE_NULL; + SrcDesc->En[1].Reg.Type = PCH_SMM_ADDR_TYPE_NULL; + SrcDesc->Sts[0].Reg.Type = PCH_SMM_ADDR_TYPE_NULL; + SrcDesc->PmcSmiSts.Reg.Type = PCH_SMM_ADDR_TYPE_NULL; +} + +// +// Mch srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescMch = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_DMISMI + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of MCH event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiMchRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescMch, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiMchType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSmiClearSource; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// TcoTimeout srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescTcoTimeout = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_TIMEOUT + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of TcoTimeout event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiTcoTimeoutRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescTcoTimeout, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiTcoTimeoutType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSmiClearSource; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// OsTco srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescOsTco = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_SW_TCO_SMI + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of OS TCO event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiOsTcoRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescOsTco, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiOsTcoType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSmiClearSource; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// Nmi +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescNmi = { + PCH_SMM_NO_FLAGS, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_CNT} + }, + S_TCO_IO_TCO1_CNT, + N_TCO_IO_TCO1_CNT_NMI2SMI_EN + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_NMI2SMI + } + }, + // + // NOTE: The status of NMI2SMI won't reflect to PMC SMI_STS. + // So skip the top level status check and check the TCO1_STS directly. + // + NULL_BIT_DESC_INITIALIZER +}; + +/** + The register function used to register SMI handler of NMI event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiNmiRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescNmi, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiNmiType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSmiClearSource; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// IntruderDetect srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescIntruderDet = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO2_CNT} + }, + S_TCO_IO_TCO2_CNT, + N_TCO_IO_TCO2_CNT_INTRD_SEL + } + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO2_STS} + }, + S_TCO_IO_TCO2_STS, + N_TCO_IO_TCO2_STS_INTRD_DET + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of Intruder Detect event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiIntruderDetRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescIntruderDet, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiIntruderDetectType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSmiClearSourceAndBlock; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// SpiBiosWp srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC mSrcDescSpiBiosWp = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + { + { + PCIE_ADDR_TYPE, + { 0xFFFFFFFF } // to be updated in PchSmiDispatchUpdateDescriptors + }, + S_SPI_CFG_BC, + N_SPI_CFG_BC_BLE + }, + }, + { + { + { + PCIE_ADDR_TYPE, + { 0xFFFFFFFF } // to be updated in PchSmiDispatchUpdateDescriptors + }, + S_SPI_CFG_BC, + N_SPI_CFG_BC_SYNC_SS + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + Special handling for SPI Write Protect + + @param[in] SrcDesc Not used +**/ +VOID +EFIAPI +PchTcoSpiWpClearSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + UINT64 SpiRegBase; + UINT32 BiosControl; + UINT32 Timeout; + + SpiRegBase = SpiPciCfgBase (); + PciSegmentAndThenOr32 ( + SpiRegBase + R_SPI_CFG_BC, + (UINT32) ~B_SPI_CFG_BC_ASYNC_SS, + B_SPI_CFG_BC_SYNC_SS + ); + // + // Ensure the SYNC is cleared + // + Timeout = 1000; + do { + BiosControl = PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BC); + Timeout--; + } while ((BiosControl & B_SPI_CFG_BC_SYNC_SS) && (Timeout > 0)); + + // + // Any TCO-based status bits require special handling. + // SMI_STS.TCO_STS must be cleared in addition to the status bit in the TCO registers + // + PchSmmClearSource (&mDescSrcTcoSts); +} + +/** + Set SMI_EN_TCO to enable TCO SMI. +**/ +STATIC +VOID +PchSetSmiEnTco ( + VOID + ) +{ + IoOr32 (mAcpiBaseAddr + R_ACPI_IO_SMI_EN, B_ACPI_IO_SMI_EN_TCO); +} + +/** + The register function used to register SMI handler of BIOS write protect event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiSpiBiosWpRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescSpiBiosWp, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiSpiBiosWpType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSpiWpClearSource; + PchTcoSpiWpClearSource (NULL); + // + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE. + // Only enable SMI_EN_TCO. + // + PchSetSmiEnTco (); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// LpcBiosWp srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC mSrcDescLpcBiosWp = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + { + { + PCIE_ADDR_TYPE, + { 0xFFFFFFFF } // to be updated in PchSmiDispatchUpdateDescriptors + }, + S_LPC_CFG_BC, + N_LPC_CFG_BC_LE + } + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_BIOSWR + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of LPC BIOS write protect event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiLpcBiosWpRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + if (IsEspiEnabled ()) { + // + // Status is D31F0's PCBC.BWPDS + // + ASSERT (FALSE); + return EFI_UNSUPPORTED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescLpcBiosWp, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiLpcBiosWpType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSmiClearSource; + PchSmmClearSource (&Record->SrcDesc); + // + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE. + // Only enable SMI_EN_TCO. + // + PchSetSmiEnTco (); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// NEWCENTURY_STS bit that needs to be cleared +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescNewCentury = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_NEWCENTURY + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of NEW CENTURY event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiNewCenturyRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescNewCentury, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiNewCenturyType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSmiClearSourceAndBlock; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiUnRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + return EFI_SUCCESS; +} + +// +// Pme srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescPme = { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_GPE0_EN_127_96} + }, + S_ACPI_IO_GPE0_EN_127_96, + N_ACPI_IO_GPE0_EN_127_96_PME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_GPE0_STS_127_96} + }, + S_ACPI_IO_GPE0_STS_127_96, + N_ACPI_IO_GPE0_STS_127_96_PME + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_GPE0 + } +}; + +/** + The register function used to register SMI handler of PME event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchAcpiSmiPmeRegister ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescPme, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchAcpiSmiPmeType, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescPme); + PchSmmEnableSource (&mSrcDescPme); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// PmeB0 srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescPmeB0 = { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_GPE0_EN_127_96} + }, + S_ACPI_IO_GPE0_EN_127_96, + N_ACPI_IO_GPE0_EN_127_96_PME_B0 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_GPE0_STS_127_96} + }, + S_ACPI_IO_GPE0_STS_127_96, + N_ACPI_IO_GPE0_STS_127_96_PME_B0 + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_GPE0 + } +}; +/** + The register function used to register SMI handler of PME B0 event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchAcpiSmiPmeB0Register ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescPmeB0, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchAcpiSmiPmeB0Type, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescPmeB0); + PchSmmEnableSource (&mSrcDescPmeB0); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// RtcAlarm srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescRtcAlarm = { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_EN} + }, + S_ACPI_IO_PM1_EN, + N_ACPI_IO_PM1_EN_RTC + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_STS} + }, + S_ACPI_IO_PM1_STS, + N_ACPI_IO_PM1_STS_RTC + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_PM1_STS_REG + } +}; + +/** + The register function used to register SMI handler of RTC alarm event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchAcpiSmiRtcAlarmRegister ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescRtcAlarm, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchAcpiSmiRtcAlarmType, + DispatchHandle + ); + + PchSmmClearSource (&mSrcDescRtcAlarm); + PchSmmEnableSource (&mSrcDescRtcAlarm); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// TmrOverflow srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescTmrOverflow = { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_EN} + }, + S_ACPI_IO_PM1_EN, + N_ACPI_IO_PM1_EN_TMROF + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_STS} + }, + S_ACPI_IO_PM1_STS, + N_ACPI_IO_PM1_STS_TMROF + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_PM1_STS_REG + } +}; + +/** + The register function used to register SMI handler of Timer Overflow event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchAcpiSmiTmrOverflowRegister ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescTmrOverflow, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchAcpiSmiTmrOverflowType, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescTmrOverflow); + PchSmmEnableSource (&mSrcDescTmrOverflow); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + + return Status; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchAcpiSmiUnRegister ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + DATABASE_RECORD *RecordToDelete; + EFI_STATUS Status; + + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle); + Status = PchSmmCoreUnRegister (NULL, DispatchHandle); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileUnregisterHandler (&gPchAcpiSmiDispatchProtocolGuid, RecordToDelete->Callback, NULL, 0); + } + return Status; +} + +// +// SerialIrq srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSerialIrq = { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SERIRQ + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SERIRQ + } +}; + +/** + The register function used to register SMI handler of Serial IRQ event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchSmiSerialIrqRegister ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescSerialIrq, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchSmiSerialIrqType, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescSerialIrq); + PchSmmEnableSource (&mSrcDescSerialIrq); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// McSmi srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescMcSmi = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_MCSMI + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_MCSMI + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_MCSMI + } +}; + +/** + The register function used to register SMI handler of MCSMI event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchSmiMcSmiRegister ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescMcSmi, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchSmiMcSmiType, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescMcSmi); + PchSmmEnableSource (&mSrcDescMcSmi); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// SmBus srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSmbus = { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SMBUS + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SMBUS + } +}; + +/** + The register function used to register SMI handler of SMBUS event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchSmiSmbusRegister ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescSmbus, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchSmiSmBusType, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescSmbus); + PchSmmEnableSource (&mSrcDescSmbus); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// SpiAsyncSmi srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC mSrcDescSpiAsyncSmi = { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + { 0xFFFFFFFF } // to be updated in PchSmiDispatchUpdateDescriptors + }, + S_SPI_CFG_BC, + N_SPI_CFG_BC_ASE_BWP + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + { 0xFFFFFFFF } // to be updated in PchSmiDispatchUpdateDescriptors + }, + S_SPI_CFG_BC, + N_SPI_CFG_BC_ASYNC_SS + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SPI + } +}; + +/** + Special handling for SPI Asynchronous SMI. + If SPI ASYNC SMI is enabled, De-assert SMI is sent when Flash Cycle Done + transitions from 1 to 0 or when the SMI enable becomes false. + + @param[in] SrcDesc Not used +**/ +VOID +EFIAPI +PchSmiSpiAsyncClearSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + UINT64 SpiRegBase; + UINT32 SpiBar0; + + SpiRegBase = SpiPciCfgBase (); + SpiBar0 = PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BAR0) & ~(B_SPI_CFG_BAR0_MASK); + if (SpiBar0 != PCH_SPI_BASE_ADDRESS) { + // + // Temporary disable MSE, and override with SPI reserved MMIO address, then enable MSE. + // + SpiBar0 = PCH_SPI_BASE_ADDRESS; + PciSegmentAnd8 (SpiRegBase + PCI_COMMAND_OFFSET, (UINT8) ~EFI_PCI_COMMAND_MEMORY_SPACE); + PciSegmentWrite32 (SpiRegBase + R_SPI_CFG_BAR0, SpiBar0); + PciSegmentOr8 (SpiRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE); + } + + MmioOr32 (SpiBar0 + R_SPI_MEM_HSFSC, B_SPI_MEM_HSFSC_FDONE); +} + +/** + Special handling to enable SPI Asynchronous SMI +**/ +VOID +PchSmiSpiAsyncEnableSource ( + VOID + ) +{ + UINT64 SpiRegBase; + UINT32 Data32And; + UINT32 Data32Or; + + SpiRegBase = SpiPciCfgBase (); + Data32And = (UINT32) ~B_SPI_CFG_BC_SYNC_SS; + Data32Or = B_SPI_CFG_BC_ASE_BWP; + + PciSegmentAndThenOr32 ( + SpiRegBase + R_SPI_CFG_BC, + Data32And, + Data32Or + ); + S3BootScriptSavePciCfgReadWrite ( + S3BootScriptWidthUint32, + SpiRegBase + R_SPI_CFG_BC, + (VOID*) &Data32Or, + (VOID*) &Data32And + ); + + // + // Clear the source + // + PchSmiSpiAsyncClearSource (NULL); +} + +/** + The register function used to register SMI handler of SPI Asynchronous event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchSmiSpiAsyncRegister ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescSpiAsyncSmi, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchSmiSpiAsyncType, + DispatchHandle + ); + + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchSmiSpiAsyncClearSource; + PchSmiSpiAsyncClearSource (NULL); + PchSmiSpiAsyncEnableSource (); + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered + @retval EFI_ACCESS_DENIED Return access denied since SPI aync SMI handler is not able to disabled. +**/ +EFI_STATUS +EFIAPI +PchSmiUnRegister ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + DATABASE_RECORD *Record; + UINT64 SpiRegBase; + EFI_STATUS Status; + + Record = DATABASE_RECORD_FROM_LINK (DispatchHandle); + if ((Record->SrcDesc.En[0].Reg.Type == PCIE_ADDR_TYPE) && + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Dev == SpiDevNumber ()) && + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc == SpiFuncNumber ()) && + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Reg == R_SPI_CFG_BC) && + (Record->SrcDesc.En[0].Bit == N_SPI_CFG_BC_ASE_BWP)) { + SpiRegBase = SpiPciCfgBase (); + if (PciSegmentRead8 (SpiRegBase + R_SPI_CFG_BC) & B_SPI_CFG_BC_BILD) { + // + // SPI Asynchronous SMI cannot be disabled + // + return EFI_ACCESS_DENIED; + } + } + Status = PchSmmCoreUnRegister (NULL, DispatchHandle); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileUnregisterHandler (&gPchSmiDispatchProtocolGuid, Record->Callback, NULL, 0); + } + return Status; +} + + +/** + Declaration of PCH TCO SMI DISPATCH PROTOCOL instance +**/ +PCH_TCO_SMI_DISPATCH_PROTOCOL mPchTcoSmiDispatchProtocol = { + PCH_TCO_SMI_DISPATCH_REVISION, // Revision + PchTcoSmiUnRegister, // Unregister + PchTcoSmiMchRegister, // Mch + PchTcoSmiTcoTimeoutRegister, // TcoTimeout + PchTcoSmiOsTcoRegister, // OsTco + PchTcoSmiNmiRegister, // Nmi + PchTcoSmiIntruderDetRegister, // IntruderDectect + PchTcoSmiSpiBiosWpRegister, // SpiBiosWp + PchTcoSmiLpcBiosWpRegister, // LpcBiosWp + PchTcoSmiNewCenturyRegister // NewCentury +}; + +/** + Declaration of PCH ACPI SMI DISPATCH PROTOCOL instance +**/ +PCH_ACPI_SMI_DISPATCH_PROTOCOL mPchAcpiSmiDispatchProtocol = { + PCH_ACPI_SMI_DISPATCH_REVISION, // Revision + PchAcpiSmiUnRegister, // Unregister + PchAcpiSmiPmeRegister, // Pme + PchAcpiSmiPmeB0Register, // PmeB0 + PchAcpiSmiRtcAlarmRegister, // RtcAlarm + PchAcpiSmiTmrOverflowRegister // TmrOverflow +}; + +/** + Declaration of MISC PCH SMI DISPATCH PROTOCOL instance +**/ +PCH_SMI_DISPATCH_PROTOCOL mPchSmiDispatchProtocol = { + PCH_SMI_DISPATCH_REVISION, // Revision + PchSmiUnRegister, // Unregister + PchSmiSerialIrqRegister, // SerialIrq + PchSmiMcSmiRegister, // McSmi + PchSmiSmbusRegister, // SmBus + PchSmiSpiAsyncRegister // SpiAsync +}; + +/** + Install protocols of PCH specifics SMI types, including + PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC SMI types. + + @retval the result of protocol installation +**/ +EFI_STATUS +InstallPchSmiDispatchProtocols ( + VOID + ) +{ + EFI_HANDLE Handle; + EFI_STATUS Status; + + Handle = NULL; + Status = gSmst->SmmInstallProtocolInterface ( + &Handle, + &gPchTcoSmiDispatchProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPchTcoSmiDispatchProtocol + ); + + Status = gSmst->SmmInstallProtocolInterface ( + &Handle, + &gPchAcpiSmiDispatchProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPchAcpiSmiDispatchProtocol + ); + Status = gSmst->SmmInstallProtocolInterface ( + &Handle, + &gPchSmiDispatchProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPchSmiDispatchProtocol + ); + + return Status; +} + +/** + The function to dispatch all callback function of PCH SMI types. + + @retval EFI_SUCCESS Function successfully completed + @retval EFI_UNSUPPORTED no +**/ +EFI_STATUS +PchSmiTypeCallbackDispatcher ( + IN DATABASE_RECORD *Record + ) +{ + EFI_STATUS Status; + PCH_SMI_TYPES PchSmiType; + + PchSmiType = Record->PchSmiType; + Status = EFI_SUCCESS; + + switch (PchSmiType) { + case PchTcoSmiMchType: + case PchTcoSmiTcoTimeoutType: + case PchTcoSmiOsTcoType: + case PchTcoSmiNmiType: + case PchTcoSmiIntruderDetectType: + case PchTcoSmiSpiBiosWpType: + case PchTcoSmiLpcBiosWpType: + case PchTcoSmiNewCenturyType: + ((PCH_TCO_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link); + break; + case PchPcieSmiRpHotplugType: + case PchPcieSmiRpLinkActiveType: + case PchPcieSmiRpLinkEqType: + break; + case PchAcpiSmiPmeType: + case PchAcpiSmiPmeB0Type: + case PchAcpiSmiRtcAlarmType: + case PchAcpiSmiTmrOverflowType: + ((PCH_ACPI_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link); + break; + case PchSmiSerialIrqType: + case PchSmiMcSmiType: + case PchSmiSmBusType: + case PchSmiSpiAsyncType: + case PchIoTrapSmiType: ///< internal type for IoTrap + ((PCH_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link); + break; + default: + Status = EFI_UNSUPPORTED; + break; + } + + return Status; +} + +/** + Performs update of SmiDispatch descriptors with values that have to be evaluated during runtime. +**/ +VOID +PchSmiDispatchUpdateDescriptors ( + VOID + ) +{ + UINT32 SpiPcieAddr; + UINT32 LpcPcieAddr; + + SpiPcieAddr = ((DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (SpiDevNumber () << 19) | + (SpiFuncNumber () << 16) | + R_SPI_CFG_BC); + LpcPcieAddr = ((DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (LpcDevNumber () << 19) | + (LpcFuncNumber () << 16) | + R_LPC_CFG_BC); + // + // mSrcDescSpiBiosWp + // + mSrcDescSpiBiosWp.En[1].Reg.Data.raw = SpiPcieAddr; + mSrcDescSpiBiosWp.Sts[0].Reg.Data.raw = SpiPcieAddr; + + // + // mSrcDescLpcBiosWp + // + mSrcDescLpcBiosWp.En[1].Reg.Data.raw = LpcPcieAddr; + + // + // mSrcDescSpiAsyncSmi + // + mSrcDescSpiAsyncSmi.En[0].Reg.Data.raw = SpiPcieAddr; + mSrcDescSpiAsyncSmi.Sts[0].Reg.Data.raw = SpiPcieAddr; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatcher.inf b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatcher.inf new file mode 100644 index 0000000000..7031b5193a --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatcher.inf @@ -0,0 +1,106 @@ +## @file +# Component description file for the Pch SMI Dispatch Handlers module +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = PchSmiDispatcher +FILE_GUID = B0D6ED53-B844-43f5-BD2F-61095264E77E +VERSION_STRING = 1.0 +MODULE_TYPE = DXE_SMM_DRIVER +PI_SPECIFICATION_VERSION = 1.10 +ENTRY_POINT = InitializePchSmmDispatcher + + +[LibraryClasses] +UefiBootServicesTableLib +UefiDriverEntryPoint +IoLib +DebugLib +PcdLib +BaseLib +BaseMemoryLib +HobLib +DevicePathLib +PchCycleDecodingLib +PchPcieRpLib +PchPcrLib +SmmServicesTableLib +ReportStatusCodeLib +PerformanceLib +DxeServicesTableLib +GpioLib +GpioPrivateLib +EspiLib +S3BootScriptLib +ConfigBlockLib +PmcPrivateLib +PmcLib +SmiHandlerProfileLib +PchPciBdfLib +P2SbSidebandAccessLib +CpuPcieInfoFruLib + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + + +[Pcd] +# Progress Code for S3 Suspend start. +# PROGRESS_CODE_S3_SUSPEND_START = (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_SPECIFIC | 0x00000000)) = 0x03078000 +gSiPkgTokenSpaceGuid.PcdProgressCodeS3SuspendStart +# Progress Code for S3 Suspend end. +# PROGRESS_CODE_S3_SUSPEND_END = (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_SPECIFIC | 0x00000001)) = 0x03078001 +gSiPkgTokenSpaceGuid.PcdProgressCodeS3SuspendEnd +gSiPkgTokenSpaceGuid.PcdEfiGcdAllocateType + + +[Sources] +PchSmm.h +PchSmmCore.c +PchSmmHelpers.c +PchxSmmHelpers.c +SmmGlobalsPch.c +PchSmmUsb.c +PchSmmGpi.c +PchSmmPowerButton.c +PchSmmSw.c +PchSmmSx.c +PchSmmPeriodicTimer.c +PchSmiDispatch.c +PcieSmmClient.c + + +[Protocols] +gEfiPciRootBridgeIoProtocolGuid ## CONSUMES +gEfiSmmGpiDispatch2ProtocolGuid ## PRODUCES +gEfiSmmSxDispatch2ProtocolGuid ## PRODUCES +gEfiSmmSwDispatch2ProtocolGuid ## PRODUCES +gEfiSmmUsbDispatch2ProtocolGuid ## PRODUCES +gEfiSmmPowerButtonDispatch2ProtocolGuid ## PRODUCES +gEfiSmmPeriodicTimerDispatch2ProtocolGuid ## PRODUCES +gEfiSmmBase2ProtocolGuid ## CONSUMES +gEfiSmmCpuProtocolGuid ## CONSUMES +gEfiSmmReadyToLockProtocolGuid ## CONSUMES +gPchTcoSmiDispatchProtocolGuid ## PRODUCES +gPchPcieSmiDispatchProtocolGuid ## PRODUCES +gPchAcpiSmiDispatchProtocolGuid ## PRODUCES +gPchSmiDispatchProtocolGuid ## PRODUCES +gPchEspiSmiDispatchProtocolGuid ## PRODUCES +gPchSmmPeriodicTimerControlGuid ## PRODUCES + + +[Guids] + + +[Depex] +gEfiPciRootBridgeIoProtocolGuid AND +gEfiPciHostBridgeResourceAllocationProtocolGuid AND ## This is to ensure that PCI MMIO resource has been prepared and available for this driver to allocate. +gEfiSmmCpuProtocolGuid AND +gEfiSmmBase2ProtocolGuid + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper.h new file mode 100644 index 0000000000..5ec9455797 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper.h @@ -0,0 +1,34 @@ +/** @file + eSPI SMI Dispatch header + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _PCH_SMI_HELPER_H_ +#define _PCH_SMI_HELPER_H_ +#include <Uefi/UefiBaseType.h> + +/** + Get CPU or PCH Pcie Root Port Device and Function Number by Root Port physical Number + + @param[in] RpNumber Root port physical number. (0-based) + @param[out] RpDev Return corresponding root port device number. + @param[out] RpFun Return corresponding root port function number. +**/ +VOID +GetPcieRpDevFun ( + IN UINTN RpIndex, + OUT UINTN *RpDev, + OUT UINTN *RpFun + ); + +/** + Performs update of SmiDispatch descriptors with values that have to be evaluated during runtime. +**/ +VOID +PchSmiDispatchUpdateDescriptors ( + VOID + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h new file mode 100644 index 0000000000..41969a0ec7 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h @@ -0,0 +1,1028 @@ +/** @file + Prototypes and defines for the PCH SMM Dispatcher. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_SMM_H_ +#define _PCH_SMM_H_ + +#include <Uefi.h> +#include <Protocol/PciRootBridgeIo.h> +#include <Protocol/LoadedImage.h> +#include <Protocol/SmmControl2.h> +#include <Protocol/SmmUsbDispatch2.h> +#include <Protocol/SmmSxDispatch2.h> +#include <Protocol/SmmSwDispatch2.h> +#include <Protocol/SmmGpiDispatch2.h> +#include <Protocol/SmmPowerButtonDispatch2.h> +#include <Protocol/SmmPeriodicTimerDispatch2.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DevicePathLib.h> +#include <Library/SmmServicesTableLib.h> +#include <Library/ReportStatusCodeLib.h> +#include <Library/PerformanceLib.h> +#include <Protocol/SmmReadyToLock.h> +#include <IndustryStandard/Pci30.h> +#include <Library/PchCycleDecodingLib.h> +#include <Library/PchPcrLib.h> +#include <Library/PciSegmentLib.h> +#include <Library/GpioLib.h> +#include <Library/PchInfoLib.h> +#include <Library/EspiLib.h> +#include <Library/GpioPrivateLib.h> +#include <Protocol/PchTcoSmiDispatch.h> +#include <Protocol/PchPcieSmiDispatch.h> +#include <Protocol/PchAcpiSmiDispatch.h> +#include <Protocol/PchSmiDispatch.h> +#include <Library/PmcLib.h> + +#define EFI_BAD_POINTER 0xAFAFAFAFAFAFAFAFULL + +extern BOOLEAN mReadyToLock; + +/// +/// Define an enumeration for all the supported protocols +/// +#define PCH_SMM_PROTOCOL_TYPE_MAX 6 + +typedef enum { + UsbType, + SxType, + SwType, + GpiType, + PowerButtonType, + PeriodicTimerType, + PchSmiDispatchType, + PchSmmProtocolTypeMax +} PCH_SMM_PROTOCOL_TYPE; + +/// +/// Define all the supported types of PCH SMI +/// +typedef enum { + PchTcoSmiMchType, + PchTcoSmiTcoTimeoutType, + PchTcoSmiOsTcoType, + PchTcoSmiNmiType, + PchTcoSmiIntruderDetectType, + PchTcoSmiSpiBiosWpType, + PchTcoSmiLpcBiosWpType, + PchTcoSmiNewCenturyType, + PchPcieSmiRpHotplugType, + PchPcieSmiRpLinkActiveType, + PchPcieSmiRpLinkEqType, + PchAcpiSmiPmeType, + PchAcpiSmiPmeB0Type, + PchAcpiSmiRtcAlarmType, + PchAcpiSmiTmrOverflowType, + PchEspiSmiEspiSlaveType, + PchSmiSerialIrqType, + PchSmiMcSmiType, + PchSmiSmBusType, + PchSmiSpiAsyncType, + PchIoTrapSmiType ///< internal SMI type +} PCH_SMI_TYPES; + +/// +/// Generic funciton pointer to cover all Pch SMI function pointer types +/// +typedef +VOID +(EFIAPI *PCH_SMI_CALLBACK_FUNCTIONS) ( + IN EFI_HANDLE DispatchHandle, + ... + ); + + +/// +/// SPECIFYING A REGISTER +/// We want a general way of referring to addresses. For this case, we'll only +/// need addresses in the ACPI table (and the TCO entries within the ACPI table). +/// However, it's interesting to consider what it would take to support other types +/// of addresses. To address Will's concern, I think it prudent to accommodate it +/// early on in the design. +/// +/// Addresses we need to consider: +/// +/// Type: Required: +/// I/O Yes +/// ACPI (special case of I/O) Only if we want to +/// TCO (special case of I/O) Only if we want to +/// GPIO (special case of MMIO) Only if we want to +/// Memory (or Memory Mapped I/O) Only if we want to +/// PCIE Yes, for BiosWp +/// +typedef enum { + /// + /// IO_ADDR_TYPE, /// unimplemented + /// + ACPI_ADDR_TYPE, + TCO_ADDR_TYPE, + /// + /// MEMORY_ADDR_TYPE, /// unimplemented + /// + GPIO_ADDR_TYPE, + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCIE_ADDR_TYPE, + PCR_ADDR_TYPE, + NUM_ADDR_TYPES, ///< count of items in this enum + PCH_SMM_ADDR_TYPE_NULL = -1 ///< sentinel to indicate NULL or to signal end of arrays +} ADDR_TYPE; + +// +// Assumption: 32-bits -- enum's evaluate to integer +// Assumption: This code will only run on IA-32. Justification: IA-64 doesn't have SMIs. +// We don't have to worry about 64-bit addresses. +// Typedef the size of addresses in case the numbers I'm using are wrong or in case +// this changes. This is a good idea because PCI_ADDR will change, for example, when +// we add support for PciExpress. +// +typedef UINT16 IO_ADDR; +typedef IO_ADDR ACPI_ADDR; ///< can omit +typedef IO_ADDR TCO_ADDR; ///< can omit +typedef UINTN MEM_ADDR; +typedef MEM_ADDR *MEMORY_MAPPED_IO_ADDRESS; +typedef MEM_ADDR *GPIO_ADDR; +typedef union { + UINT32 Raw; + struct { + UINT32 Reg: 16; + UINT32 Fnc: 3; + UINT32 Dev: 5; + UINT32 Bus: 8; + } Fields; +} PCIE_ADDR; + +typedef union { + UINT32 Raw; + struct { + UINT16 Offset; + UINT8 Pid; + UINT8 Base; + } Fields; +} PCR_ADDR; + +typedef struct { + ADDR_TYPE Type; + union { + /// + /// used to initialize during declaration/definition + /// + UINT32 raw; + + /// + /// used to access useful data + /// + IO_ADDR io; + ACPI_ADDR acpi; + TCO_ADDR tco; + GPIO_ADDR gpio; + MEM_ADDR mem; + MEMORY_MAPPED_IO_ADDRESS Mmio; + PCIE_ADDR pcie; + PCR_ADDR Pcr; + + } Data; + +} PCH_SMM_ADDRESS; + +/// +/// SPECIFYING BITS WITHIN A REGISTER +/// Here's a struct that helps us specify a source or enable bit. +/// +typedef struct { + PCH_SMM_ADDRESS Reg; + UINT8 SizeInBytes; ///< of the register + UINT8 Bit; +} PCH_SMM_BIT_DESC; + +// +// Sometimes, we'll have bit descriptions that are unused. It'd be great to have a +// way to easily identify them: +// +#define IS_BIT_DESC_NULL(BitDesc) ((BitDesc).Reg.Type == PCH_SMM_ADDR_TYPE_NULL) ///< "returns" true when BitDesc is NULL +#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type = PCH_SMM_ADDR_TYPE_NULL) ///< will "return" an integer w/ value of 0 +#define NULL_BIT_DESC_INITIALIZER \ + { \ + { \ + PCH_SMM_ADDR_TYPE_NULL, \ + { \ + 0 \ + } \ + }, \ + 0, 0 \ + } +// +// I'd like a type to specify the callback's Sts & En bits because they'll +// be commonly used together: +// +#define NUM_EN_BITS 2 +#define NUM_STS_BITS 1 + +// +// Flags +// +typedef UINT8 PCH_SMM_SOURCE_FLAGS; + +// +// Flags required to describe the event source +// +#define PCH_SMM_NO_FLAGS 0 +#define PCH_SMM_SCI_EN_DEPENDENT 1 + +typedef struct { + PCH_SMM_SOURCE_FLAGS Flags; + PCH_SMM_BIT_DESC En[NUM_EN_BITS]; ///< Describes the enable bit(s) for the SMI event + PCH_SMM_BIT_DESC Sts[NUM_STS_BITS]; ///< Describes the secondary status bit for the SMI event. Might be the same as TopLevelSmi + PCH_SMM_BIT_DESC PmcSmiSts; ///< Refereing to the top level status bit in PMC SMI_STS, i.e. R_PCH_SMI_STS +} PCH_SMM_SOURCE_DESC; + +/// +/// Used to initialize null source descriptor +/// +#define NULL_SOURCE_DESC_INITIALIZER \ + { \ + PCH_SMM_NO_FLAGS, \ + { \ + NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \ + }, \ + { \ + NULL_BIT_DESC_INITIALIZER \ + }, \ + NULL_BIT_DESC_INITIALIZER \ + } + +/// +/// Define a PCIE RP event context for SmiProfileHandlerInfo tool +/// +typedef struct { + PCH_SMI_TYPES PchSmiType; + UINTN RpIndex; +} PCH_SMM_PCIE_REGISTER_CONTEXT; + +/// +/// CHILD CONTEXTS +/// To keep consistent w/ the architecture, we'll need to provide the context +/// to the child when we call its callback function. After talking with Will, +/// we agreed that we'll need functions to "dig" the context out of the hardware +/// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to compare those +/// contexts to prevent unnecessary dispatches. I'd like a general type for these +/// "GetContext" functions, so I'll need a union of all the protocol contexts for +/// our internal use: +/// +typedef union { + // + // (in no particular order) + // + EFI_SMM_SX_REGISTER_CONTEXT Sx; + EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer; + EFI_SMM_SW_REGISTER_CONTEXT Sw; + EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT PowerButton; + EFI_SMM_USB_REGISTER_CONTEXT Usb; + EFI_SMM_GPI_REGISTER_CONTEXT Gpi; + PCH_SMM_PCIE_REGISTER_CONTEXT Pcie; +} PCH_SMM_CONTEXT; + +/// +/// Misc data for PchDispatcher usage. +/// For PeriodicTimer, since the ElapsedTime is removed from EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT of EDKII, +/// and PchDispatcher needs it for every record. Thus move it here to support ElapsedTime. +/// +typedef struct { + UINTN ElapsedTime; + /// + /// A switch to control periodic timer SMI enabling + /// + BOOLEAN TimerSmiEnabled; +} PCH_SMM_MISC_DATA; + +// +// Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes +// +typedef struct _DATABASE_RECORD DATABASE_RECORD; + +/// +/// Assumption: the GET_CONTEXT function will be as small and simple as possible. +/// Assumption: We don't need to pass in an enumeration for the protocol because each +/// GET_CONTEXT function is written for only one protocol. +/// We also need a function to compare contexts to see if the child should be dispatched +/// In addition, we need a function to acquire CommBuffer and CommBufferSize for +/// dispatch callback function of EDKII native support. +/// +typedef +VOID +(EFIAPI *GET_CONTEXT) ( + IN DATABASE_RECORD * Record, + OUT PCH_SMM_CONTEXT * Context + ); + +typedef +BOOLEAN +(EFIAPI *CMP_CONTEXT) ( + IN PCH_SMM_CONTEXT * Context1, + IN PCH_SMM_CONTEXT * Context2 + ); + +typedef +VOID +(EFIAPI *GET_COMMBUFFER) ( + IN DATABASE_RECORD * Record, + OUT VOID **CommBuffer, + OUT UINTN * CommBufferSize + ); + +/// +/// Finally, every protocol will require a "Get Context" and "Compare Context" call, so +/// we may as well wrap that up in a table, too. +/// +typedef struct { + GET_CONTEXT GetContext; + CMP_CONTEXT CmpContext; + GET_COMMBUFFER GetCommBuffer; +} CONTEXT_FUNCTIONS; + +extern CONTEXT_FUNCTIONS ContextFunctions[PCH_SMM_PROTOCOL_TYPE_MAX]; + +/// +/// MAPPING CONTEXT TO BIT DESCRIPTIONS +/// I'd like to have a general approach to mapping contexts to bit descriptions. +/// Sometimes, we'll find that we can use table lookups or constant assignments; +/// other times, we'll find that we'll need to use a function to perform the mapping. +/// If we define a macro to mask that process, we'll never have to change the code. +/// I don't know if this is desirable or not -- if it isn't, then we can get rid +/// of the macros and just use function calls or variable assignments. Doesn't matter +/// to me. +/// Mapping complex contexts requires a function +/// + +/** + Maps a USB context to a source description. + + @param[in] Context The context we need to map. Type must be USB. + @param[out] SrcDesc The source description that corresponds to the given context. + +**/ +VOID +MapUsbToSrcDesc ( + IN PCH_SMM_CONTEXT *Context, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Figure out which timer the child is requesting and + send back the source description + + @param[in] DispatchContext The pointer to the Dispatch Context instances + @param[out] SrcDesc The pointer to the source description + +**/ +VOID +MapPeriodicTimerToSrcDesc ( + IN PCH_SMM_CONTEXT *DispatchContext, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ); + +// +// Mapping simple contexts can be done by assignment or lookup table +// +extern CONST PCH_SMM_SOURCE_DESC mSxSourceDesc; +extern CONST PCH_SMM_SOURCE_DESC mPowerButtonSourceDesc; +extern CONST PCH_SMM_SOURCE_DESC mSrcDescNewCentury; +extern CONST PCH_SMM_SOURCE_DESC mGpiSourceDescTemplate; + +/// +/// For PCHx, APMC is UINT8 port, so the MAX SWI Value is 0xFF. +/// +#define MAXIMUM_SWI_VALUE 0xFF +/// +/// Open: Need to make sure this kind of type cast will actually work. +/// May need an intermediate form w/ two VOID* arguments. I'll figure +/// that out when I start compiling. +/// +typedef +VOID +(EFIAPI *PCH_SMM_CLEAR_SOURCE) ( + CONST PCH_SMM_SOURCE_DESC * SrcDesc + ); + +/// +/// "DATABASE" RECORD +/// Linked list data structures +/// +#define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C') + +struct _DATABASE_RECORD { + UINT32 Signature; + LIST_ENTRY Link; + BOOLEAN Processed; + /// + /// Status and Enable bit description + /// + PCH_SMM_SOURCE_DESC SrcDesc; + + /// + /// Callback function + /// + EFI_SMM_HANDLER_ENTRY_POINT2 Callback; + PCH_SMM_CONTEXT ChildContext; + UINTN ContextSize; + + /// + /// Special handling hooks -- init them to NULL if unused/unneeded + /// + PCH_SMM_CLEAR_SOURCE ClearSource; + + /// + /// Functions required to make callback code general + /// + CONTEXT_FUNCTIONS ContextFunctions; + + /// + /// The protocol that this record dispatches + /// + PCH_SMM_PROTOCOL_TYPE ProtocolType; + + /// + /// Misc data for private usage + /// + PCH_SMM_MISC_DATA MiscData; + + /// + /// PCH SMI callback function + /// + PCH_SMI_CALLBACK_FUNCTIONS PchSmiCallback; + /// + /// Indicate the PCH SMI types. + /// + PCH_SMI_TYPES PchSmiType; +}; + +#define DATABASE_RECORD_FROM_LINK(_record) CR (_record, DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE) +#define DATABASE_RECORD_FROM_CHILDCONTEXT(_record) CR (_record, DATABASE_RECORD, ChildContext, DATABASE_RECORD_SIGNATURE) + +/// +/// HOOKING INTO THE ARCHITECTURE +/// +typedef +EFI_STATUS +(EFIAPI *PCH_SMM_GENERIC_REGISTER) ( + IN VOID **This, + IN VOID *DispatchFunction, + IN VOID *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ); +typedef +EFI_STATUS +(EFIAPI *PCH_SMM_GENERIC_UNREGISTER) ( + IN VOID **This, + IN EFI_HANDLE DispatchHandle + ); + +/// +/// Define a memory "stamp" equivalent in size and function to most of the protocols +/// +typedef struct { + PCH_SMM_GENERIC_REGISTER Register; + PCH_SMM_GENERIC_UNREGISTER Unregister; + UINTN Extra1; + UINTN Extra2; ///< may not need this one +} PCH_SMM_GENERIC_PROTOCOL; + +/** + Register a child SMI dispatch function with a parent SMM driver. + + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL instance. + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source. + @param[in] DispatchContext Pointer to the dispatch function's context. + @param[out] DispatchHandle Handle of dispatch function, for when interfacing + with the parent SMM driver, will be the address of linked + list link in the call back record. + + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create database record + @retval EFI_INVALID_PARAMETER The input parameter is invalid + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. +**/ +EFI_STATUS +EFIAPI +PchPiSmmCoreRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN PCH_SMM_CONTEXT *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchPiSmmCoreUnRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE *DispatchHandle + ); + + +/** + Unregister a child SMI source dispatch function with a parent SMM driver. + + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +EFIAPI +PchSmmCoreUnRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE *DispatchHandle + ); + +typedef union { + PCH_SMM_GENERIC_PROTOCOL Generic; + EFI_SMM_USB_DISPATCH2_PROTOCOL Usb; + EFI_SMM_SX_DISPATCH2_PROTOCOL Sx; + EFI_SMM_SW_DISPATCH2_PROTOCOL Sw; + EFI_SMM_GPI_DISPATCH2_PROTOCOL Gpi; + EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL PowerButton; + EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL PeriodicTimer; +} PCH_SMM_PROTOCOL; + +/// +/// Define a structure to help us identify the generic protocol +/// +#define PROTOCOL_SIGNATURE SIGNATURE_32 ('P', 'R', 'O', 'T') + +typedef struct { + UINTN Signature; + + PCH_SMM_PROTOCOL_TYPE Type; + EFI_GUID *Guid; + PCH_SMM_PROTOCOL Protocols; +} PCH_SMM_QUALIFIED_PROTOCOL; + +#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \ + CR ( \ + _generic, \ + PCH_SMM_QUALIFIED_PROTOCOL, \ + Protocols, \ + PROTOCOL_SIGNATURE \ + ) + +/// +/// Create private data for the protocols that we'll publish +/// +typedef struct { + LIST_ENTRY CallbackDataBase; + EFI_HANDLE SmiHandle; + EFI_HANDLE InstallMultProtHandle; + PCH_SMM_QUALIFIED_PROTOCOL Protocols[PCH_SMM_PROTOCOL_TYPE_MAX]; +} PRIVATE_DATA; + +extern PRIVATE_DATA mPrivateData; +extern UINT16 mAcpiBaseAddr; +extern UINT16 mTcoBaseAddr; + +/** + The internal function used to create and insert a database record + + @param[in] InsertRecord Record to insert to database. + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. +**/ +EFI_STATUS +SmmCoreInsertRecord ( + IN DATABASE_RECORD *NewRecord, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Get the Sleep type + + @param[in] Record No use + @param[out] Context The context that includes SLP_TYP bits to be filled +**/ +VOID +EFIAPI +SxGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ); + +/** + Register a child SMI source dispatch function for the specified software SMI. + + This service registers a function (DispatchFunction) which will be called when the software + SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On return, + DispatchHandle contains a unique handle which may be used later to unregister the function + using UnRegister(). + + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance. + @param[in] DispatchFunction Function to register for handler when the specified software + SMI is generated. + @param[in, out] RegisterContext Pointer to the dispatch function's context. + The caller fills this context in before calling + the register function to indicate to the register + function which Software SMI input value the + dispatch function should be invoked for. + @param[out] DispatchHandle Handle generated by the dispatcher to track the + function instance. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_DEVICE_ERROR The SW driver was unable to enable the SMI source. + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI input value + is not within a valid range or is already in use. + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM) to manage this + child. + @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be assigned + for this dispatch. +**/ +EFI_STATUS +EFIAPI +PchSwSmiRegister ( + IN EFI_SMM_SW_DISPATCH2_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function for the specified software SMI. + + This service removes the handler associated with DispatchHandle so that it will no longer be + called in response to a software SMI. + + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully unregistered. + @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid. +**/ +EFI_STATUS +EFIAPI +PchSwSmiUnRegister ( + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +/** + Init required protocol for Pch Sw Dispatch protocol. +**/ +VOID +PchSwDispatchInit ( + VOID + ); + +/** + Check whether sleep type of two contexts match + + @param[in] Context1 Context 1 that includes sleep type 1 + @param[in] Context2 Context 2 that includes sleep type 2 + + @retval FALSE Sleep types match + @retval TRUE Sleep types don't match +**/ +BOOLEAN +EFIAPI +SxCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ); + +/** + Update the elapsed time from the Interval data of DATABASE_RECORD + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] HwContext The Context to be updated. +**/ +VOID +EFIAPI +PeriodicTimerGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ); + +/** + Check whether Periodic Timer of two contexts match + + @param[in] Context1 Context 1 that includes Periodic Timer 1 + @param[in] Context2 Context 2 that includes Periodic Timer 2 + + @retval FALSE Periodic Timer match + @retval TRUE Periodic Timer don't match +**/ +BOOLEAN +EFIAPI +PeriodicTimerCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ); + +/** + Gather the CommBuffer information of SmmPeriodicTimerDispatch2. + + @param[in] Record No use + @param[out] CommBuffer Point to the CommBuffer structure + @param[out] CommBufferSize Point to the Size of CommBuffer structure +**/ +VOID +EFIAPI +PeriodicTimerGetCommBuffer ( + IN DATABASE_RECORD *Record, + OUT VOID **CommBuffer, + OUT UINTN *CommBufferSize + ); + +/** + Get the power button status. + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] Context Calling context from the hardware, will be updated with the current power button status. +**/ +VOID +EFIAPI +PowerButtonGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ); + +/** + Check whether Power Button status of two contexts match + + @param[in] Context1 Context 1 that includes Power Button status 1 + @param[in] Context2 Context 2 that includes Power Button status 2 + + @retval FALSE Power Button status match + @retval TRUE Power Button status don't match +**/ +BOOLEAN +EFIAPI +PowerButtonCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ); + +/** + This function is responsible for calculating and enabling any timers that are required + to dispatch messages to children. The SrcDesc argument isn't acutally used. + + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC instance. +**/ +VOID +EFIAPI +PchSmmPeriodicTimerClearSource ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + This services returns the next SMI tick period that is supported by the chipset. + The order returned is from longest to shortest interval period. + + @param[in] This Pointer to the EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance. + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter SMI interval period that is supported by the child. + + @retval EFI_SUCCESS The service returned successfully. + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is invalid. +**/ +EFI_STATUS +PchSmmPeriodicTimerDispatchGetNextShorterInterval ( + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This, + IN OUT UINT64 **SmiTickInterval + ); + +/** + Install PCH SMM periodic timer control protocol + + @param[in] Handle handle for this driver + + @retval EFI_SUCCESS Driver initialization completed successfully +**/ +EFI_STATUS +EFIAPI +InstallPchSmmPeriodicTimerControlProtocol ( + IN EFI_HANDLE Handle + ); + +/** + Install protocols of PCH specifics SMI types, including + PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC SMI types. + + @retval the result of protocol installation +**/ +EFI_STATUS +InstallPchSmiDispatchProtocols ( + VOID + ); + +/** + The function to dispatch all callback function of PCH SMI types. + + @retval EFI_SUCCESS Function successfully completed + @retval EFI_UNSUPPORTED no +**/ +EFI_STATUS +PchSmiTypeCallbackDispatcher ( + IN DATABASE_RECORD *Record + ); + +/** + The register function used to register SMI handler of IoTrap event. + This is internal function and only used by Iotrap module. + + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[in] IoTrapIndex Index number of IOTRAP register + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. +**/ +EFI_STATUS +PchInternalIoTrapSmiRegister ( + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + IN UINTN IoTrapIndex, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +PchInternalIoTrapSmiUnRegister ( + IN EFI_HANDLE DispatchHandle + ); + +/** + Register an eSPI SMI handler based on the type + + @param[in] DispatchFunction Callback in an event of eSPI SMI + @param[in] PchSmiTypes The eSPI type published by PchSmiDispatch + @param[out] DispatchHandle The callback handle + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS Registration is successful. +**/ +EFI_STATUS +PchInternalEspiSmiRegister ( + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + IN PCH_SMI_TYPES PchSmiTypes, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister an eSPI SMI handler + + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +PchInternalEspiSmiUnRegister ( + IN EFI_HANDLE DispatchHandle + ); + +/** + The internal function used to create and insert a database record + for SMI record of Pch Smi types. + + @param[in] SrcDesc The pointer to the SMI source description + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[in] PchSmiType Specific SMI type of PCH SMI + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. +**/ +EFI_STATUS +PchSmiRecordInsert ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc, + IN PCH_SMI_CALLBACK_FUNCTIONS DispatchFunction, + IN PCH_SMI_TYPES PchSmiType, + OUT EFI_HANDLE *DispatchHandle + ); + +extern CONST PCH_SMM_SOURCE_DESC mSrcDescSerialIrq; +extern PCH_SMM_SOURCE_DESC mSrcDescLpcBiosWp; + +/** + Clear the TCO SMI status bit and block after the SMI handling is done + + @param[in] SrcDesc Pointer to the PCH SMI source description table + +**/ +VOID +EFIAPI +PchTcoSmiClearSourceAndBlock ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Clear the TCO SMI status bit after the SMI handling is done + + @param[in] SrcDesc Pointer to the PCH SMI source description table + +**/ +VOID +EFIAPI +PchTcoSmiClearSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Initialize Source descriptor structure + + @param[in] SrcDesc Pointer to the PCH SMI source description table +**/ +VOID +EFIAPI +NullInitSourceDesc ( + PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + The register function used to register SMI handler of GPI SMI event. + + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. + @param[in] DispatchFunction Function to register for handler when the specified GPI causes an SMI. + @param[in] RegisterContext Pointer to the dispatch function's context. + The caller fills this context in before calling + the register function to indicate to the register + function the GPI(s) for which the dispatch function + should be invoked. + @param[out] DispatchHandle Handle generated by the dispatcher to track the + function instance. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_ACCESS_DENIED Register is not allowed + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The GPI input value + is not within valid range. + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM) to manage this child. +**/ +EFI_STATUS +EFIAPI +PchGpiSmiRegister ( + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN EFI_SMM_GPI_REGISTER_CONTEXT *RegisterContext, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a GPI SMI source dispatch function with a parent SMM driver + + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +EFIAPI +PchGpiSmiUnRegister ( + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore.c new file mode 100644 index 0000000000..cb889b5ce3 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore.c @@ -0,0 +1,905 @@ +/** @file + This driver is responsible for the registration of child drivers + and the abstraction of the PCH SMI sources. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmm.h" +#include "PchSmmHelpers.h" +#include "PchSmiHelper.h" +#include <Library/SmiHandlerProfileLib.h> +#include <Register/GpioRegs.h> +#include <Register/PmcRegs.h> +#include <Register/TcoRegs.h> +#include <Register/RtcRegs.h> + +#define PROGRESS_CODE_S3_SUSPEND_START PcdGet32 (PcdProgressCodeS3SuspendStart) +// +// MODULE / GLOBAL DATA +// +// Module variables used by the both the main dispatcher and the source dispatchers +// Declared in PchSmm.h +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mAcpiBaseAddr; +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mTcoBaseAddr; +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mReadyToLock; +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mS3SusStart; +GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mNumOfRootPorts; + +GLOBAL_REMOVE_IF_UNREFERENCED PRIVATE_DATA mPrivateData = { + { + NULL, + NULL + }, // CallbackDataBase linked list head + NULL, // EFI handle returned when calling InstallMultipleProtocolInterfaces + NULL, // + { // protocol arrays + // + // elements within the array + // + { + PROTOCOL_SIGNATURE, + UsbType, + &gEfiSmmUsbDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister + }} + }, + { + PROTOCOL_SIGNATURE, + SxType, + &gEfiSmmSxDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister + }} + }, + { + PROTOCOL_SIGNATURE, + SwType, + &gEfiSmmSwDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchSwSmiRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchSwSmiUnRegister, + (UINTN) MAXIMUM_SWI_VALUE + }} + }, + { + PROTOCOL_SIGNATURE, + GpiType, + &gEfiSmmGpiDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchGpiSmiRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchGpiSmiUnRegister, + (UINTN) PCH_GPIO_NUM_SUPPORTED_GPIS + }} + }, + { + PROTOCOL_SIGNATURE, + PowerButtonType, + &gEfiSmmPowerButtonDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister + }} + }, + { + PROTOCOL_SIGNATURE, + PeriodicTimerType, + &gEfiSmmPeriodicTimerDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister, + (UINTN) PchSmmPeriodicTimerDispatchGetNextShorterInterval + }} + }, + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED CONTEXT_FUNCTIONS mContextFunctions[PCH_SMM_PROTOCOL_TYPE_MAX] = { + { + NULL, + NULL, + NULL + }, + { + SxGetContext, + SxCmpContext, + NULL + }, + { + NULL, + NULL, + NULL + }, + { + NULL, + NULL, + NULL + }, + { + PowerButtonGetContext, + PowerButtonCmpContext, + NULL + }, + { + PeriodicTimerGetContext, + PeriodicTimerCmpContext, + PeriodicTimerGetCommBuffer + }, +}; + +// +// PROTOTYPES +// +// Functions use only in this file +// +EFI_STATUS +EFIAPI +PchSmmCoreDispatcher ( + IN EFI_HANDLE SmmImageHandle, + IN CONST VOID *PchSmmCore, OPTIONAL + IN OUT VOID *CommunicationBuffer, + IN OUT UINTN *SourceSize + ); + +// +// FUNCTIONS +// +/** + SMM ready to lock notification event handler. + + @param Protocol Points to the protocol's unique identifier + @param Interface Points to the interface instance + @param Handle The handle on which the interface was installed + + @retval EFI_SUCCESS SmmReadyToLockCallback runs successfully + +**/ +EFI_STATUS +EFIAPI +SmmReadyToLockCallback ( + IN CONST EFI_GUID *Protocol, + IN VOID *Interface, + IN EFI_HANDLE Handle + ) +{ + mReadyToLock = TRUE; + + return EFI_SUCCESS; +} + +/** + <b>PchSmiDispatcher SMM Module Entry Point</b>\n + - <b>Introduction</b>\n + The PchSmiDispatcher module is an SMM driver which provides SMI handler registration + services for PCH generated SMIs. + + - <b>Details</b>\n + This module provides SMI handler registration servicies for PCH SMIs. + NOTE: All the register/unregister functions will be locked after SMM ready to boot signal event. + Please make sure no handler is installed after that. + + - @pre + - EFI_SMM_BASE2_PROTOCOL + - Documented in the System Management Mode Core Interface Specification + - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL + - Documented in the UEFI 2.0 Specification and above + - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL + - This is to ensure that PCI MMIO and IO resource has been prepared and available for this driver to allocate. + - EFI_SMM_CPU_PROTOCOL + + - @result + The PchSmiDispatcher driver produces: + - EFI_SMM_USB_DISPATCH2_PROTOCOL + - EFI_SMM_SX_DISPATCH2_PROTOCOL + - EFI_SMM_SW_DISPATCH2_PROTOCOL + - EFI_SMM_GPI_DISPATCH2_PROTOCOL + - EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL + - EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL + - EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL + - @link _PCH_SMM_IO_TRAP_CONTROL_PROTOCOL PCH_SMM_IO_TRAP_CONTROL_PROTOCOL @endlink + - @link _PCH_PCIE_SMI_DISPATCH_PROTOCOL PCH_PCIE_SMI_DISPATCH_PROTOCOL @endlink + - @link _PCH_TCO_SMI_DISPATCH_PROTOCOL PCH_TCO_SMI_DISPATCH_PROTOCOL @endlink + - @link _PCH_ACPI_SMI_DISPATCH_PROTOCOL PCH_ACPI_SMI_DISPATCH_PROTOCOL @endlink + - @link _PCH_SMI_DISPATCH_PROTOCOL PCH_SMI_DISPATCH_PROTOCOL @endlink + + @param[in] ImageHandle Pointer to the loaded image protocol for this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_SUCCESS PchSmmDispatcher Initialization completed. +**/ +EFI_STATUS +EFIAPI +InitializePchSmmDispatcher ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + VOID *SmmReadyToLockRegistration; + + mS3SusStart = FALSE; + + PchSmiDispatchUpdateDescriptors (); + + // + // Access ACPI Base Addresses Register + // + mAcpiBaseAddr = PmcGetAcpiBase (); + ASSERT (mAcpiBaseAddr != 0); + + // + // Access TCO Base Addresses Register + // + PchTcoBaseGet (&mTcoBaseAddr); + ASSERT (mTcoBaseAddr != 0); + + mNumOfRootPorts = GetPchMaxPciePortNum (); + + // + // Register a callback function to handle subsequent SMIs. This callback + // will be called by SmmCoreDispatcher. + // + Status = gSmst->SmiHandlerRegister (PchSmmCoreDispatcher, NULL, &mPrivateData.SmiHandle); + ASSERT_EFI_ERROR (Status); + // + // Initialize Callback DataBase + // + InitializeListHead (&mPrivateData.CallbackDataBase); + + // + // Enable SMIs on the PCH now that we have a callback + // + PchSmmInitHardware (); + + // + // Install and initialize all the needed protocols + // + PchSwDispatchInit (); + PchSmmPublishDispatchProtocols (); + InstallPchSmiDispatchProtocols (); + InstallPchSmmPeriodicTimerControlProtocol (mPrivateData.InstallMultProtHandle); + + // + // Register EFI_SMM_READY_TO_LOCK_PROTOCOL_GUID notify function. + // + Status = gSmst->SmmRegisterProtocolNotify ( + &gEfiSmmReadyToLockProtocolGuid, + SmmReadyToLockCallback, + &SmmReadyToLockRegistration + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +/** + The internal function used to create and insert a database record + + @param[in] InsertRecord Record to insert to database. + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. +**/ +EFI_STATUS +SmmCoreInsertRecord ( + IN DATABASE_RECORD *NewRecord, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + if ((NewRecord == NULL) || + (NewRecord->Signature != DATABASE_RECORD_SIGNATURE)) + { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Status = gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof (DATABASE_RECORD), (VOID **) &Record); + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + CopyMem (Record, NewRecord, sizeof (DATABASE_RECORD)); + + // + // After ensuring the source of event is not null, we will insert the record into the database + // + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + + // + // Child's handle will be the address linked list link in the record + // + *DispatchHandle = (EFI_HANDLE) (&Record->Link); + + return EFI_SUCCESS; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchPiSmmCoreUnRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE *DispatchHandle + ) +{ + DATABASE_RECORD *RecordToDelete; + EFI_STATUS Status; + PCH_SMM_QUALIFIED_PROTOCOL *Qualified; + + Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This); + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle); + Status = PchSmmCoreUnRegister (NULL, DispatchHandle); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileUnregisterHandler ( + Qualified->Guid, + RecordToDelete->Callback, + &RecordToDelete->ChildContext, + RecordToDelete->ContextSize + ); + } + return Status; +} + +/** + Register a child SMI dispatch function with a parent SMM driver. + + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL instance. + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source. + @param[in] DispatchContext Pointer to the dispatch function's context. + @param[out] DispatchHandle Handle of dispatch function, for when interfacing + with the parent SMM driver, will be the address of linked + list link in the call back record. + + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create database record + @retval EFI_INVALID_PARAMETER The input parameter is invalid + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. +**/ +EFI_STATUS +EFIAPI +PchPiSmmCoreRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN PCH_SMM_CONTEXT *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD Record; + PCH_SMM_QUALIFIED_PROTOCOL *Qualified; + PCH_SMM_SOURCE_DESC NullSourceDesc; + + // + // Initialize NullSourceDesc + // + NullInitSourceDesc (&NullSourceDesc); + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + ZeroMem (&Record, sizeof (DATABASE_RECORD)); + + // + // Gather information about the registration request + // + Record.Callback = DispatchFunction; + + Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This); + + Record.ProtocolType = Qualified->Type; + + Record.ContextFunctions = mContextFunctions[Qualified->Type]; + // + // Perform linked list housekeeping + // + Record.Signature = DATABASE_RECORD_SIGNATURE; + + switch (Qualified->Type) { + // + // By the end of this switch statement, we'll know the + // source description the child is registering for + // + case UsbType: + Record.ContextSize = sizeof (EFI_SMM_USB_REGISTER_CONTEXT); + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize); + // + // Check the validity of Context Type + // + if ((Record.ChildContext.Usb.Type < UsbLegacy) || (Record.ChildContext.Usb.Type > UsbWake)) { + return EFI_INVALID_PARAMETER; + } + + PchSmmUsbUpdateDescriptors (); + MapUsbToSrcDesc (DispatchContext, &Record.SrcDesc); + Record.ClearSource = NULL; + // + // use default clear source function + // + break; + + case SxType: + Record.ContextSize = sizeof (EFI_SMM_SX_REGISTER_CONTEXT); + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize); + // + // Check the validity of Context Type and Phase + // + if ((Record.ChildContext.Sx.Type < SxS0) || + (Record.ChildContext.Sx.Type >= EfiMaximumSleepType) || + (Record.ChildContext.Sx.Phase < SxEntry) || + (Record.ChildContext.Sx.Phase >= EfiMaximumPhase) + ) { + return EFI_INVALID_PARAMETER; + } + + CopyMem (&Record.SrcDesc, &mSxSourceDesc, sizeof (PCH_SMM_SOURCE_DESC)); + Record.ClearSource = NULL; + // + // use default clear source function + // + break; + + case PowerButtonType: + Record.ContextSize = sizeof (EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT); + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize); + // + // Check the validity of Context Phase + // + if ((Record.ChildContext.PowerButton.Phase < EfiPowerButtonEntry) || + (Record.ChildContext.PowerButton.Phase > EfiPowerButtonExit)) + { + return EFI_INVALID_PARAMETER; + } + + CopyMem (&Record.SrcDesc, &mPowerButtonSourceDesc, sizeof (PCH_SMM_SOURCE_DESC)); + Record.ClearSource = NULL; + // + // use default clear source function + // + break; + + case PeriodicTimerType: + Record.ContextSize = sizeof (EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT); + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize); + // + // Check the validity of timer value + // + if (DispatchContext->PeriodicTimer.SmiTickInterval <= 0) { + return EFI_INVALID_PARAMETER; + } + + MapPeriodicTimerToSrcDesc (DispatchContext, &Record.SrcDesc); + Record.MiscData.TimerSmiEnabled = TRUE; + Record.ClearSource = PchSmmPeriodicTimerClearSource; + break; + + default: + return EFI_INVALID_PARAMETER; + break; + } + + if (CompareSources (&Record.SrcDesc, &NullSourceDesc)) { + return EFI_INVALID_PARAMETER; + } + + // + // After ensuring the source of event is not null, we will insert the record into the database + // Child's handle will be the address linked list link in the record + // + Status = SmmCoreInsertRecord ( + &Record, + DispatchHandle + ); + ASSERT_EFI_ERROR (Status); + + if (Record.ClearSource == NULL) { + // + // Clear the SMI associated w/ the source using the default function + // + PchSmmClearSource (&Record.SrcDesc); + } else { + // + // This source requires special handling to clear + // + Record.ClearSource (&Record.SrcDesc); + } + + PchSmmEnableSource (&Record.SrcDesc); + SmiHandlerProfileRegisterHandler ( + Qualified->Guid, + DispatchFunction, + (UINTN)RETURN_ADDRESS (0), + DispatchContext, + Record.ContextSize + ); + + return EFI_SUCCESS; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver. + + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +EFIAPI +PchSmmCoreUnRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + BOOLEAN NeedClearEnable; + UINTN DescIndex; + DATABASE_RECORD *RecordToDelete; + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + + if (DispatchHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle); + + // + // Take the entry out of the linked list + // + if (RecordToDelete->Link.ForwardLink == (LIST_ENTRY *) EFI_BAD_POINTER) { + return EFI_INVALID_PARAMETER; + } + + RemoveEntryList (&RecordToDelete->Link); + + // + // Loop through all the souces in record linked list to see if any source enable is equal. + // If any source enable is equal, we do not want to disable it. + // + for (DescIndex = 0; DescIndex < NUM_EN_BITS; ++DescIndex) { + if (IS_BIT_DESC_NULL (RecordToDelete->SrcDesc.En[DescIndex])) { + continue; + } + NeedClearEnable = TRUE; + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + if (IsBitEqualToAnySourceEn (&RecordToDelete->SrcDesc.En[DescIndex], &RecordInDb->SrcDesc)) { + NeedClearEnable = FALSE; + break; + } + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + } + if (NeedClearEnable == FALSE) { + continue; + } + WriteBitDesc (&RecordToDelete->SrcDesc.En[DescIndex], 0, FALSE); + } + Status = gSmst->SmmFreePool (RecordToDelete); + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + return Status; + } + return EFI_SUCCESS; +} + +/** + This function clears the pending SMI status before set EOS. + NOTE: This only clears the pending SMI with known reason. + Please do not clear unknown pending SMI status since that will hide potential issues. + + @param[in] SmiStsValue SMI status + @param[in] SciEn Sci Enable status +**/ +STATIC +VOID +ClearPendingSmiStatus ( + UINT32 SmiStsValue, + BOOLEAN SciEn + ) +{ + // + // Clear NewCentury status if it's not handled. + // + if (SmiStsValue & B_ACPI_IO_SMI_STS_TCO) { + if (IoRead16 (mTcoBaseAddr + R_TCO_IO_TCO1_STS) & B_TCO_IO_TCO1_STS_NEWCENTURY) { + PchTcoSmiClearSourceAndBlock (&mSrcDescNewCentury); + } + } + // Clear PWRBTNOR_STS if it's not handled. + // + if (IoRead16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS) & B_ACPI_IO_PM1_STS_PRBTNOR) { + IoWrite16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS, B_ACPI_IO_PM1_STS_PRBTNOR); + } + // + // Clear WADT_STS if this is triggered by WADT timer. + // + if (!SciEn) { + if ((IoRead32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_EN_127_96) & B_ACPI_IO_GPE0_EN_127_96_WADT) && + (IoRead32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96) & B_ACPI_IO_GPE0_STS_127_96_WADT)) { + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96, B_ACPI_IO_GPE0_STS_127_96_WADT); + } + } + // + // Clear GPIO_UNLOCK_SMI_STS in case it is set as GPIO Unlock SMI is not supported + // + if (SmiStsValue & B_ACPI_IO_SMI_STS_GPIO_UNLOCK) { + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_SMI_STS, B_ACPI_IO_SMI_STS_GPIO_UNLOCK); + } +} + +/** + The callback function to handle subsequent SMIs. This callback will be called by SmmCoreDispatcher. + + @param[in] SmmImageHandle Not used + @param[in] PchSmmCore Not used + @param[in, out] CommunicationBuffer Not used + @param[in, out] SourceSize Not used + + @retval EFI_SUCCESS Function successfully completed +**/ +EFI_STATUS +EFIAPI +PchSmmCoreDispatcher ( + IN EFI_HANDLE SmmImageHandle, + IN CONST VOID *PchSmmCore, + IN OUT VOID *CommunicationBuffer, + IN OUT UINTN *SourceSize + ) +{ + // + // Used to prevent infinite loops + // + UINTN EscapeCount; + + BOOLEAN ContextsMatch; + BOOLEAN EosSet; + BOOLEAN SxChildWasDispatched; + + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + DATABASE_RECORD *RecordToExhaust; + LIST_ENTRY *LinkToExhaust; + + PCH_SMM_CONTEXT Context; + VOID *CommBuffer; + UINTN CommBufferSize; + + EFI_STATUS Status; + BOOLEAN SciEn; + UINT32 SmiEnValue; + UINT32 SmiStsValue; + UINT8 Port74Save; + UINT8 Port76Save; + + PCH_SMM_SOURCE_DESC ActiveSource; + + // + // Initialize ActiveSource + // + NullInitSourceDesc (&ActiveSource); + + EscapeCount = 3; + ContextsMatch = FALSE; + EosSet = FALSE; + SxChildWasDispatched = FALSE; + Status = EFI_SUCCESS; + + // + // Save IO index registers + // @note: Save/Restore port 70h directly might break NMI_EN# setting, + // then save/restore 74h/76h instead. + // @note: CF8 is not saved. Prefer method is to use MMIO instead of CF8 + // + Port76Save = IoRead8 (R_RTC_IO_EXT_INDEX_ALT); + Port74Save = IoRead8 (R_RTC_IO_INDEX_ALT); + + if (!IsListEmpty (&mPrivateData.CallbackDataBase)) { + // + // We have children registered w/ us -- continue + // + while ((!EosSet) && (EscapeCount > 0)) { + EscapeCount--; + + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + + // + // Cache SciEn, SmiEnValue and SmiStsValue to determine if source is active + // + SciEn = PchSmmGetSciEn (); + SmiEnValue = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); + SmiStsValue = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS)); + + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + + // + // look for the first active source + // + if (!SourceIsActive (&RecordInDb->SrcDesc, SciEn, SmiEnValue, SmiStsValue)) { + // + // Didn't find the source yet, keep looking + // + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + + // + // if it's the last one, try to clear EOS + // + if (IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + // + // Clear pending SMI status before EOS + // + ClearPendingSmiStatus (SmiStsValue, SciEn); + EosSet = PchSmmSetAndCheckEos (); + } + } else { + // + // We found a source. If this is a sleep type, we have to go to + // appropriate sleep state anyway.No matter there is sleep child or not + // + if (RecordInDb->ProtocolType == SxType) { + SxChildWasDispatched = TRUE; + } + // + // "cache" the source description and don't query I/O anymore + // + CopyMem ((VOID *) &ActiveSource, (VOID *) &(RecordInDb->SrcDesc), sizeof (PCH_SMM_SOURCE_DESC)); + LinkToExhaust = LinkInDb; + + // + // exhaust the rest of the queue looking for the same source + // + while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) { + RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust); + // + // RecordToExhaust->Link might be removed (unregistered) by Callback function, and then the + // system will hang in ASSERT() while calling GetNextNode(). + // To prevent the issue, we need to get next record in DB here (before Callback function). + // + LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, &RecordToExhaust->Link); + + if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) { + // + // These source descriptions are equal, so this callback should be + // dispatched. + // + if (RecordToExhaust->ContextFunctions.GetContext != NULL) { + // + // This child requires that we get a calling context from + // hardware and compare that context to the one supplied + // by the child. + // + ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL); + + // + // Make sure contexts match before dispatching event to child + // + RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context); + ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext); + + } else { + // + // This child doesn't require any more calling context beyond what + // it supplied in registration. Simply pass back what it gave us. + // + Context = RecordToExhaust->ChildContext; + ContextsMatch = TRUE; + } + + if (ContextsMatch) { + if (RecordToExhaust->ProtocolType == PchSmiDispatchType) { + // + // For PCH SMI dispatch protocols + // + PchSmiTypeCallbackDispatcher (RecordToExhaust); + } else { + if ((RecordToExhaust->ProtocolType == SxType) && (Context.Sx.Type == SxS3) && (Context.Sx.Phase == SxEntry) && !mS3SusStart) { + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PROGRESS_CODE_S3_SUSPEND_START); + mS3SusStart = TRUE; + } + // + // For EFI standard SMI dispatch protocols + // + if (RecordToExhaust->Callback != NULL) { + if (RecordToExhaust->ContextFunctions.GetCommBuffer != NULL) { + // + // This callback function needs CommBuffer and CommBufferSize. + // Get those from child and then pass to callback function. + // + RecordToExhaust->ContextFunctions.GetCommBuffer (RecordToExhaust, &CommBuffer, &CommBufferSize); + } else { + // + // Child doesn't support the CommBuffer and CommBufferSize. + // Just pass NULL value to callback function. + // + CommBuffer = NULL; + CommBufferSize = 0; + } + + PERF_START_EX (NULL, "SmmFunction", NULL, AsmReadTsc (), RecordToExhaust->ProtocolType); + RecordToExhaust->Callback ((EFI_HANDLE) & RecordToExhaust->Link, &Context, CommBuffer, &CommBufferSize); + PERF_END_EX (NULL, "SmmFunction", NULL, AsmReadTsc (), RecordToExhaust->ProtocolType); + if (RecordToExhaust->ProtocolType == SxType) { + SxChildWasDispatched = TRUE; + } + } else { + ASSERT (FALSE); + } + } + } + } + } + + if (RecordInDb->ClearSource == NULL) { + // + // Clear the SMI associated w/ the source using the default function + // + PchSmmClearSource (&ActiveSource); + } else { + // + // This source requires special handling to clear + // + RecordInDb->ClearSource (&ActiveSource); + } + // + // Clear pending SMI status before EOS + // + ClearPendingSmiStatus (SmiStsValue, SciEn); + // + // Also, try to clear EOS + // + EosSet = PchSmmSetAndCheckEos (); + // + // Queue is empty, reset the search + // + break; + } + } + } + } + // + // Restore IO index registers + // @note: Save/Restore port 70h directly might break NMI_EN# setting, + // then save/restore 74h/76h instead. + // + IoWrite8 (R_RTC_IO_EXT_INDEX_ALT, Port76Save); + IoWrite8 (R_RTC_IO_INDEX_ALT, Port74Save); + + return Status; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c new file mode 100644 index 0000000000..4c59c07bac --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c @@ -0,0 +1,255 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Gpi dispatch protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmm.h" +#include "PchSmmHelpers.h" +#include <Library/SmiHandlerProfileLib.h> +#include <Register/GpioRegs.h> +#include <Register/PmcRegs.h> + +// +// Structure for GPI SMI is a template which needs to have +// GPI Smi bit offset and Smi Status & Enable registers updated (accordingly +// to choosen group and pad number) after adding it to SMM Callback database +// + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mPchGpiSourceDescTemplate = { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + GPIO_ADDR_TYPE, {0x0} + }, + S_GPIO_PCR_GP_SMI_STS, 0x0, + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_GPIO_SMI + } +}; + +/** + The register function used to register SMI handler of GPI SMI event. + + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. + @param[in] DispatchFunction Function to register for handler when the specified GPI causes an SMI. + @param[in] RegisterContext Pointer to the dispatch function's context. + The caller fills this context in before calling + the register function to indicate to the register + function the GPI(s) for which the dispatch function + should be invoked. + @param[out] DispatchHandle Handle generated by the dispatcher to track the + function instance. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_ACCESS_DENIED Register is not allowed + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The GPI input value + is not within valid range. + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM) to manage this child. +**/ +EFI_STATUS +EFIAPI +PchGpiSmiRegister ( + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN EFI_SMM_GPI_REGISTER_CONTEXT *RegisterContext, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD Record; + GPIO_PAD GpioPad; + UINT8 GpiSmiBitOffset; + UINT32 GpiHostSwOwnRegAddress; + UINT32 GpiSmiStsRegAddress; + UINT32 Data32And; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = GpioGetPadAndSmiRegs ( + (UINT32) RegisterContext->GpiNum, + &GpioPad, + &GpiSmiBitOffset, + &GpiHostSwOwnRegAddress, + &GpiSmiStsRegAddress + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem (&Record, sizeof (DATABASE_RECORD)); + + // + // Gather information about the registration request + // + Record.Callback = DispatchFunction; + Record.ChildContext.Gpi = *RegisterContext; + Record.ProtocolType = GpiType; + Record.Signature = DATABASE_RECORD_SIGNATURE; + + CopyMem (&Record.SrcDesc, &mPchGpiSourceDescTemplate, sizeof (PCH_SMM_SOURCE_DESC) ); + + Record.SrcDesc.Sts[0].Reg.Data.raw = GpiSmiStsRegAddress; // GPI SMI Status register + Record.SrcDesc.Sts[0].Bit = GpiSmiBitOffset; // Bit position for selected pad + + // + // Insert GpiSmi handler to PchSmmCore database + // + *DispatchHandle = NULL; + + Status = SmmCoreInsertRecord ( + &Record, + DispatchHandle + ); + ASSERT_EFI_ERROR (Status); + + SmiHandlerProfileRegisterHandler ( + &gEfiSmmGpiDispatch2ProtocolGuid, + (EFI_SMM_HANDLER_ENTRY_POINT2) DispatchFunction, + (UINTN)RETURN_ADDRESS (0), + RegisterContext, + sizeof(*RegisterContext) + ); + + // + // Enable GPI SMI + // HOSTSW_OWN with respect to generating GPI SMI has negative logic: + // - 0 (ACPI mode) - GPIO pad will be capable of generating SMI/NMI/SCI + // - 1 (GPIO mode) - GPIO pad will not generate SMI/NMI/SCI + // + Data32And = (UINT32)~(1u << GpiSmiBitOffset); + MmioAnd32 (GpiHostSwOwnRegAddress, Data32And); + + return EFI_SUCCESS; +} + +/** + Unregister a GPI SMI source dispatch function with a parent SMM driver + + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +EFIAPI +PchGpiSmiUnRegister ( + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *RecordToDelete; + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + GPIO_PAD GpioPad; + UINT8 GpiSmiBitOffset; + UINT32 GpiHostSwOwnRegAddress; + UINT32 GpiSmiStsRegAddress; + UINT32 Data32Or; + UINT32 Data32And; + BOOLEAN DisableGpiSmiSource; + + + if (DispatchHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle); + if ((RecordToDelete->Signature != DATABASE_RECORD_SIGNATURE) || + (RecordToDelete->ProtocolType != GpiType)) { + return EFI_INVALID_PARAMETER; + } + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + DisableGpiSmiSource = TRUE; + // + // Loop through all sources in record linked list to see if any other GPI SMI + // is installed on the same pin. If no then disable GPI SMI capability on this pad + // + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + // + // If this is the record to delete skip it + // + if (RecordInDb == RecordToDelete) { + continue; + } + // + // Check if record is GPI SMI type + // + if (RecordInDb->ProtocolType == GpiType) { + // + // Check if same GPIO pad is the source of this SMI + // + if (RecordInDb->ChildContext.Gpi.GpiNum == RecordToDelete->ChildContext.Gpi.GpiNum) { + DisableGpiSmiSource = FALSE; + break; + } + } + } + + if (DisableGpiSmiSource) { + GpioGetPadAndSmiRegs ( + (UINT32) RecordToDelete->ChildContext.Gpi.GpiNum, + &GpioPad, + &GpiSmiBitOffset, + &GpiHostSwOwnRegAddress, + &GpiSmiStsRegAddress + ); + + Data32Or = 1u << GpiSmiBitOffset; + Data32And = 0xFFFFFFFF; + MmioOr32 (GpiHostSwOwnRegAddress, Data32Or); + } + + + RemoveEntryList (&RecordToDelete->Link); + ZeroMem (RecordToDelete, sizeof (DATABASE_RECORD)); + Status = gSmst->SmmFreePool (RecordToDelete); + + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + return Status; + } + SmiHandlerProfileUnregisterHandler ( + &gEfiSmmGpiDispatch2ProtocolGuid, + RecordToDelete->Callback, + &RecordToDelete->ChildContext, + RecordToDelete->ContextSize + ); + return EFI_SUCCESS; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c new file mode 100644 index 0000000000..724a383855 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c @@ -0,0 +1,332 @@ +/** @file + Helper functions for PCH SMM dispatcher. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#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. + /// + } + } + } +} + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h new file mode 100644 index 0000000000..93ab8564ff --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h @@ -0,0 +1,163 @@ +/** @file + Helper functions for PCH SMM + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef PCH_SMM_HELPERS_H +#define PCH_SMM_HELPERS_H + +#include "PchSmm.h" +#include "PchxSmmHelpers.h" +// +// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SUPPORT / HELPER FUNCTIONS (PCH version-independent) +// + +/** + Publish SMI Dispatch protocols. + + +**/ +VOID +PchSmmPublishDispatchProtocols ( + VOID + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + Performs update of SmmUsb descriptors with values that have to be evaluated during runtime. +**/ +VOID +PchSmmUsbUpdateDescriptors ( + VOID + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c new file mode 100644 index 0000000000..3078d0c696 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c @@ -0,0 +1,670 @@ +/** @file + File to contain all the hardware specific stuff for the Periodical Timer dispatch protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include <Protocol/PchSmmPeriodicTimerControl.h> +#include <Library/PmcPrivateLib.h> + +// +// There is only one instance for PeriodicTimerCommBuffer. +// It's safe in SMM since there is no re-entry for the function. +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_PERIODIC_TIMER_CONTEXT mPchPeriodicTimerCommBuffer; + +typedef enum { + PERIODIC_TIMER= 0, + SWSMI_TIMER, + NUM_TIMERS +} SUPPORTED_TIMER; + +typedef struct _TIMER_INTERVAL { + UINT64 Interval; + UINT8 AssociatedTimer; +} TIMER_INTERVAL; + +#define NUM_INTERVALS 8 + +// +// Time constants, in 100 nano-second units +// +#define TIME_64s 640000000 ///< 64 s +#define TIME_32s 320000000 ///< 32 s +#define TIME_16s 160000000 ///< 16 s +#define TIME_8s 80000000 ///< 8 s +#define TIME_64ms 640000 ///< 64 ms +#define TIME_32ms 320000 ///< 32 ms +#define TIME_16ms 160000 ///< 16 ms +#define TIME_1_5ms 15000 ///< 1.5 ms + +typedef enum { + INDEX_TIME_64s = 0, + INDEX_TIME_32s, + INDEX_TIME_16s, + INDEX_TIME_8s, + INDEX_TIME_64ms, + INDEX_TIME_32ms, + INDEX_TIME_16ms, + INDEX_TIME_1_5ms, + INDEX_TIME_MAX +} TIMER_INTERVAL_INDEX; + +static TIMER_INTERVAL mSmmPeriodicTimerIntervals[NUM_INTERVALS] = { + { + TIME_64s, + PERIODIC_TIMER + }, + { + TIME_32s, + PERIODIC_TIMER + }, + { + TIME_16s, + PERIODIC_TIMER + }, + { + TIME_8s, + PERIODIC_TIMER + }, + { + TIME_64ms, + SWSMI_TIMER + }, + { + TIME_32ms, + SWSMI_TIMER + }, + { + TIME_16ms, + SWSMI_TIMER + }, + { + TIME_1_5ms, + SWSMI_TIMER + }, +}; + +typedef struct _TIMER_INFO { + UINTN NumChildren; ///< number of children using this timer + UINT64 MinReqInterval; ///< minimum interval required by children + UINTN CurrentSetting; ///< interval this timer is set at right now (index into interval table) +} TIMER_INFO; + +GLOBAL_REMOVE_IF_UNREFERENCED TIMER_INFO mTimers[NUM_TIMERS]; + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mTimerSourceDesc[NUM_TIMERS] = { + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_PERIODIC + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_PERIODIC + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_PERIODIC + } + }, + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_SWSMI_TMR + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SWSMI_TMR + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SWSMI_TMR + } + } +}; + +/** + Program Smm Periodic Timer + + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC instance. +**/ +VOID +PchSmmPeriodicTimerProgramTimers ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Convert the dispatch context to the timer interval, this function will assert if then either: + (1) The context contains an invalid interval + (2) The timer interval table is corrupt + + @param[in] DispatchContext The pointer to the Dispatch Context + + @retval TIMER_INTERVAL The timer interval of input dispatch context +**/ +TIMER_INTERVAL * +ContextToTimerInterval ( + IN PCH_SMM_CONTEXT *DispatchContext + ) +{ + UINTN loopvar; + + /// + /// Determine which timer this child is using + /// + for (loopvar = 0; loopvar < NUM_INTERVALS; loopvar++) { + if (((DispatchContext->PeriodicTimer.SmiTickInterval == 0) && + (DispatchContext->PeriodicTimer.Period >= mSmmPeriodicTimerIntervals[loopvar].Interval)) || + (DispatchContext->PeriodicTimer.SmiTickInterval == mSmmPeriodicTimerIntervals[loopvar].Interval)) { + return &mSmmPeriodicTimerIntervals[loopvar]; + } + } + /// + /// If this assertion fires, then either: + /// (1) the context contains an invalid interval + /// (2) the timer interval table is corrupt + /// + ASSERT (FALSE); + + return NULL; +} + +/** + Figure out which timer the child is requesting and + send back the source description + + @param[in] DispatchContext The pointer to the Dispatch Context instances + @param[out] SrcDesc The pointer to the source description + +**/ +VOID +MapPeriodicTimerToSrcDesc ( + IN PCH_SMM_CONTEXT *DispatchContext, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + TIMER_INTERVAL *TimerInterval; + + /// + /// Figure out which timer the child is requesting and + /// send back the source description + /// + TimerInterval = ContextToTimerInterval (DispatchContext); + if (TimerInterval == NULL) { + return; + } + + CopyMem ( + (VOID *) SrcDesc, + (VOID *) (&mTimerSourceDesc[TimerInterval->AssociatedTimer]), + sizeof (PCH_SMM_SOURCE_DESC) + ); + + /// + /// Program the value of the interval into hardware + /// + PchSmmPeriodicTimerProgramTimers (SrcDesc); +} + +/** + Update the elapsed time from the Interval data of DATABASE_RECORD + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] HwContext The Context to be updated. + +**/ +VOID +EFIAPI +PeriodicTimerGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *HwContext + ) +{ + TIMER_INTERVAL *TimerInterval; + + ASSERT (Record->ProtocolType == PeriodicTimerType); + + TimerInterval = ContextToTimerInterval (&Record->ChildContext); + if (TimerInterval == NULL) { + return; + } + /// + /// Ignore the hardware context. It's not required for this protocol. + /// Instead, just increment the child's context. + /// Update the elapsed time w/ the data from our tables + /// + Record->MiscData.ElapsedTime += mTimers[TimerInterval->AssociatedTimer].MinReqInterval; + *HwContext = Record->ChildContext; +} + +/** + Check whether Periodic Timer of two contexts match + + @param[in] Context1 Context 1 that includes Periodic Timer 1 + @param[in] Context2 Context 2 that includes Periodic Timer 2 + + @retval FALSE Periodic Timer match + @retval TRUE Periodic Timer don't match +**/ +BOOLEAN +EFIAPI +PeriodicTimerCmpContext ( + IN PCH_SMM_CONTEXT *HwContext, + IN PCH_SMM_CONTEXT *ChildContext + ) +{ + DATABASE_RECORD *Record; + Record = DATABASE_RECORD_FROM_CHILDCONTEXT (ChildContext); + + if (!Record->MiscData.TimerSmiEnabled) { + return FALSE; + } + if (Record->MiscData.ElapsedTime >= ChildContext->PeriodicTimer.Period) { + /// + /// For EDKII, the ElapsedTime is reset when PeriodicTimerGetCommBuffer + /// + return TRUE; + } else { + return FALSE; + } +} + +/** + Gather the CommBuffer information of SmmPeriodicTimerDispatch2. + + @param[in] Record No use + @param[out] CommBuffer Point to the CommBuffer structure + @param[out] CommBufferSize Point to the Size of CommBuffer structure + +**/ +VOID +EFIAPI +PeriodicTimerGetCommBuffer ( + IN DATABASE_RECORD *Record, + OUT VOID **CommBuffer, + OUT UINTN *CommBufferSize + ) +{ + ASSERT (Record->ProtocolType == PeriodicTimerType); + + mPchPeriodicTimerCommBuffer.ElapsedTime = Record->MiscData.ElapsedTime; + + /// + /// For EDKII, the ElapsedTime is reset here + /// + Record->MiscData.ElapsedTime = 0; + + /// + /// Return the CommBuffer + /// + *CommBuffer = (VOID *) &mPchPeriodicTimerCommBuffer; + *CommBufferSize = sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT); +} + +/** + Program Smm Periodic Timer + + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC instance. +**/ +VOID +PchSmmPeriodicTimerProgramTimers ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + SUPPORTED_TIMER Timer; + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + TIMER_INTERVAL *TimerInterval; + + /// + /// Find the minimum required interval for each timer + /// + for (Timer = 0; Timer < NUM_TIMERS; Timer++) { + mTimers[Timer].MinReqInterval = ~ (UINT64) 0x0; + mTimers[Timer].NumChildren = 0; + } + + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + if (RecordInDb->ProtocolType == PeriodicTimerType) { + if (RecordInDb->MiscData.TimerSmiEnabled) { + /// + /// This child is registerd with the PeriodicTimer protocol + /// + TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext); + if (TimerInterval == NULL) { + return; + } + + Timer = TimerInterval->AssociatedTimer; + if (Timer < 0 || Timer >= NUM_TIMERS) { + ASSERT (FALSE); + CpuDeadLoop (); + return; + } + if (mTimers[Timer].MinReqInterval > RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval) { + mTimers[Timer].MinReqInterval = RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval; + } + mTimers[Timer].NumChildren++; + } + } + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + } + /// + /// Program the hardware + /// + if (mTimers[PERIODIC_TIMER].NumChildren > 0) { + switch (mTimers[PERIODIC_TIMER].MinReqInterval) { + case TIME_64s: + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate64s); + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64s; + break; + + case TIME_32s: + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate32s); + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s; + break; + + case TIME_16s: + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate16s); + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s; + break; + + case TIME_8s: + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate8s); + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s; + break; + + default: + ASSERT (FALSE); + break; + } + + /// + /// Restart the timer here, just need to clear the SMI + /// + if (SrcDesc->Sts[0].Bit == N_ACPI_IO_SMI_STS_PERIODIC) { + PchSmmClearSource (&mTimerSourceDesc[PERIODIC_TIMER]); + } + } else { + PchSmmDisableSource (&mTimerSourceDesc[PERIODIC_TIMER]); + } + + if (mTimers[SWSMI_TIMER].NumChildren > 0) { + switch (mTimers[SWSMI_TIMER].MinReqInterval) { + case TIME_64ms: + PmcSetSwSmiRate (PmcSwSmiRate64ms); + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_64ms; + break; + + case TIME_32ms: + PmcSetSwSmiRate (PmcSwSmiRate32ms); + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_32ms; + break; + + case TIME_16ms: + PmcSetSwSmiRate (PmcSwSmiRate16ms); + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_16ms; + break; + + case TIME_1_5ms: + PmcSetSwSmiRate (PmcSwSmiRate1p5ms); + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_1_5ms; + break; + + default: + ASSERT (FALSE); + break; + } + + /// + /// Restart the timer here, need to disable, clear, then enable to restart this timer + /// + if (SrcDesc->Sts[0].Bit == N_ACPI_IO_SMI_STS_SWSMI_TMR) { + PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]); + PchSmmClearSource (&mTimerSourceDesc[SWSMI_TIMER]); + PchSmmEnableSource (&mTimerSourceDesc[SWSMI_TIMER]); + } + } else { + PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]); + } +} + +/** + This services returns the next SMI tick period that is supported by the chipset. + The order returned is from longest to shortest interval period. + + @param[in] This Pointer to the EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance. + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter SMI interval period that is supported by the child. + + @retval EFI_SUCCESS The service returned successfully. + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is invalid. +**/ +EFI_STATUS +PchSmmPeriodicTimerDispatchGetNextShorterInterval ( + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This, + IN OUT UINT64 **SmiTickInterval + ) +{ + TIMER_INTERVAL *IntervalPointer; + + ASSERT (SmiTickInterval != NULL); + if (SmiTickInterval == NULL) { + return EFI_INVALID_PARAMETER; + } + + IntervalPointer = (TIMER_INTERVAL *) *SmiTickInterval; + + if (IntervalPointer == NULL) { + /// + /// The first time child requesting an interval + /// + IntervalPointer = &mSmmPeriodicTimerIntervals[0]; + } else if (IntervalPointer == &mSmmPeriodicTimerIntervals[NUM_INTERVALS - 1]) { + /// + /// At end of the list + /// + IntervalPointer = NULL; + } else { + if ((IntervalPointer >= &mSmmPeriodicTimerIntervals[0]) && + (IntervalPointer < &mSmmPeriodicTimerIntervals[NUM_INTERVALS - 1]) + ) { + /// + /// Get the next interval in the list + /// + IntervalPointer++; + } else { + /// + /// Input is out of range + /// + return EFI_INVALID_PARAMETER; + } + } + + if (IntervalPointer != NULL) { + *SmiTickInterval = &IntervalPointer->Interval; + } else { + *SmiTickInterval = NULL; + } + + return EFI_SUCCESS; +} + +/** + This function is responsible for calculating and enabling any timers that are required + to dispatch messages to children. The SrcDesc argument isn't acutally used. + + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC instance. + +**/ +VOID +EFIAPI +PchSmmPeriodicTimerClearSource ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + PchSmmPeriodicTimerProgramTimers (SrcDesc); +} + + +/** + Check if the handle is in type of PeriodicTimer + + @retval TRUE The handle is in type of PeriodicTimer. + @retval FALSE The handle is not in type of PeriodicTimer. +**/ +BOOLEAN +IsSmmPeriodicTimerHandle ( + IN EFI_HANDLE DispatchHandle + ) +{ + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + if (DispatchHandle == (EFI_HANDLE) LinkInDb) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + if (RecordInDb->ProtocolType == PeriodicTimerType) { + return TRUE; + } + } + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, LinkInDb); + } + return FALSE; +} + +/** + Pause SMM periodic timer callback function. + + This function disable the SMI enable of SMI timer according to the DispatchHandle, + which is returned by SMM periodic timer callback registration. + + @retval EFI_SUCCESS This operation is complete. + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. +**/ +EFI_STATUS +EFIAPI +PchSmmPeriodicTimerControlPause ( + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + DATABASE_RECORD *RecordInDb; + + if (IsSmmPeriodicTimerHandle (DispatchHandle) == FALSE) { + return EFI_INVALID_PARAMETER; + } + + RecordInDb = DATABASE_RECORD_FROM_LINK (DispatchHandle); + RecordInDb->MiscData.TimerSmiEnabled = FALSE; + // + // reset the timer interval per SMI trigger due to stop a periodic timer SMI + // + PchSmmPeriodicTimerProgramTimers (&RecordInDb->SrcDesc); + return EFI_SUCCESS; +} + +/** + Resume SMM periodic timer callback function. + + This function enable the SMI enable of SMI timer according to the DispatchHandle, + which is returned by SMM periodic timer callback registration. + + @retval EFI_SUCCESS This operation is complete. + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. +**/ +EFI_STATUS +EFIAPI +PchSmmPeriodicTimerControlResume ( + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + DATABASE_RECORD *RecordInDb; + + if (IsSmmPeriodicTimerHandle (DispatchHandle) == FALSE) { + return EFI_INVALID_PARAMETER; + } + RecordInDb = DATABASE_RECORD_FROM_LINK (DispatchHandle); + RecordInDb->MiscData.TimerSmiEnabled = TRUE; + // + // reset the timer interval per SMI trigger due to resume a periodic timer SMI + // + PchSmmPeriodicTimerProgramTimers (&RecordInDb->SrcDesc); + return EFI_SUCCESS; +} + +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL mPchSmmPeriodicTimerControlProtocol = { + PchSmmPeriodicTimerControlPause, + PchSmmPeriodicTimerControlResume +}; + +/** + Install PCH SMM periodic timer control protocol + + @param[in] Handle handle for this driver + + @retval EFI_SUCCESS Driver initialization completed successfully +**/ +EFI_STATUS +EFIAPI +InstallPchSmmPeriodicTimerControlProtocol ( + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + + // + // Install protocol interface + // + Status = gSmst->SmmInstallProtocolInterface ( + &Handle, + &gPchSmmPeriodicTimerControlGuid, + EFI_NATIVE_INTERFACE, + &mPchSmmPeriodicTimerControlProtocol + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowerButton.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowerButton.c new file mode 100644 index 0000000000..e6d3bf012f --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowerButton.c @@ -0,0 +1,77 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Power Button dispatch protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <PchSmmHelpers.h> +#include <Library/PmcPrivateLib.h> + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mPowerButtonSourceDesc = { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_EN} + }, + S_ACPI_IO_PM1_EN, + N_ACPI_IO_PM1_EN_PWRBTN + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_STS} + }, + S_ACPI_IO_PM1_STS, + N_ACPI_IO_PM1_STS_PWRBTN + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_PM1_STS_REG + } +}; + +/** + Get the power button status. + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] Context Calling context from the hardware, will be updated with the current power button status. + +**/ +VOID +EFIAPI +PowerButtonGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ) +{ + return; +} + +/** + Check whether Power Button status of two contexts match + + @param[in] Context1 Context 1 that includes Power Button status 1 + @param[in] Context2 Context 2 that includes Power Button status 2 + + @retval FALSE Power Button status match + @retval TRUE Power Button status don't match +**/ +BOOLEAN +EFIAPI +PowerButtonCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ) +{ + return TRUE; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c new file mode 100644 index 0000000000..311a21820c --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c @@ -0,0 +1,381 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Sw dispatch protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include <Protocol/SmmCpu.h> +#include <Register/PchRegsLpc.h> +#include <Register/PmcRegs.h> + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_CPU_PROTOCOL *mSmmCpuProtocol; + +STATIC LIST_ENTRY mSwSmiCallbackDataBase; + +// +// "SWSMI" RECORD +// Linked list data structures +// +#define SW_SMI_RECORD_SIGNATURE SIGNATURE_32 ('S', 'W', 'S', 'M') + +#define SW_SMI_RECORD_FROM_LINK(_record) CR (_record, SW_SMI_RECORD, Link, SW_SMI_RECORD_SIGNATURE) + +typedef struct { + UINT32 Signature; + LIST_ENTRY Link; + EFI_SMM_SW_REGISTER_CONTEXT Context; + EFI_SMM_HANDLER_ENTRY_POINT2 Callback; +} SW_SMI_RECORD; + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSwSourceDesc = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_APMC + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_APM + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_APM + } +}; + +/** + Check the SwSmiInputValue to see if there is a duplicated one in the database + + @param[in] SwSmiInputValue SwSmiInputValue + + @retval EFI_SUCCESS There is no duplicated SwSmiInputValue + @retval EFI_INVALID_PARAMETER There is a duplicated SwSmiInputValue +**/ +EFI_STATUS +SmiInputValueDuplicateCheck ( + IN UINTN SwSmiInputValue + ) +{ + SW_SMI_RECORD *SwSmiRecord; + LIST_ENTRY *LinkInDb; + + LinkInDb = GetFirstNode (&mSwSmiCallbackDataBase); + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) { + SwSmiRecord = SW_SMI_RECORD_FROM_LINK (LinkInDb); + if (SwSmiRecord->Context.SwSmiInputValue == SwSmiInputValue) { + return EFI_INVALID_PARAMETER; + } + LinkInDb = GetNextNode (&mSwSmiCallbackDataBase, &SwSmiRecord->Link); + } + + return EFI_SUCCESS; +} + +/** + Register a child SMI source dispatch function for the specified software SMI. + + This service registers a function (DispatchFunction) which will be called when the software + SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On return, + DispatchHandle contains a unique handle which may be used later to unregister the function + using UnRegister(). + + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance. + @param[in] DispatchFunction Function to register for handler when the specified software + SMI is generated. + @param[in, out] RegisterContext Pointer to the dispatch function's context. + The caller fills this context in before calling + the register function to indicate to the register + function which Software SMI input value the + dispatch function should be invoked for. + @param[out] DispatchHandle Handle generated by the dispatcher to track the + function instance. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_DEVICE_ERROR The SW driver was unable to enable the SMI source. + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI input value + is not within a valid range or is already in use. + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM) to manage this + child. + @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be assigned + for this dispatch. +**/ +EFI_STATUS +EFIAPI +PchSwSmiRegister ( + IN EFI_SMM_SW_DISPATCH2_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + SW_SMI_RECORD *SwSmiRecord; + UINTN Index; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + // + // Find available SW SMI value if the input is -1 + // + if (DispatchContext->SwSmiInputValue == (UINTN) -1) { + for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) { + if (!EFI_ERROR (SmiInputValueDuplicateCheck (Index))) { + DispatchContext->SwSmiInputValue = Index; + break; + } + } + if (DispatchContext->SwSmiInputValue == (UINTN) -1) { + return EFI_OUT_OF_RESOURCES; + } + } + // + // Check if it's a valid SW SMI value. + // The value must not bigger than 0xFF. + // And the value must not be 0xFF sincie it's used for SmmControll protocol. + // + if (DispatchContext->SwSmiInputValue >= MAXIMUM_SWI_VALUE) { + return EFI_INVALID_PARAMETER; + } + + if (EFI_ERROR (SmiInputValueDuplicateCheck (DispatchContext->SwSmiInputValue))) { + return EFI_INVALID_PARAMETER; + } + + // + // Create database record and add to database + // + Status = gSmst->SmmAllocatePool ( + EfiRuntimeServicesData, + sizeof (SW_SMI_RECORD), + (VOID **) &SwSmiRecord + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to allocate memory for SwSmiRecord! \n")); + return EFI_OUT_OF_RESOURCES; + } + // + // Gather information about the registration request + // + SwSmiRecord->Signature = SW_SMI_RECORD_SIGNATURE; + SwSmiRecord->Context.SwSmiInputValue = DispatchContext->SwSmiInputValue; + SwSmiRecord->Callback = DispatchFunction; + // + // Publish the S/W SMI numbers in Serial logs used for Debug build. + // + DEBUG ((DEBUG_INFO, "SW SMI NUM %x Sw Record at Address 0x%X\n", SwSmiRecord->Context.SwSmiInputValue, SwSmiRecord)); + + InsertTailList (&mSwSmiCallbackDataBase, &SwSmiRecord->Link); + + // + // Child's handle will be the address linked list link in the record + // + *DispatchHandle = (EFI_HANDLE) (&SwSmiRecord->Link); + + return EFI_SUCCESS; +} + +/** + Unregister a child SMI source dispatch function for the specified software SMI. + + This service removes the handler associated with DispatchHandle so that it will no longer be + called in response to a software SMI. + + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully unregistered. + @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid. +**/ +EFI_STATUS +EFIAPI +PchSwSmiUnRegister ( + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + EFI_STATUS Status; + SW_SMI_RECORD *RecordToDelete; + + if (DispatchHandle == 0) { + return EFI_INVALID_PARAMETER; + } + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + RecordToDelete = SW_SMI_RECORD_FROM_LINK (DispatchHandle); + // + // Take the entry out of the linked list + // + if (RecordToDelete->Signature != SW_SMI_RECORD_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + RemoveEntryList (&RecordToDelete->Link); + ZeroMem (RecordToDelete, sizeof (SW_SMI_RECORD)); + Status = gSmst->SmmFreePool (RecordToDelete); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +/** + Main entry point for an SMM handler dispatch or communicate-based callback. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] Context Points to an optional handler context which was specified when the + handler was registered. + @param[in,out] CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in,out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers + should still be called. + @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should + still be called. + @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still + be called. + @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced. +**/ +EFI_STATUS +EFIAPI +PchSwSmiDispatcher ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + EFI_SMM_SAVE_STATE_IO_INFO SmiIoInfo; + UINTN CpuIndex; + SW_SMI_RECORD *SwSmiRecord; + LIST_ENTRY *LinkInDb; + EFI_SMM_SW_CONTEXT SwSmiCommBuffer; + UINTN SwSmiCommBufferSize; + + SwSmiCommBufferSize = sizeof (EFI_SMM_SW_CONTEXT); + // + // The value in DataPort might not be accurate in multiple thread environment. + // There might be racing condition for R_PCH_IO_APM_STS port. + // Therefor, this is just for reference. + // + SwSmiCommBuffer.DataPort = IoRead8 (R_PCH_IO_APM_STS); + + for (CpuIndex = 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) { + Status = mSmmCpuProtocol->ReadSaveState ( + mSmmCpuProtocol, + sizeof (EFI_SMM_SAVE_STATE_IO_INFO), + EFI_SMM_SAVE_STATE_REGISTER_IO, + CpuIndex, + &SmiIoInfo + ); + // + // If this is not the SMI source, skip it. + // + if (EFI_ERROR (Status)) { + continue; + } + // + // If the IO address is not "BYTE" "WRITE" to "R_PCH_IO_APM_CNT (0xB2)", skip it. + // + if ((SmiIoInfo.IoPort != R_PCH_IO_APM_CNT) || + (SmiIoInfo.IoType != EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT) || + (SmiIoInfo.IoWidth != EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8)) + { + continue; + } + // + // If the IO data is used for SmmControl protocol, skip it. + // + if (SmiIoInfo.IoData == 0xFF) { + continue; + } + + SwSmiCommBuffer.SwSmiCpuIndex = CpuIndex; + SwSmiCommBuffer.CommandPort = (UINT8) SmiIoInfo.IoData; + + LinkInDb = GetFirstNode (&mSwSmiCallbackDataBase); + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) { + SwSmiRecord = SW_SMI_RECORD_FROM_LINK (LinkInDb); + if (SwSmiRecord->Context.SwSmiInputValue == SmiIoInfo.IoData) { + SwSmiRecord->Callback ((EFI_HANDLE) &SwSmiRecord->Link, &SwSmiRecord->Context, &SwSmiCommBuffer, &SwSmiCommBufferSize); + } + LinkInDb = GetNextNode (&mSwSmiCallbackDataBase, &SwSmiRecord->Link); + } + } + + return EFI_SUCCESS; +} + +/** + Init required protocol for Pch Sw Dispatch protocol. +**/ +VOID +PchSwDispatchInit ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE DispatchHandle; + DATABASE_RECORD Record; + + // + // Locate PI SMM CPU protocol + // + Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **)&mSmmCpuProtocol); + ASSERT_EFI_ERROR (Status); + + // + // Initialize SW SMI Callback DataBase + // + InitializeListHead (&mSwSmiCallbackDataBase); + + // + // Insert SwSmi handler to PchSmmCore database + // There will always be one SwType record in PchSmmCore database + // + ZeroMem (&Record, sizeof (DATABASE_RECORD)); + Record.Signature = DATABASE_RECORD_SIGNATURE; + Record.Callback = PchSwSmiDispatcher; + Record.ProtocolType = SwType; + + CopyMem (&Record.SrcDesc, &mSwSourceDesc, sizeof (PCH_SMM_SOURCE_DESC)); + + DispatchHandle = NULL; + Status = SmmCoreInsertRecord ( + &Record, + &DispatchHandle + ); + ASSERT_EFI_ERROR (Status); +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c new file mode 100644 index 0000000000..798fb33347 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c @@ -0,0 +1,117 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Sx dispatch protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include <Register/PmcRegs.h> +#include "PchSmiHelper.h" + +extern BOOLEAN mS3SusStart; +#define PROGRESS_CODE_S3_SUSPEND_END PcdGet32 (PcdProgressCodeS3SuspendEnd) + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSxSourceDesc = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_ON_SLP_EN + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_ON_SLP_EN + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_ON_SLP_EN + } +}; + +/** + Get the Sleep type + + @param[in] Record No use + @param[out] Context The context that includes SLP_TYP bits to be filled + +**/ +VOID +EFIAPI +SxGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ) +{ + UINT32 Pm1Cnt; + + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); + + /// + /// By design, the context phase will always be ENTRY + /// + Context->Sx.Phase = SxEntry; + + /// + /// Map the PM1_CNT register's SLP_TYP bits to the context type + /// + switch (Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) { + case V_ACPI_IO_PM1_CNT_S0: + Context->Sx.Type = SxS0; + break; + + case V_ACPI_IO_PM1_CNT_S1: + Context->Sx.Type = SxS1; + break; + + case V_ACPI_IO_PM1_CNT_S3: + Context->Sx.Type = SxS3; + break; + + case V_ACPI_IO_PM1_CNT_S4: + Context->Sx.Type = SxS4; + break; + + case V_ACPI_IO_PM1_CNT_S5: + Context->Sx.Type = SxS5; + break; + + default: + ASSERT (FALSE); + break; + } +} + +/** + Check whether sleep type of two contexts match + + @param[in] Context1 Context 1 that includes sleep type 1 + @param[in] Context2 Context 2 that includes sleep type 2 + + @retval FALSE Sleep types match + @retval TRUE Sleep types don't match +**/ +BOOLEAN +EFIAPI +SxCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ) +{ + return (BOOLEAN) (Context1->Sx.Type == Context2->Sx.Type); +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c new file mode 100644 index 0000000000..6b23956c4a --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c @@ -0,0 +1,244 @@ +/** @file + File to contain all the hardware specific stuff for the Smm USB dispatch protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include <Register/PmcRegs.h> +#include <Library/PchPciBdfLib.h> + +typedef enum { + PchUsbControllerLpc0 = 0, + PchUsbControllerXhci, + PchUsbControllerTypeMax +} PCH_USB_CONTROLLER_TYPE; + +typedef struct { + UINT8 Function; + UINT8 Device; + PCH_USB_CONTROLLER_TYPE UsbConType; +} PCH_USB_CONTROLLER; + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mUsb1Legacy = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_LEGACY_USB + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_LEGACY_USB + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_LEGACY_USB + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mUsb3Legacy = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_LEGACY_USB3 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_LEGACY_USB3 + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_LEGACY_USB3 + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED PCH_USB_CONTROLLER mUsbControllersMap[] = { + { + 0xFF, // to be updated in PchSmmUsbUpdateDescriptors + 0xFF, // to be updated in PchSmmUsbUpdateDescriptors + PchUsbControllerLpc0 + }, + { + 0xFF, // to be updated in PchSmmUsbUpdateDescriptors + 0xFF, // to be updated in PchSmmUsbUpdateDescriptors + PchUsbControllerXhci + } +}; + +/** + Performs update of SmmUsb descriptors with values that have to be evaluated during runtime. +**/ +VOID +PchSmmUsbUpdateDescriptors ( + VOID + ) +{ + // + // mUsbControllersMap + // + mUsbControllersMap[0].Function = LpcFuncNumber (); + mUsbControllersMap[0].Device = LpcDevNumber (); + mUsbControllersMap[1].Function = PchXhciFuncNumber (); + mUsbControllersMap[1].Device = PchXhciDevNumber (); +} + +/** + Find the handle that best matches the input Device Path and return the USB controller type + + @param[in] DevicePath Pointer to the device Path table + @param[out] Controller Returned with the USB controller type of the input device path + + @retval EFI_SUCCESS Find the handle that best matches the input Device Path + @exception EFI_UNSUPPORTED Invalid device Path table or can't find any match USB device path + PCH_USB_CONTROLLER_TYPE The USB controller type of the input + device path +**/ +EFI_STATUS +DevicePathToSupportedController ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT PCH_USB_CONTROLLER_TYPE *Controller + ) +{ + EFI_STATUS Status; + EFI_HANDLE DeviceHandle; + ACPI_HID_DEVICE_PATH *AcpiNode; + PCI_DEVICE_PATH *PciNode; + EFI_DEVICE_PATH_PROTOCOL *RemaingDevicePath; + UINT8 UsbIndex; + /// + /// Find the handle that best matches the Device Path. If it is only a + /// partial match the remaining part of the device path is returned in + /// RemainingDevicePath. + /// + RemaingDevicePath = DevicePath; + Status = gBS->LocateDevicePath ( + &gEfiPciRootBridgeIoProtocolGuid, + &DevicePath, + &DeviceHandle + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + DevicePath = RemaingDevicePath; + + /// + /// Get first node: Acpi Node + /// + AcpiNode = (ACPI_HID_DEVICE_PATH *) RemaingDevicePath; + + if (AcpiNode->Header.Type != ACPI_DEVICE_PATH || + AcpiNode->Header.SubType != ACPI_DP || + DevicePathNodeLength (&AcpiNode->Header) != sizeof (ACPI_HID_DEVICE_PATH) || + AcpiNode->HID != EISA_PNP_ID (0x0A03) || + AcpiNode->UID != 0 + ) { + return EFI_UNSUPPORTED; + } else { + /// + /// Get the next node: Pci Node + /// + RemaingDevicePath = NextDevicePathNode (RemaingDevicePath); + PciNode = (PCI_DEVICE_PATH *) RemaingDevicePath; + if (PciNode->Header.Type != HARDWARE_DEVICE_PATH || + PciNode->Header.SubType != HW_PCI_DP || + DevicePathNodeLength (&PciNode->Header) != sizeof (PCI_DEVICE_PATH) + ) { + return EFI_UNSUPPORTED; + } + + for (UsbIndex = 0; UsbIndex < sizeof (mUsbControllersMap) / sizeof (PCH_USB_CONTROLLER); UsbIndex++) { + if ((PciNode->Device == mUsbControllersMap[UsbIndex].Device) && + (PciNode->Function == mUsbControllersMap[UsbIndex].Function)) { + *Controller = mUsbControllersMap[UsbIndex].UsbConType; + return EFI_SUCCESS; + } + } + + return EFI_UNSUPPORTED; + } +} + +/** + Maps a USB context to a source description. + + @param[in] Context The context we need to map. Type must be USB. + @param[in] SrcDesc The source description that corresponds to the given context. + +**/ +VOID +MapUsbToSrcDesc ( + IN PCH_SMM_CONTEXT *Context, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + PCH_USB_CONTROLLER_TYPE Controller; + EFI_STATUS Status; + + Status = DevicePathToSupportedController (Context->Usb.Device, &Controller); + /// + /// Either the device path passed in by the child is incorrect or + /// the ones stored here internally are incorrect. + /// + ASSERT_EFI_ERROR (Status); + + switch (Context->Usb.Type) { + case UsbLegacy: + switch (Controller) { + case PchUsbControllerLpc0: + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb1Legacy), sizeof (PCH_SMM_SOURCE_DESC)); + break; + + case PchUsbControllerXhci: + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb3Legacy), sizeof (PCH_SMM_SOURCE_DESC)); + break; + + default: + ASSERT (FALSE); + break; + } + break; + + case UsbWake: + ASSERT (FALSE); + break; + + default: + ASSERT (FALSE); + break; + } +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.c new file mode 100644 index 0000000000..c0ce5785fd --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.c @@ -0,0 +1,682 @@ +/** @file + This driver is responsible for the registration of child drivers + and the abstraction of the PCH SMI sources. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include <Register/PchRegs.h> +#include <Register/PmcRegs.h> +#include <Register/TcoRegs.h> + +extern UINT32 mTco1StsClear; +// +// Help handle porting bit shifts to IA-64. +// +#define BIT_ZERO 0x00000001 + +/** + Publish SMI Dispatch protocols. + + +**/ +VOID +PchSmmPublishDispatchProtocols ( + VOID + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINTN Index; + // + // Install protocol interfaces. + // + for (Index = 0; Index < PCH_SMM_PROTOCOL_TYPE_MAX; Index++) { + Status = gSmst->SmmInstallProtocolInterface ( + &mPrivateData.InstallMultProtHandle, + mPrivateData.Protocols[Index].Guid, + EFI_NATIVE_INTERFACE, + &mPrivateData.Protocols[Index].Protocols.Generic + ); + } + ASSERT_EFI_ERROR (Status); +} + +/** + Initialize bits that aren't necessarily related to an SMI source. + + + @retval EFI_SUCCESS SMI source initialization completed. + @retval Asserts Global Smi Bit is not enabled successfully. +**/ +EFI_STATUS +PchSmmInitHardware ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Clear all SMIs + // + PchSmmClearSmi (); + + Status = PchSmmEnableGlobalSmiBit (); + ASSERT_EFI_ERROR (Status); + + // + // Be *really* sure to clear all SMIs + // + PchSmmClearSmi (); + + return EFI_SUCCESS; +} + +/** + Enables the PCH to generate SMIs. Note that no SMIs will be generated + if no SMI sources are enabled. Conversely, no enabled SMI source will + generate SMIs if SMIs are not globally enabled. This is the main + switchbox for SMI generation. + + + @retval EFI_SUCCESS Enable Global Smi Bit completed +**/ +EFI_STATUS +PchSmmEnableGlobalSmiBit ( + VOID + ) +{ + UINT32 SmiEn; + + SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); + + // + // Set the "global smi enable" bit + // + SmiEn |= B_ACPI_IO_SMI_EN_GBL_SMI; + + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn); + + return EFI_SUCCESS; +} + +/** + Clears the SMI after all SMI source have been processed. + Note that this function will not work correctly (as it is + written) unless all SMI sources have been processed. + A revision of this function could manually clear all SMI + status bits to guarantee success. + + + @retval EFI_SUCCESS Clears the SMIs completed + @retval Asserts EOS was not set to a 1 +**/ +EFI_STATUS +PchSmmClearSmi ( + VOID + ) +{ + return EFI_SUCCESS; +} + +/** + Set the SMI EOS bit after all SMI source have been processed. + + + @retval FALSE EOS was not set to a 1; this is an error + @retval TRUE EOS was correctly set to a 1 +**/ +BOOLEAN +PchSmmSetAndCheckEos ( + VOID + ) +{ + UINT32 SmiEn; + + SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); + + // + // Reset the PCH to generate subsequent SMIs + // + SmiEn |= B_ACPI_IO_SMI_EN_EOS; + + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn); + + // + // Double check that the assert worked + // + SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); + + // + // Return TRUE if EOS is set correctly + // + if ((SmiEn & B_ACPI_IO_SMI_EN_EOS) == 0) { + // + // EOS was not set to a 1; this is an error + // + return FALSE; + } else { + // + // EOS was correctly set to a 1 + // + return TRUE; + } +} + +/** + Determine whether an ACPI OS is present (via the SCI_EN bit) + + + @retval TRUE ACPI OS is present + @retval FALSE ACPI OS is not present +**/ +BOOLEAN +PchSmmGetSciEn ( + VOID + ) +{ + BOOLEAN SciEn; + UINT32 Pm1Cnt; + + // + // Determine whether an ACPI OS is present (via the SCI_EN bit) + // + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); + SciEn = (BOOLEAN) ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) == B_ACPI_IO_PM1_CNT_SCI_EN); + + return SciEn; +} + +/** + Read a specifying bit with the register + These may or may not need to change w/ the PCH version; they're highly IA-32 dependent, though. + + @param[in] BitDesc The struct that includes register address, size in byte and bit number + + @retval TRUE The bit is enabled + @retval FALSE The bit is disabled +**/ +BOOLEAN +ReadBitDesc ( + CONST PCH_SMM_BIT_DESC *BitDesc + ) +{ + EFI_STATUS Status; + UINT64 Register; + UINT32 PciBus; + UINT32 PciDev; + UINT32 PciFun; + UINT32 PciReg; + UINTN RegSize; + BOOLEAN BitWasOne; + UINTN ShiftCount; + UINTN RegisterOffset; + UINT32 BaseAddr; + UINT64 PciBaseAddress; + + ASSERT (BitDesc != NULL); + if (BitDesc == NULL) { + return FALSE; + } + ASSERT (!IS_BIT_DESC_NULL (*BitDesc)); + + RegSize = 0; + Register = 0; + ShiftCount = 0; + BitWasOne = FALSE; + + switch (BitDesc->Reg.Type) { + + case ACPI_ADDR_TYPE: + case TCO_ADDR_TYPE: + if (BitDesc->Reg.Type == ACPI_ADDR_TYPE) { + RegisterOffset = BitDesc->Reg.Data.acpi; + BaseAddr = mAcpiBaseAddr; + } else { + RegisterOffset = BitDesc->Reg.Data.tco; + BaseAddr = mTcoBaseAddr; + } + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized. + // Check your assignments to bit descriptions. + // + ASSERT (FALSE); + break; + + case 1: + RegSize = SMM_IO_UINT8; + break; + + case 2: + RegSize = SMM_IO_UINT16; + break; + + case 4: + RegSize = SMM_IO_UINT32; + break; + + case 8: + RegSize = SMM_IO_UINT64; + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + // + // Double check that we correctly read in the acpi base address + // + ASSERT ((BaseAddr != 0x0) && ((BaseAddr & 0x1) != 0x1)); + + ShiftCount = BitDesc->Bit; + // + // As current CPU Smm Io can only support at most + // 32-bit read/write,if Operation is 64 bit, + // we do a 32 bit operation according to BitDesc->Bit + // + if (RegSize == SMM_IO_UINT64) { + RegSize = SMM_IO_UINT32; + // + // If the operation is for high 32 bits + // + if (BitDesc->Bit >= 32) { + RegisterOffset += 4; + ShiftCount -= 32; + } + } + + Status = gSmst->SmmIo.Io.Read ( + &gSmst->SmmIo, + RegSize, + BaseAddr + RegisterOffset, + 1, + &Register + ); + ASSERT_EFI_ERROR (Status); + + if ((Register & (LShiftU64 (BIT_ZERO, ShiftCount))) != 0) { + BitWasOne = TRUE; + } else { + BitWasOne = FALSE; + } + break; + + case GPIO_ADDR_TYPE: + case MEMORY_MAPPED_IO_ADDRESS_TYPE: + // + // Read the register, and it with the bit to read + // + switch (BitDesc->SizeInBytes) { + case 1: + Register = (UINT64) MmioRead8 ((UINTN) BitDesc->Reg.Data.Mmio); + break; + + case 2: + Register = (UINT64) MmioRead16 ((UINTN) BitDesc->Reg.Data.Mmio); + break; + + case 4: + Register = (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio); + break; + + case 8: + Register = (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio); + *((UINT32 *) (&Register) + 1) = MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio + 4); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + + Register = Register & (LShiftU64 (BIT0, BitDesc->Bit)); + if (Register) { + BitWasOne = TRUE; + } else { + BitWasOne = FALSE; + } + break; + + case PCIE_ADDR_TYPE: + PciBus = BitDesc->Reg.Data.pcie.Fields.Bus; + PciDev = BitDesc->Reg.Data.pcie.Fields.Dev; + PciFun = BitDesc->Reg.Data.pcie.Fields.Fnc; + PciReg = BitDesc->Reg.Data.pcie.Fields.Reg; + PciBaseAddress = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0); + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized. + // Check your assignments to bit descriptions. + // + ASSERT (FALSE); + break; + + case 1: + Register = (UINT64) PciSegmentRead8 (PciBaseAddress + PciReg); + break; + + case 2: + Register = (UINT64) PciSegmentRead16 (PciBaseAddress + PciReg); + break; + + case 4: + Register = (UINT64) PciSegmentRead32 (PciBaseAddress + PciReg); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + + if ((Register & (LShiftU64 (BIT_ZERO, BitDesc->Bit))) != 0) { + BitWasOne = TRUE; + } else { + BitWasOne = FALSE; + } + break; + + case PCR_ADDR_TYPE: + // + // Read the register, and it with the bit to read + // + switch (BitDesc->SizeInBytes) { + case 1: + Register = PchPcrRead8 (BitDesc->Reg.Data.Pcr.Fields.Pid, BitDesc->Reg.Data.Pcr.Fields.Offset); + break; + + case 2: + Register = PchPcrRead16 (BitDesc->Reg.Data.Pcr.Fields.Pid, BitDesc->Reg.Data.Pcr.Fields.Offset); + break; + + case 4: + Register = PchPcrRead32 (BitDesc->Reg.Data.Pcr.Fields.Pid, BitDesc->Reg.Data.Pcr.Fields.Offset); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + + Register = Register & (LShiftU64 (BIT0, BitDesc->Bit)); + if (Register) { + BitWasOne = TRUE; + } else { + BitWasOne = FALSE; + } + break; + + default: + // + // This address type is not yet implemented + // + ASSERT (FALSE); + break; + } + + return BitWasOne; +} + +/** + Write a specifying bit with the register + + @param[in] BitDesc The struct that includes register address, size in byte and bit number + @param[in] ValueToWrite The value to be wrote + @param[in] WriteClear If the rest bits of the register is write clear + +**/ +VOID +WriteBitDesc ( + CONST PCH_SMM_BIT_DESC *BitDesc, + CONST BOOLEAN ValueToWrite, + CONST BOOLEAN WriteClear + ) +{ + EFI_STATUS Status; + UINT64 Register; + UINT64 AndVal; + UINT64 OrVal; + UINT32 RegSize; + UINT32 PciBus; + UINT32 PciDev; + UINT32 PciFun; + UINT32 PciReg; + UINTN RegisterOffset; + UINT32 BaseAddr; + UINT64 PciBaseAddress; + + ASSERT (BitDesc != NULL); + if (BitDesc == NULL) { + return; + } + ASSERT (!IS_BIT_DESC_NULL (*BitDesc)); + + RegSize = 0; + Register = 0; + + if (WriteClear) { + AndVal = LShiftU64 (BIT_ZERO, BitDesc->Bit); + } else { + AndVal = ~(LShiftU64 (BIT_ZERO, BitDesc->Bit)); + } + + OrVal = (LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit)); + + switch (BitDesc->Reg.Type) { + + case ACPI_ADDR_TYPE: + case TCO_ADDR_TYPE: + if (BitDesc->Reg.Type == ACPI_ADDR_TYPE) { + RegisterOffset = BitDesc->Reg.Data.acpi; + BaseAddr = mAcpiBaseAddr; + } else { + RegisterOffset = BitDesc->Reg.Data.tco; + BaseAddr = mTcoBaseAddr; + } + + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized. + // Check your assignments to bit descriptions. + // + ASSERT (FALSE); + break; + + case 1: + RegSize = SMM_IO_UINT8; + break; + + case 2: + RegSize = SMM_IO_UINT16; + break; + + case 4: + RegSize = SMM_IO_UINT32; + break; + + case 8: + RegSize = SMM_IO_UINT64; + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + // + // Double check that we correctly read in the acpi base address + // + ASSERT ((BaseAddr != 0x0) && ((BaseAddr & 0x1) != 0x1)); + + // + // As current CPU Smm Io can only support at most + // 32-bit read/write,if Operation is 64 bit, + // we do a 32 bit operation according to BitDesc->Bit + // + if (RegSize == SMM_IO_UINT64) { + RegSize = SMM_IO_UINT32; + // + // If the operation is for high 32 bits + // + if (BitDesc->Bit >= 32) { + RegisterOffset += 4; + + if (WriteClear) { + AndVal = LShiftU64 (BIT_ZERO, BitDesc->Bit - 32); + } else { + AndVal = ~(LShiftU64 (BIT_ZERO, BitDesc->Bit - 32)); + } + + OrVal = LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit - 32); + } + } + + Status = gSmst->SmmIo.Io.Read ( + &gSmst->SmmIo, + RegSize, + BaseAddr + RegisterOffset, + 1, + &Register + ); + ASSERT_EFI_ERROR (Status); + + Register &= AndVal; + Register |= OrVal; + + Status = gSmst->SmmIo.Io.Write ( + &gSmst->SmmIo, + RegSize, + BaseAddr + RegisterOffset, + 1, + &Register + ); + ASSERT_EFI_ERROR (Status); + break; + + case GPIO_ADDR_TYPE: + case MEMORY_MAPPED_IO_ADDRESS_TYPE: + // + // Read the register, or it with the bit to set, then write it back. + // + switch (BitDesc->SizeInBytes) { + case 1: + MmioAndThenOr8 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT8) AndVal, (UINT8) OrVal); + break; + + case 2: + MmioAndThenOr16 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT16) AndVal, (UINT16) OrVal); + break; + + case 4: + MmioAndThenOr32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) AndVal, (UINT32) OrVal); + break; + + case 8: + Register = (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio); + *((UINT32 *) (&Register) + 1) = MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio + 4); + Register &= AndVal; + Register |= OrVal; + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) Register); + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio + 4, *((UINT32 *) (&Register) + 1)); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + break; + + case PCIE_ADDR_TYPE: + PciBus = BitDesc->Reg.Data.pcie.Fields.Bus; + PciDev = BitDesc->Reg.Data.pcie.Fields.Dev; + PciFun = BitDesc->Reg.Data.pcie.Fields.Fnc; + PciReg = BitDesc->Reg.Data.pcie.Fields.Reg; + PciBaseAddress = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0); + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized -- check your assignments + // to bit descriptions. + // + ASSERT (FALSE); + break; + + case 1: + PciSegmentAndThenOr8 (PciBaseAddress + PciReg, (UINT8) AndVal, (UINT8) OrVal); + break; + + case 2: + PciSegmentAndThenOr16 (PciBaseAddress + PciReg, (UINT16) AndVal, (UINT16) OrVal); + break; + + case 4: + PciSegmentAndThenOr32 (PciBaseAddress + PciReg, (UINT32) AndVal, (UINT32) OrVal); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + break; + + case PCR_ADDR_TYPE: + // + // Read the register, or it with the bit to set, then write it back. + // + switch (BitDesc->SizeInBytes) { + case 1: + PchPcrAndThenOr8 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pid, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT8) AndVal, (UINT8) OrVal); + break; + + case 2: + PchPcrAndThenOr16 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pid, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT16) AndVal, (UINT16) OrVal); + break; + + case 4: + PchPcrAndThenOr32 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pid, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT32) AndVal, (UINT32) OrVal); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + break; + + default: + // + // This address type is not yet implemented + // + ASSERT (FALSE); + break; + } +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.h new file mode 100644 index 0000000000..998b38e159 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.h @@ -0,0 +1,107 @@ +/** @file + This driver is responsible for the registration of child drivers + and the abstraction of the PCH SMI sources. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCHX_SMM_HELPERS_H_ +#define _PCHX_SMM_HELPERS_H_ + +#include "PchSmm.h" + +/** + Initialize bits that aren't necessarily related to an SMI source. + + + @retval EFI_SUCCESS SMI source initialization completed. + @retval Asserts Global Smi Bit is not enabled successfully. +**/ +EFI_STATUS +PchSmmInitHardware ( + VOID + ); + +/** + Enables the PCH to generate SMIs. Note that no SMIs will be generated + if no SMI sources are enabled. Conversely, no enabled SMI source will + generate SMIs if SMIs are not globally enabled. This is the main + switchbox for SMI generation. + + + @retval EFI_SUCCESS Enable Global Smi Bit completed +**/ +EFI_STATUS +PchSmmEnableGlobalSmiBit ( + VOID + ); + +/** + Clears the SMI after all SMI source have been processed. + Note that this function will not work correctly (as it is + written) unless all SMI sources have been processed. + A revision of this function could manually clear all SMI + status bits to guarantee success. + + + @retval EFI_SUCCESS Clears the SMIs completed + @retval Asserts EOS was not set to a 1 +**/ +EFI_STATUS +PchSmmClearSmi ( + VOID + ); + +/** + Set the SMI EOS bit after all SMI source have been processed. + + + @retval FALSE EOS was not set to a 1; this is an error + @retval TRUE EOS was correctly set to a 1 +**/ +BOOLEAN +PchSmmSetAndCheckEos ( + VOID + ); + +/** + Determine whether an ACPI OS is present (via the SCI_EN bit) + + + @retval TRUE ACPI OS is present + @retval FALSE ACPI OS is not present +**/ +BOOLEAN +PchSmmGetSciEn ( + VOID + ); + +/** + Read a specifying bit with the register + + @param[in] BitDesc The struct that includes register address, size in byte and bit number + + @retval TRUE The bit is enabled + @retval FALSE The bit is disabled +**/ +BOOLEAN +ReadBitDesc ( + CONST PCH_SMM_BIT_DESC *BitDesc + ); + +/** + Write a specifying bit with the register + + @param[in] BitDesc The struct that includes register address, size in byte and bit number + @param[in] ValueToWrite The value to be wrote + @param[in] WriteClear If the rest bits of the register is write clear + +**/ +VOID +WriteBitDesc ( + CONST PCH_SMM_BIT_DESC *BitDesc, + CONST BOOLEAN ValueToWrite, + CONST BOOLEAN WriteClear + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PcieSmmClient.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PcieSmmClient.c new file mode 100644 index 0000000000..6d210f671b --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PcieSmmClient.c @@ -0,0 +1,38 @@ +/** @file + This function handle the register/unregister of PCH PCIe specific SMI events. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include <Register/PmcRegs.h> +#include <Register/PchPcieRpRegs.h> +#include <Library/CpuPcieInfoFruLib.h> +#include <CpuPcieInfo.h> +#include <Library/PchPcieRpLib.h> +#include <Library/PchInfoLib.h> +#include <Library/PchPciBdfLib.h> + +extern UINT32 mNumOfRootPorts; + +/** + Get CPU or PCH Pcie Root Port Device and Function Number by Root Port physical Number + + @param[in] RpNumber Root port physical number. (0-based) + @param[out] RpDev Return corresponding root port device number. + @param[out] RpFun Return corresponding root port function number. +**/ +VOID +GetPcieRpDevFun ( + IN UINTN RpIndex, + OUT UINTN *RpDev, + OUT UINTN *RpFun + ) +{ + if (RpIndex >= CpuRpIndex0 && RpIndex <= CpuRpIndex3) { + GetCpuPcieRpDevFun ((RpIndex - CpuRpIndex0), RpDev, RpFun); + } else { + *RpDev = PchPcieRpDevNumber (RpIndex); + *RpFun = PchPcieRpFuncNumber (RpIndex); + } +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/SmmGlobalsPch.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/SmmGlobalsPch.c new file mode 100644 index 0000000000..f66079884f --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/SmmGlobalsPch.c @@ -0,0 +1,20 @@ +/** @file + This driver is responsible for the registration of child drivers + and the abstraction of the PCH SMI sources. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <Register/TcoRegs.h> + +GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mTco1StsClear = + ( + B_TCO_IO_TCO1_STS_DMISERR | + B_TCO_IO_TCO1_STS_DMISMI | + B_TCO_IO_TCO1_STS_DMISCI | + B_TCO_IO_TCO1_STS_BIOSWR | + B_TCO_IO_TCO1_STS_NEWCENTURY | + B_TCO_IO_TCO1_STS_TIMEOUT | + B_TCO_IO_TCO1_STS_TCO_INT | + B_TCO_IO_TCO1_STS_SW_TCO_SMI + ); diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf new file mode 100644 index 0000000000..d73c12f964 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf @@ -0,0 +1,53 @@ +## @file +# Component description file for SmmControl module +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = SmmControl +FILE_GUID = A0BAD9F7-AB78-491b-B583-C52B7F84B9E0 +VERSION_STRING = 1.0 +MODULE_TYPE = DXE_RUNTIME_DRIVER +ENTRY_POINT = SmmControlDriverEntryInit +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + + + +[LibraryClasses] +IoLib +UefiDriverEntryPoint +DebugLib +UefiBootServicesTableLib +UefiRuntimeServicesTableLib +PmcLib +GpioLib + + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + + +[Sources] +SmmControlDriver.h +SmmControlDriver.c + + +[Protocols] +gEfiSmmControl2ProtocolGuid ## PRODUCES + + +[Guids] +gEfiEventVirtualAddressChangeGuid + + +[Depex] +TRUE diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c new file mode 100644 index 0000000000..8864d18787 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c @@ -0,0 +1,338 @@ +/** @file + This is the driver that publishes the SMM Control Protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <Library/IoLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Guid/EventGroup.h> +#include <Library/PmcLib.h> +#include <Library/GpioLib.h> +#include <IndustryStandard/Pci30.h> +#include <Register/PchRegsLpc.h> +#include <Register/SpiRegs.h> +#include <Register/PmcRegs.h> +#include "SmmControlDriver.h" + +STATIC SMM_CONTROL_PRIVATE_DATA mSmmControl; +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mABase; + +/** + Fixup internal data pointers so that the services can be called in virtual mode. + + @param[in] Event The event registered. + @param[in] Context Event context. + +**/ +VOID +EFIAPI +SmmControlVirtualAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Trigger)); + gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Clear)); +} + +/** + <b>SmmControl DXE RUNTIME Module Entry Point</b>\n + - <b>Introduction</b>\n + The SmmControl module is a DXE RUNTIME driver that provides a standard way + for other drivers to trigger software SMIs. + + - @pre + - PCH Power Management I/O space base address has already been programmed. + If SmmControl Runtime DXE driver is run before Status Code Runtime Protocol + is installed and there is the need to use Status code in the driver, it will + be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID to the dependency file. + - EFI_SMM_BASE2_PROTOCOL + - Documented in the System Management Mode Core Interface Specification. + + - @result + The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL documented in + System Management Mode Core Interface Specification. + + @param[in] ImageHandle Handle for the image of this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_STATUS Results of the installation of the SMM Control Protocol +**/ +EFI_STATUS +EFIAPI +SmmControlDriverEntryInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() Start\n")); + + // + // Get the Power Management I/O space base address. We assume that + // this base address has already been programmed if this driver is + // being run. + // + mABase = PmcGetAcpiBase (); + + Status = EFI_SUCCESS; + if (mABase != 0) { + // + // Install the instance of the protocol + // + mSmmControl.Signature = SMM_CONTROL_PRIVATE_DATA_SIGNATURE; + mSmmControl.Handle = ImageHandle; + + mSmmControl.SmmControl.Trigger = Activate; + mSmmControl.SmmControl.Clear = Deactivate; + mSmmControl.SmmControl.MinimumTriggerPeriod = 0; + + // + // Install our protocol interfaces on the device's handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mSmmControl.Handle, + &gEfiSmmControl2ProtocolGuid, + &mSmmControl.SmmControl, + NULL + ); + } else { + Status = EFI_DEVICE_ERROR; + return Status; + } + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + SmmControlVirtualAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &Event + ); + + DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() End\n")); + + return Status; +} + +/** + Trigger the software SMI + + @param[in] Command The value to be set on the software SMI command port + @param[in] Data The value to be set on the software SMI data port + + @retval EFI_SUCCESS Function completes successfully +**/ +EFI_STATUS +EFIAPI +SmmTrigger ( + IN UINT8 Command, + IN UINT8 Data + ) +{ + UINT32 OutputData; + UINT32 OutputPort; + + // + // Enable the APMC SMI + // + OutputPort = mABase + R_ACPI_IO_SMI_EN; + OutputData = IoRead32 ((UINTN) OutputPort); + OutputData |= (B_ACPI_IO_SMI_EN_APMC | B_ACPI_IO_SMI_EN_GBL_SMI); + DEBUG ( + (DEBUG_VERBOSE, + "The SMI Control Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite32 ( + (UINTN) OutputPort, + (UINT32) (OutputData) + ); + + OutputPort = R_PCH_IO_APM_STS; + OutputData = Data; + + // + // Write data to APM DATA PORT + // + IoWrite8 ( + (UINTN) OutputPort, + (UINT8) (OutputData) + ); + OutputPort = R_PCH_IO_APM_CNT; + OutputData = Command; + + // + // Generate the APMC SMI + // + IoWrite8 ( + (UINTN) OutputPort, + (UINT8) (OutputData) + ); + + return EFI_SUCCESS; +} + +/** + Clear the SMI status + + + @retval EFI_SUCCESS The function completes successfully + @retval EFI_DEVICE_ERROR Something error occurred +**/ +EFI_STATUS +EFIAPI +SmmClear ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 OutputData; + UINT32 OutputPort; + + Status = EFI_SUCCESS; + + // + // Clear the Power Button Override Status Bit, it gates EOS from being set. + // + OutputPort = mABase + R_ACPI_IO_PM1_STS; + OutputData = B_ACPI_IO_PM1_STS_PRBTNOR; + DEBUG ( + (DEBUG_VERBOSE, + "The PM1 Status Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite16 ( + (UINTN) OutputPort, + (UINT16) (OutputData) + ); + + // + // Clear the APM SMI Status Bit + // + OutputPort = mABase + R_ACPI_IO_SMI_STS; + OutputData = B_ACPI_IO_SMI_STS_APM; + DEBUG ( + (DEBUG_VERBOSE, + "The SMI Status Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite32 ( + (UINTN) OutputPort, + (UINT32) (OutputData) + ); + + // + // Set the EOS Bit + // + OutputPort = mABase + R_ACPI_IO_SMI_EN; + OutputData = IoRead32 ((UINTN) OutputPort); + OutputData |= B_ACPI_IO_SMI_EN_EOS; + DEBUG ( + (DEBUG_VERBOSE, + "The SMI Control Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite32 ( + (UINTN) OutputPort, + (UINT32) (OutputData) + ); + + // + // There is no need to read EOS back and check if it is set. + // This can lead to a reading of zero if an SMI occurs right after the SMI_EN port read + // but before the data is returned to the CPU. + // SMM Dispatcher should make sure that EOS is set after all SMI sources are processed. + // + return Status; +} + +/** + This routine generates an SMI + + @param[in] This The EFI SMM Control protocol instance + @param[in, out] CommandPort The buffer contains data to the command port + @param[in, out] DataPort The buffer contains data to the data port + @param[in] Periodic Periodic or not + @param[in] ActivationInterval Interval of periodic SMI + + @retval EFI Status Describing the result of the operation + @retval EFI_INVALID_PARAMETER Some parameter value passed is not supported +**/ +EFI_STATUS +EFIAPI +Activate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL * This, + IN OUT UINT8 *CommandPort OPTIONAL, + IN OUT UINT8 *DataPort OPTIONAL, + IN BOOLEAN Periodic OPTIONAL, + IN UINTN ActivationInterval OPTIONAL + ) +{ + EFI_STATUS Status; + UINT8 Command; + UINT8 Data; + + if (Periodic) { + DEBUG ((DEBUG_WARN, "Invalid parameter\n")); + return EFI_INVALID_PARAMETER; + } + + // + // Extract the values from CommandPort and DataPort + // + if (CommandPort == NULL) { + Command = 0xFF; + } else { + Command = *CommandPort; + } + + if (DataPort == NULL) { + Data = 0x00; + } else { + Data = *DataPort; + } + + // + // Clear any pending the APM SMI + // + Status = SmmClear (); + if (EFI_ERROR (Status)) { + return Status; + } + + return SmmTrigger (Command, Data); +} + +/** + This routine clears an SMI + + @param[in] This The EFI SMM Control protocol instance + @param[in] Periodic Periodic or not + + @retval EFI Status Describing the result of the operation + @retval EFI_INVALID_PARAMETER Some parameter value passed is not supported +**/ +EFI_STATUS +EFIAPI +Deactivate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN BOOLEAN Periodic OPTIONAL + ) +{ + if (Periodic) { + return EFI_INVALID_PARAMETER; + } + + return SmmClear (); +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h new file mode 100644 index 0000000000..a366de7d5e --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h @@ -0,0 +1,122 @@ +/** @file + Header file for SMM Control Driver. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _SMM_CONTROL_DRIVER_H_ +#define _SMM_CONTROL_DRIVER_H_ + +#include <Protocol/SmmControl2.h> + + +#define SMM_CONTROL_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', '4', 's', 'c') + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + EFI_SMM_CONTROL2_PROTOCOL SmmControl; +} SMM_CONTROL_PRIVATE_DATA; + +#define SMM_CONTROL_PRIVATE_DATA_FROM_THIS(a) CR (a, SMM_CONTROL_PRIVATE_DATA, SmmControl, SMM_CONTROL_DEV_SIGNATURE) + +// +// Prototypes +// + +/** + <b>SmmControl DXE RUNTIME Module Entry Point</b>\n + - <b>Introduction</b>\n + The SmmControl module is a DXE RUNTIME driver that provides a standard way + for other drivers to trigger software SMIs. + + - @pre + - PCH Power Management I/O space base address has already been programmed. + If SmmControl Runtime DXE driver is run before Status Code Runtime Protocol + is installed and there is the need to use Status code in the driver, it will + be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID to the dependency file. + - EFI_SMM_BASE2_PROTOCOL + - Documented in the System Management Mode Core Interface Specification. + + - @result + The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL documented in + System Management Mode Core Interface Specification. + + @param[in] ImageHandle Handle for the image of this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_STATUS Results of the installation of the SMM Control Protocol +**/ +EFI_STATUS +EFIAPI +SmmControlDriverEntryInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Trigger the software SMI + + @param[in] Command The value to be set on the software SMI command port + @param[in] Data The value to be set on the software SMI data port + + @retval EFI_SUCCESS Function completes successfully +**/ +EFI_STATUS +EFIAPI +SmmTrigger ( + IN UINT8 Command, + IN UINT8 Data + ); + +/** + Clear the SMI status + + + @retval EFI_SUCCESS The function completes successfully + @retval EFI_DEVICE_ERROR Something error occurred +**/ +EFI_STATUS +EFIAPI +SmmClear ( + VOID + ); + +/** + This routine generates an SMI + + @param[in] This The EFI SMM Control protocol instance + @param[in, out] ArgumentBuffer The buffer of argument + @param[in, out] ArgumentBufferSize The size of the argument buffer + @param[in] Periodic Periodic or not + @param[in] ActivationInterval Interval of periodic SMI + + @retval EFI Status Describing the result of the operation + @retval EFI_INVALID_PARAMETER Some parameter value passed is not supported +**/ +EFI_STATUS +EFIAPI +Activate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN OUT UINT8 *ArgumentBuffer OPTIONAL, + IN OUT UINT8 *ArgumentBufferSize OPTIONAL, + IN BOOLEAN Periodic OPTIONAL, + IN UINTN ActivationInterval OPTIONAL + ); + +/** + This routine clears an SMI + + @param[in] This The EFI SMM Control protocol instance + @param[in] Periodic Periodic or not + + @retval EFI Status Describing the result of the operation + @retval EFI_INVALID_PARAMETER Some parameter value passed is not supported +**/ +EFI_STATUS +EFIAPI +Deactivate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN BOOLEAN Periodic OPTIONAL + ); +#endif -- 2.36.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107572): https://edk2.groups.io/g/devel/message/107572 Mute This Topic: https://groups.io/mt/100551004/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [edk2-devel] [PATCH v2 5/7] AlderlakeSiliconPkg/Pch: Add drivers 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 5/7] AlderlakeSiliconPkg/Pch: Add drivers Saloni Kasbekar @ 2023-08-16 2:46 ` Chuang, Rosen 0 siblings, 0 replies; 14+ messages in thread From: Chuang, Rosen @ 2023-08-16 2:46 UTC (permalink / raw) To: Kasbekar, Saloni, devel@edk2.groups.io Cc: Chaganty, Rangasai V, Desimone, Nathaniel L, Oram, Isaac W Reviewed-by: Rosen Chuang < rosen.chuang@intel.com> -----Original Message----- From: Kasbekar, Saloni <saloni.kasbekar@intel.com> Sent: Saturday, August 5, 2023 1:38 AM To: devel@edk2.groups.io Cc: Kasbekar, Saloni <saloni.kasbekar@intel.com>; Chaganty, Rangasai V <rangasai.v.chaganty@intel.com>; Desimone, Nathaniel L <nathaniel.l.desimone@intel.com>; Oram, Isaac W <isaac.w.oram@intel.com>; Chuang, Rosen <rosen.chuang@intel.com> Subject: [PATCH v2 5/7] AlderlakeSiliconPkg/Pch: Add drivers Adds the following drivers: - PchSmiDispatcher - SmmControl Cc: Sai Chaganty <rangasai.v.chaganty@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Isaac Oram <isaac.w.oram@intel.com> Cc: Rosen Chuang <rosen.chuang@intel.com> Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com> --- .../Pch/PchSmiDispatcher/Smm/PchSmiDispatch.c | 1857 +++++++++++++++++ .../PchSmiDispatcher/Smm/PchSmiDispatcher.inf | 106 + .../Pch/PchSmiDispatcher/Smm/PchSmiHelper.h | 34 + .../Pch/PchSmiDispatcher/Smm/PchSmm.h | 1028 +++++++++ .../Pch/PchSmiDispatcher/Smm/PchSmmCore.c | 905 ++++++++ .../Pch/PchSmiDispatcher/Smm/PchSmmGpi.c | 255 +++ .../Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c | 332 +++ .../Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h | 163 ++ .../Smm/PchSmmPeriodicTimer.c | 670 ++++++ .../PchSmiDispatcher/Smm/PchSmmPowerButton.c | 77 + .../Pch/PchSmiDispatcher/Smm/PchSmmSw.c | 381 ++++ .../Pch/PchSmiDispatcher/Smm/PchSmmSx.c | 117 ++ .../Pch/PchSmiDispatcher/Smm/PchSmmUsb.c | 244 +++ .../Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.c | 682 ++++++ .../Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.h | 107 + .../Pch/PchSmiDispatcher/Smm/PcieSmmClient.c | 38 + .../Pch/PchSmiDispatcher/Smm/SmmGlobalsPch.c | 20 + .../Pch/SmmControl/RuntimeDxe/SmmControl.inf | 53 + .../SmmControl/RuntimeDxe/SmmControlDriver.c | 338 +++ .../SmmControl/RuntimeDxe/SmmControlDriver.h | 122 ++ 20 files changed, 7529 insertions(+) create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatch.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatcher.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowerButton.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PcieSmmClient.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/SmmGlobalsPch.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatch.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatch.c new file mode 100644 index 0000000000..637b9bb437 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatch.c @@ -0,0 +1,1857 @@ +/** @file + This function handle the register/unregister of PCH specific SMI events. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include <Library/SmiHandlerProfileLib.h> +#include <Register/PchRegs.h> +#include <Register/PmcRegs.h> +#include <Register/TcoRegs.h> +#include <Register/PchRegsLpc.h> +#include <Register/SpiRegs.h> +#include <Library/PchPciBdfLib.h> +#include <Library/S3BootScriptLib.h> +#include "PchSmiHelper.h" + + +/** + The internal function used to create and insert a database record + for SMI record of Pch Smi types. + + @param[in] SrcDesc The pointer to the SMI source description + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[in] PchSmiType Specific SMI type of PCH SMI + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. +**/ +EFI_STATUS +PchSmiRecordInsert ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc, + IN PCH_SMI_CALLBACK_FUNCTIONS DispatchFunction, + IN PCH_SMI_TYPES PchSmiType, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD Record; + + if (SrcDesc == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&Record, sizeof (DATABASE_RECORD)); + // + // Gather information about the registration request + // + Record.Signature = DATABASE_RECORD_SIGNATURE; + Record.PchSmiCallback = DispatchFunction; + Record.ProtocolType = PchSmiDispatchType; + Record.PchSmiType = PchSmiType; + + CopyMem (&Record.SrcDesc, SrcDesc, sizeof (PCH_SMM_SOURCE_DESC)); + Status = SmmCoreInsertRecord ( + &Record, + DispatchHandle + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + + +// +// TCO_STS bit that needs to be cleared +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mDescSrcTcoSts = { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } + }, + NULL_BIT_DESC_INITIALIZER +}; + +/** + Clear the TCO SMI status bit and block after the SMI handling is done + + @param[in] SrcDesc Pointer to the PCH SMI source description table + +**/ +VOID +EFIAPI +PchTcoSmiClearSourceAndBlock ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + PchSmmClearSourceAndBlock (SrcDesc); + // + // Any TCO-based status bits require special handling. + // SMI_STS.TCO_STS must be cleared in addition to the status bit in the TCO registers + // + PchSmmClearSource (&mDescSrcTcoSts); +} + +/** + Clear the TCO SMI status bit after the SMI handling is done + + @param[in] SrcDesc Pointer to the PCH SMI source description table + +**/ +VOID +EFIAPI +PchTcoSmiClearSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + PchSmmClearSource (SrcDesc); + // + // Any TCO-based status bits require special handling. + // SMI_STS.TCO_STS must be cleared in addition to the status bit in the TCO registers + // + PchSmmClearSource (&mDescSrcTcoSts); +} + +/** + Initialize Source descriptor structure + + @param[in] SrcDesc Pointer to the PCH SMI source description table + +**/ +VOID +EFIAPI +NullInitSourceDesc ( + PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + ZeroMem (SrcDesc, sizeof (PCH_SMM_SOURCE_DESC)); + SrcDesc->En[0].Reg.Type = PCH_SMM_ADDR_TYPE_NULL; + SrcDesc->En[1].Reg.Type = PCH_SMM_ADDR_TYPE_NULL; + SrcDesc->Sts[0].Reg.Type = PCH_SMM_ADDR_TYPE_NULL; + SrcDesc->PmcSmiSts.Reg.Type = PCH_SMM_ADDR_TYPE_NULL; +} + +// +// Mch srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescMch = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_DMISMI + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of MCH event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiMchRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescMch, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiMchType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSmiClearSource; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// TcoTimeout srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescTcoTimeout = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_TIMEOUT + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of TcoTimeout event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiTcoTimeoutRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescTcoTimeout, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiTcoTimeoutType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSmiClearSource; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// OsTco srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescOsTco = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_SW_TCO_SMI + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of OS TCO event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiOsTcoRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescOsTco, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiOsTcoType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSmiClearSource; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// Nmi +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescNmi = { + PCH_SMM_NO_FLAGS, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_CNT} + }, + S_TCO_IO_TCO1_CNT, + N_TCO_IO_TCO1_CNT_NMI2SMI_EN + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_NMI2SMI + } + }, + // + // NOTE: The status of NMI2SMI won't reflect to PMC SMI_STS. + // So skip the top level status check and check the TCO1_STS directly. + // + NULL_BIT_DESC_INITIALIZER +}; + +/** + The register function used to register SMI handler of NMI event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiNmiRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescNmi, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiNmiType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSmiClearSource; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// IntruderDetect srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescIntruderDet = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO2_CNT} + }, + S_TCO_IO_TCO2_CNT, + N_TCO_IO_TCO2_CNT_INTRD_SEL + } + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO2_STS} + }, + S_TCO_IO_TCO2_STS, + N_TCO_IO_TCO2_STS_INTRD_DET + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of Intruder Detect event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiIntruderDetRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescIntruderDet, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiIntruderDetectType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSmiClearSourceAndBlock; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// SpiBiosWp srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC mSrcDescSpiBiosWp = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + { + { + PCIE_ADDR_TYPE, + { 0xFFFFFFFF } // to be updated in PchSmiDispatchUpdateDescriptors + }, + S_SPI_CFG_BC, + N_SPI_CFG_BC_BLE + }, + }, + { + { + { + PCIE_ADDR_TYPE, + { 0xFFFFFFFF } // to be updated in PchSmiDispatchUpdateDescriptors + }, + S_SPI_CFG_BC, + N_SPI_CFG_BC_SYNC_SS + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + Special handling for SPI Write Protect + + @param[in] SrcDesc Not used +**/ +VOID +EFIAPI +PchTcoSpiWpClearSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + UINT64 SpiRegBase; + UINT32 BiosControl; + UINT32 Timeout; + + SpiRegBase = SpiPciCfgBase (); + PciSegmentAndThenOr32 ( + SpiRegBase + R_SPI_CFG_BC, + (UINT32) ~B_SPI_CFG_BC_ASYNC_SS, + B_SPI_CFG_BC_SYNC_SS + ); + // + // Ensure the SYNC is cleared + // + Timeout = 1000; + do { + BiosControl = PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BC); + Timeout--; + } while ((BiosControl & B_SPI_CFG_BC_SYNC_SS) && (Timeout > 0)); + + // + // Any TCO-based status bits require special handling. + // SMI_STS.TCO_STS must be cleared in addition to the status bit in the TCO registers + // + PchSmmClearSource (&mDescSrcTcoSts); +} + +/** + Set SMI_EN_TCO to enable TCO SMI. +**/ +STATIC +VOID +PchSetSmiEnTco ( + VOID + ) +{ + IoOr32 (mAcpiBaseAddr + R_ACPI_IO_SMI_EN, B_ACPI_IO_SMI_EN_TCO); +} + +/** + The register function used to register SMI handler of BIOS write protect event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiSpiBiosWpRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescSpiBiosWp, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiSpiBiosWpType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSpiWpClearSource; + PchTcoSpiWpClearSource (NULL); + // + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE. + // Only enable SMI_EN_TCO. + // + PchSetSmiEnTco (); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// LpcBiosWp srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC mSrcDescLpcBiosWp = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + { + { + PCIE_ADDR_TYPE, + { 0xFFFFFFFF } // to be updated in PchSmiDispatchUpdateDescriptors + }, + S_LPC_CFG_BC, + N_LPC_CFG_BC_LE + } + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_BIOSWR + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of LPC BIOS write protect event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiLpcBiosWpRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + if (IsEspiEnabled ()) { + // + // Status is D31F0's PCBC.BWPDS + // + ASSERT (FALSE); + return EFI_UNSUPPORTED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescLpcBiosWp, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiLpcBiosWpType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSmiClearSource; + PchSmmClearSource (&Record->SrcDesc); + // + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE. + // Only enable SMI_EN_TCO. + // + PchSetSmiEnTco (); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// NEWCENTURY_STS bit that needs to be cleared +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescNewCentury = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_NEWCENTURY + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of NEW CENTURY event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiNewCenturyRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescNewCentury, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiNewCenturyType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchTcoSmiClearSourceAndBlock; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiUnRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + return EFI_SUCCESS; +} + +// +// Pme srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescPme = { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_GPE0_EN_127_96} + }, + S_ACPI_IO_GPE0_EN_127_96, + N_ACPI_IO_GPE0_EN_127_96_PME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_GPE0_STS_127_96} + }, + S_ACPI_IO_GPE0_STS_127_96, + N_ACPI_IO_GPE0_STS_127_96_PME + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_GPE0 + } +}; + +/** + The register function used to register SMI handler of PME event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchAcpiSmiPmeRegister ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescPme, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchAcpiSmiPmeType, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescPme); + PchSmmEnableSource (&mSrcDescPme); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// PmeB0 srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescPmeB0 = { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_GPE0_EN_127_96} + }, + S_ACPI_IO_GPE0_EN_127_96, + N_ACPI_IO_GPE0_EN_127_96_PME_B0 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_GPE0_STS_127_96} + }, + S_ACPI_IO_GPE0_STS_127_96, + N_ACPI_IO_GPE0_STS_127_96_PME_B0 + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_GPE0 + } +}; +/** + The register function used to register SMI handler of PME B0 event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchAcpiSmiPmeB0Register ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescPmeB0, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchAcpiSmiPmeB0Type, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescPmeB0); + PchSmmEnableSource (&mSrcDescPmeB0); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// RtcAlarm srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescRtcAlarm = { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_EN} + }, + S_ACPI_IO_PM1_EN, + N_ACPI_IO_PM1_EN_RTC + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_STS} + }, + S_ACPI_IO_PM1_STS, + N_ACPI_IO_PM1_STS_RTC + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_PM1_STS_REG + } +}; + +/** + The register function used to register SMI handler of RTC alarm event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchAcpiSmiRtcAlarmRegister ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescRtcAlarm, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchAcpiSmiRtcAlarmType, + DispatchHandle + ); + + PchSmmClearSource (&mSrcDescRtcAlarm); + PchSmmEnableSource (&mSrcDescRtcAlarm); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// TmrOverflow srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescTmrOverflow = { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_EN} + }, + S_ACPI_IO_PM1_EN, + N_ACPI_IO_PM1_EN_TMROF + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_STS} + }, + S_ACPI_IO_PM1_STS, + N_ACPI_IO_PM1_STS_TMROF + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_PM1_STS_REG + } +}; + +/** + The register function used to register SMI handler of Timer Overflow event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchAcpiSmiTmrOverflowRegister ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescTmrOverflow, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchAcpiSmiTmrOverflowType, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescTmrOverflow); + PchSmmEnableSource (&mSrcDescTmrOverflow); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + + return Status; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchAcpiSmiUnRegister ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + DATABASE_RECORD *RecordToDelete; + EFI_STATUS Status; + + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle); + Status = PchSmmCoreUnRegister (NULL, DispatchHandle); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileUnregisterHandler (&gPchAcpiSmiDispatchProtocolGuid, RecordToDelete->Callback, NULL, 0); + } + return Status; +} + +// +// SerialIrq srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSerialIrq = { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SERIRQ + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SERIRQ + } +}; + +/** + The register function used to register SMI handler of Serial IRQ event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchSmiSerialIrqRegister ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescSerialIrq, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchSmiSerialIrqType, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescSerialIrq); + PchSmmEnableSource (&mSrcDescSerialIrq); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// McSmi srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescMcSmi = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_MCSMI + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_MCSMI + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_MCSMI + } +}; + +/** + The register function used to register SMI handler of MCSMI event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchSmiMcSmiRegister ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescMcSmi, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchSmiMcSmiType, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescMcSmi); + PchSmmEnableSource (&mSrcDescMcSmi); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// SmBus srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSmbus = { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SMBUS + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SMBUS + } +}; + +/** + The register function used to register SMI handler of SMBUS event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchSmiSmbusRegister ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescSmbus, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchSmiSmBusType, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescSmbus); + PchSmmEnableSource (&mSrcDescSmbus); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +// +// SpiAsyncSmi srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC mSrcDescSpiAsyncSmi = { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + { 0xFFFFFFFF } // to be updated in PchSmiDispatchUpdateDescriptors + }, + S_SPI_CFG_BC, + N_SPI_CFG_BC_ASE_BWP + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + { 0xFFFFFFFF } // to be updated in PchSmiDispatchUpdateDescriptors + }, + S_SPI_CFG_BC, + N_SPI_CFG_BC_ASYNC_SS + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SPI + } +}; + +/** + Special handling for SPI Asynchronous SMI. + If SPI ASYNC SMI is enabled, De-assert SMI is sent when Flash Cycle Done + transitions from 1 to 0 or when the SMI enable becomes false. + + @param[in] SrcDesc Not used +**/ +VOID +EFIAPI +PchSmiSpiAsyncClearSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + UINT64 SpiRegBase; + UINT32 SpiBar0; + + SpiRegBase = SpiPciCfgBase (); + SpiBar0 = PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BAR0) & ~(B_SPI_CFG_BAR0_MASK); + if (SpiBar0 != PCH_SPI_BASE_ADDRESS) { + // + // Temporary disable MSE, and override with SPI reserved MMIO address, then enable MSE. + // + SpiBar0 = PCH_SPI_BASE_ADDRESS; + PciSegmentAnd8 (SpiRegBase + PCI_COMMAND_OFFSET, (UINT8) ~EFI_PCI_COMMAND_MEMORY_SPACE); + PciSegmentWrite32 (SpiRegBase + R_SPI_CFG_BAR0, SpiBar0); + PciSegmentOr8 (SpiRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE); + } + + MmioOr32 (SpiBar0 + R_SPI_MEM_HSFSC, B_SPI_MEM_HSFSC_FDONE); +} + +/** + Special handling to enable SPI Asynchronous SMI +**/ +VOID +PchSmiSpiAsyncEnableSource ( + VOID + ) +{ + UINT64 SpiRegBase; + UINT32 Data32And; + UINT32 Data32Or; + + SpiRegBase = SpiPciCfgBase (); + Data32And = (UINT32) ~B_SPI_CFG_BC_SYNC_SS; + Data32Or = B_SPI_CFG_BC_ASE_BWP; + + PciSegmentAndThenOr32 ( + SpiRegBase + R_SPI_CFG_BC, + Data32And, + Data32Or + ); + S3BootScriptSavePciCfgReadWrite ( + S3BootScriptWidthUint32, + SpiRegBase + R_SPI_CFG_BC, + (VOID*) &Data32Or, + (VOID*) &Data32And + ); + + // + // Clear the source + // + PchSmiSpiAsyncClearSource (NULL); +} + +/** + The register function used to register SMI handler of SPI Asynchronous event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchSmiSpiAsyncRegister ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = PchSmiRecordInsert ( + &mSrcDescSpiAsyncSmi, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchSmiSpiAsyncType, + DispatchHandle + ); + + if (!EFI_ERROR (Status)) { + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource = PchSmiSpiAsyncClearSource; + PchSmiSpiAsyncClearSource (NULL); + PchSmiSpiAsyncEnableSource (); + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0); + } + return Status; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered + @retval EFI_ACCESS_DENIED Return access denied since SPI aync SMI handler is not able to disabled. +**/ +EFI_STATUS +EFIAPI +PchSmiUnRegister ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + DATABASE_RECORD *Record; + UINT64 SpiRegBase; + EFI_STATUS Status; + + Record = DATABASE_RECORD_FROM_LINK (DispatchHandle); + if ((Record->SrcDesc.En[0].Reg.Type == PCIE_ADDR_TYPE) && + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Dev == SpiDevNumber ()) && + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc == SpiFuncNumber ()) && + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Reg == R_SPI_CFG_BC) && + (Record->SrcDesc.En[0].Bit == N_SPI_CFG_BC_ASE_BWP)) { + SpiRegBase = SpiPciCfgBase (); + if (PciSegmentRead8 (SpiRegBase + R_SPI_CFG_BC) & B_SPI_CFG_BC_BILD) { + // + // SPI Asynchronous SMI cannot be disabled + // + return EFI_ACCESS_DENIED; + } + } + Status = PchSmmCoreUnRegister (NULL, DispatchHandle); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileUnregisterHandler (&gPchSmiDispatchProtocolGuid, Record->Callback, NULL, 0); + } + return Status; +} + + +/** + Declaration of PCH TCO SMI DISPATCH PROTOCOL instance +**/ +PCH_TCO_SMI_DISPATCH_PROTOCOL mPchTcoSmiDispatchProtocol = { + PCH_TCO_SMI_DISPATCH_REVISION, // Revision + PchTcoSmiUnRegister, // Unregister + PchTcoSmiMchRegister, // Mch + PchTcoSmiTcoTimeoutRegister, // TcoTimeout + PchTcoSmiOsTcoRegister, // OsTco + PchTcoSmiNmiRegister, // Nmi + PchTcoSmiIntruderDetRegister, // IntruderDectect + PchTcoSmiSpiBiosWpRegister, // SpiBiosWp + PchTcoSmiLpcBiosWpRegister, // LpcBiosWp + PchTcoSmiNewCenturyRegister // NewCentury +}; + +/** + Declaration of PCH ACPI SMI DISPATCH PROTOCOL instance +**/ +PCH_ACPI_SMI_DISPATCH_PROTOCOL mPchAcpiSmiDispatchProtocol = { + PCH_ACPI_SMI_DISPATCH_REVISION, // Revision + PchAcpiSmiUnRegister, // Unregister + PchAcpiSmiPmeRegister, // Pme + PchAcpiSmiPmeB0Register, // PmeB0 + PchAcpiSmiRtcAlarmRegister, // RtcAlarm + PchAcpiSmiTmrOverflowRegister // TmrOverflow +}; + +/** + Declaration of MISC PCH SMI DISPATCH PROTOCOL instance +**/ +PCH_SMI_DISPATCH_PROTOCOL mPchSmiDispatchProtocol = { + PCH_SMI_DISPATCH_REVISION, // Revision + PchSmiUnRegister, // Unregister + PchSmiSerialIrqRegister, // SerialIrq + PchSmiMcSmiRegister, // McSmi + PchSmiSmbusRegister, // SmBus + PchSmiSpiAsyncRegister // SpiAsync +}; + +/** + Install protocols of PCH specifics SMI types, including + PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC SMI types. + + @retval the result of protocol installation +**/ +EFI_STATUS +InstallPchSmiDispatchProtocols ( + VOID + ) +{ + EFI_HANDLE Handle; + EFI_STATUS Status; + + Handle = NULL; + Status = gSmst->SmmInstallProtocolInterface ( + &Handle, + &gPchTcoSmiDispatchProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPchTcoSmiDispatchProtocol + ); + + Status = gSmst->SmmInstallProtocolInterface ( + &Handle, + &gPchAcpiSmiDispatchProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPchAcpiSmiDispatchProtocol + ); + Status = gSmst->SmmInstallProtocolInterface ( + &Handle, + &gPchSmiDispatchProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPchSmiDispatchProtocol + ); + + return Status; +} + +/** + The function to dispatch all callback function of PCH SMI types. + + @retval EFI_SUCCESS Function successfully completed + @retval EFI_UNSUPPORTED no +**/ +EFI_STATUS +PchSmiTypeCallbackDispatcher ( + IN DATABASE_RECORD *Record + ) +{ + EFI_STATUS Status; + PCH_SMI_TYPES PchSmiType; + + PchSmiType = Record->PchSmiType; + Status = EFI_SUCCESS; + + switch (PchSmiType) { + case PchTcoSmiMchType: + case PchTcoSmiTcoTimeoutType: + case PchTcoSmiOsTcoType: + case PchTcoSmiNmiType: + case PchTcoSmiIntruderDetectType: + case PchTcoSmiSpiBiosWpType: + case PchTcoSmiLpcBiosWpType: + case PchTcoSmiNewCenturyType: + ((PCH_TCO_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link); + break; + case PchPcieSmiRpHotplugType: + case PchPcieSmiRpLinkActiveType: + case PchPcieSmiRpLinkEqType: + break; + case PchAcpiSmiPmeType: + case PchAcpiSmiPmeB0Type: + case PchAcpiSmiRtcAlarmType: + case PchAcpiSmiTmrOverflowType: + ((PCH_ACPI_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link); + break; + case PchSmiSerialIrqType: + case PchSmiMcSmiType: + case PchSmiSmBusType: + case PchSmiSpiAsyncType: + case PchIoTrapSmiType: ///< internal type for IoTrap + ((PCH_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link); + break; + default: + Status = EFI_UNSUPPORTED; + break; + } + + return Status; +} + +/** + Performs update of SmiDispatch descriptors with values that have to be evaluated during runtime. +**/ +VOID +PchSmiDispatchUpdateDescriptors ( + VOID + ) +{ + UINT32 SpiPcieAddr; + UINT32 LpcPcieAddr; + + SpiPcieAddr = ((DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (SpiDevNumber () << 19) | + (SpiFuncNumber () << 16) | + R_SPI_CFG_BC); + LpcPcieAddr = ((DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (LpcDevNumber () << 19) | + (LpcFuncNumber () << 16) | + R_LPC_CFG_BC); + // + // mSrcDescSpiBiosWp + // + mSrcDescSpiBiosWp.En[1].Reg.Data.raw = SpiPcieAddr; + mSrcDescSpiBiosWp.Sts[0].Reg.Data.raw = SpiPcieAddr; + + // + // mSrcDescLpcBiosWp + // + mSrcDescLpcBiosWp.En[1].Reg.Data.raw = LpcPcieAddr; + + // + // mSrcDescSpiAsyncSmi + // + mSrcDescSpiAsyncSmi.En[0].Reg.Data.raw = SpiPcieAddr; + mSrcDescSpiAsyncSmi.Sts[0].Reg.Data.raw = SpiPcieAddr; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatcher.inf b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatcher.inf new file mode 100644 index 0000000000..7031b5193a --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatcher.inf @@ -0,0 +1,106 @@ +## @file +# Component description file for the Pch SMI Dispatch Handlers module +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = PchSmiDispatcher +FILE_GUID = B0D6ED53-B844-43f5-BD2F-61095264E77E +VERSION_STRING = 1.0 +MODULE_TYPE = DXE_SMM_DRIVER +PI_SPECIFICATION_VERSION = 1.10 +ENTRY_POINT = InitializePchSmmDispatcher + + +[LibraryClasses] +UefiBootServicesTableLib +UefiDriverEntryPoint +IoLib +DebugLib +PcdLib +BaseLib +BaseMemoryLib +HobLib +DevicePathLib +PchCycleDecodingLib +PchPcieRpLib +PchPcrLib +SmmServicesTableLib +ReportStatusCodeLib +PerformanceLib +DxeServicesTableLib +GpioLib +GpioPrivateLib +EspiLib +S3BootScriptLib +ConfigBlockLib +PmcPrivateLib +PmcLib +SmiHandlerProfileLib +PchPciBdfLib +P2SbSidebandAccessLib +CpuPcieInfoFruLib + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + + +[Pcd] +# Progress Code for S3 Suspend start. +# PROGRESS_CODE_S3_SUSPEND_START = (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_SPECIFIC | 0x00000000)) = 0x03078000 +gSiPkgTokenSpaceGuid.PcdProgressCodeS3SuspendStart +# Progress Code for S3 Suspend end. +# PROGRESS_CODE_S3_SUSPEND_END = (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_SPECIFIC | 0x00000001)) = 0x03078001 +gSiPkgTokenSpaceGuid.PcdProgressCodeS3SuspendEnd +gSiPkgTokenSpaceGuid.PcdEfiGcdAllocateType + + +[Sources] +PchSmm.h +PchSmmCore.c +PchSmmHelpers.c +PchxSmmHelpers.c +SmmGlobalsPch.c +PchSmmUsb.c +PchSmmGpi.c +PchSmmPowerButton.c +PchSmmSw.c +PchSmmSx.c +PchSmmPeriodicTimer.c +PchSmiDispatch.c +PcieSmmClient.c + + +[Protocols] +gEfiPciRootBridgeIoProtocolGuid ## CONSUMES +gEfiSmmGpiDispatch2ProtocolGuid ## PRODUCES +gEfiSmmSxDispatch2ProtocolGuid ## PRODUCES +gEfiSmmSwDispatch2ProtocolGuid ## PRODUCES +gEfiSmmUsbDispatch2ProtocolGuid ## PRODUCES +gEfiSmmPowerButtonDispatch2ProtocolGuid ## PRODUCES +gEfiSmmPeriodicTimerDispatch2ProtocolGuid ## PRODUCES +gEfiSmmBase2ProtocolGuid ## CONSUMES +gEfiSmmCpuProtocolGuid ## CONSUMES +gEfiSmmReadyToLockProtocolGuid ## CONSUMES +gPchTcoSmiDispatchProtocolGuid ## PRODUCES +gPchPcieSmiDispatchProtocolGuid ## PRODUCES +gPchAcpiSmiDispatchProtocolGuid ## PRODUCES +gPchSmiDispatchProtocolGuid ## PRODUCES +gPchEspiSmiDispatchProtocolGuid ## PRODUCES +gPchSmmPeriodicTimerControlGuid ## PRODUCES + + +[Guids] + + +[Depex] +gEfiPciRootBridgeIoProtocolGuid AND +gEfiPciHostBridgeResourceAllocationProtocolGuid AND ## This is to ensure that PCI MMIO resource has been prepared and available for this driver to allocate. +gEfiSmmCpuProtocolGuid AND +gEfiSmmBase2ProtocolGuid + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper.h new file mode 100644 index 0000000000..5ec9455797 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper.h @@ -0,0 +1,34 @@ +/** @file + eSPI SMI Dispatch header + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _PCH_SMI_HELPER_H_ +#define _PCH_SMI_HELPER_H_ +#include <Uefi/UefiBaseType.h> + +/** + Get CPU or PCH Pcie Root Port Device and Function Number by Root Port physical Number + + @param[in] RpNumber Root port physical number. (0-based) + @param[out] RpDev Return corresponding root port device number. + @param[out] RpFun Return corresponding root port function number. +**/ +VOID +GetPcieRpDevFun ( + IN UINTN RpIndex, + OUT UINTN *RpDev, + OUT UINTN *RpFun + ); + +/** + Performs update of SmiDispatch descriptors with values that have to be evaluated during runtime. +**/ +VOID +PchSmiDispatchUpdateDescriptors ( + VOID + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h new file mode 100644 index 0000000000..41969a0ec7 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h @@ -0,0 +1,1028 @@ +/** @file + Prototypes and defines for the PCH SMM Dispatcher. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_SMM_H_ +#define _PCH_SMM_H_ + +#include <Uefi.h> +#include <Protocol/PciRootBridgeIo.h> +#include <Protocol/LoadedImage.h> +#include <Protocol/SmmControl2.h> +#include <Protocol/SmmUsbDispatch2.h> +#include <Protocol/SmmSxDispatch2.h> +#include <Protocol/SmmSwDispatch2.h> +#include <Protocol/SmmGpiDispatch2.h> +#include <Protocol/SmmPowerButtonDispatch2.h> +#include <Protocol/SmmPeriodicTimerDispatch2.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DevicePathLib.h> +#include <Library/SmmServicesTableLib.h> +#include <Library/ReportStatusCodeLib.h> +#include <Library/PerformanceLib.h> +#include <Protocol/SmmReadyToLock.h> +#include <IndustryStandard/Pci30.h> +#include <Library/PchCycleDecodingLib.h> +#include <Library/PchPcrLib.h> +#include <Library/PciSegmentLib.h> +#include <Library/GpioLib.h> +#include <Library/PchInfoLib.h> +#include <Library/EspiLib.h> +#include <Library/GpioPrivateLib.h> +#include <Protocol/PchTcoSmiDispatch.h> +#include <Protocol/PchPcieSmiDispatch.h> +#include <Protocol/PchAcpiSmiDispatch.h> +#include <Protocol/PchSmiDispatch.h> +#include <Library/PmcLib.h> + +#define EFI_BAD_POINTER 0xAFAFAFAFAFAFAFAFULL + +extern BOOLEAN mReadyToLock; + +/// +/// Define an enumeration for all the supported protocols +/// +#define PCH_SMM_PROTOCOL_TYPE_MAX 6 + +typedef enum { + UsbType, + SxType, + SwType, + GpiType, + PowerButtonType, + PeriodicTimerType, + PchSmiDispatchType, + PchSmmProtocolTypeMax +} PCH_SMM_PROTOCOL_TYPE; + +/// +/// Define all the supported types of PCH SMI +/// +typedef enum { + PchTcoSmiMchType, + PchTcoSmiTcoTimeoutType, + PchTcoSmiOsTcoType, + PchTcoSmiNmiType, + PchTcoSmiIntruderDetectType, + PchTcoSmiSpiBiosWpType, + PchTcoSmiLpcBiosWpType, + PchTcoSmiNewCenturyType, + PchPcieSmiRpHotplugType, + PchPcieSmiRpLinkActiveType, + PchPcieSmiRpLinkEqType, + PchAcpiSmiPmeType, + PchAcpiSmiPmeB0Type, + PchAcpiSmiRtcAlarmType, + PchAcpiSmiTmrOverflowType, + PchEspiSmiEspiSlaveType, + PchSmiSerialIrqType, + PchSmiMcSmiType, + PchSmiSmBusType, + PchSmiSpiAsyncType, + PchIoTrapSmiType ///< internal SMI type +} PCH_SMI_TYPES; + +/// +/// Generic funciton pointer to cover all Pch SMI function pointer types +/// +typedef +VOID +(EFIAPI *PCH_SMI_CALLBACK_FUNCTIONS) ( + IN EFI_HANDLE DispatchHandle, + ... + ); + + +/// +/// SPECIFYING A REGISTER +/// We want a general way of referring to addresses. For this case, we'll only +/// need addresses in the ACPI table (and the TCO entries within the ACPI table). +/// However, it's interesting to consider what it would take to support other types +/// of addresses. To address Will's concern, I think it prudent to accommodate it +/// early on in the design. +/// +/// Addresses we need to consider: +/// +/// Type: Required: +/// I/O Yes +/// ACPI (special case of I/O) Only if we want to +/// TCO (special case of I/O) Only if we want to +/// GPIO (special case of MMIO) Only if we want to +/// Memory (or Memory Mapped I/O) Only if we want to +/// PCIE Yes, for BiosWp +/// +typedef enum { + /// + /// IO_ADDR_TYPE, /// unimplemented + /// + ACPI_ADDR_TYPE, + TCO_ADDR_TYPE, + /// + /// MEMORY_ADDR_TYPE, /// unimplemented + /// + GPIO_ADDR_TYPE, + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCIE_ADDR_TYPE, + PCR_ADDR_TYPE, + NUM_ADDR_TYPES, ///< count of items in this enum + PCH_SMM_ADDR_TYPE_NULL = -1 ///< sentinel to indicate NULL or to signal end of arrays +} ADDR_TYPE; + +// +// Assumption: 32-bits -- enum's evaluate to integer +// Assumption: This code will only run on IA-32. Justification: IA-64 doesn't have SMIs. +// We don't have to worry about 64-bit addresses. +// Typedef the size of addresses in case the numbers I'm using are wrong or in case +// this changes. This is a good idea because PCI_ADDR will change, for example, when +// we add support for PciExpress. +// +typedef UINT16 IO_ADDR; +typedef IO_ADDR ACPI_ADDR; ///< can omit +typedef IO_ADDR TCO_ADDR; ///< can omit +typedef UINTN MEM_ADDR; +typedef MEM_ADDR *MEMORY_MAPPED_IO_ADDRESS; +typedef MEM_ADDR *GPIO_ADDR; +typedef union { + UINT32 Raw; + struct { + UINT32 Reg: 16; + UINT32 Fnc: 3; + UINT32 Dev: 5; + UINT32 Bus: 8; + } Fields; +} PCIE_ADDR; + +typedef union { + UINT32 Raw; + struct { + UINT16 Offset; + UINT8 Pid; + UINT8 Base; + } Fields; +} PCR_ADDR; + +typedef struct { + ADDR_TYPE Type; + union { + /// + /// used to initialize during declaration/definition + /// + UINT32 raw; + + /// + /// used to access useful data + /// + IO_ADDR io; + ACPI_ADDR acpi; + TCO_ADDR tco; + GPIO_ADDR gpio; + MEM_ADDR mem; + MEMORY_MAPPED_IO_ADDRESS Mmio; + PCIE_ADDR pcie; + PCR_ADDR Pcr; + + } Data; + +} PCH_SMM_ADDRESS; + +/// +/// SPECIFYING BITS WITHIN A REGISTER +/// Here's a struct that helps us specify a source or enable bit. +/// +typedef struct { + PCH_SMM_ADDRESS Reg; + UINT8 SizeInBytes; ///< of the register + UINT8 Bit; +} PCH_SMM_BIT_DESC; + +// +// Sometimes, we'll have bit descriptions that are unused. It'd be great to have a +// way to easily identify them: +// +#define IS_BIT_DESC_NULL(BitDesc) ((BitDesc).Reg.Type == PCH_SMM_ADDR_TYPE_NULL) ///< "returns" true when BitDesc is NULL +#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type = PCH_SMM_ADDR_TYPE_NULL) ///< will "return" an integer w/ value of 0 +#define NULL_BIT_DESC_INITIALIZER \ + { \ + { \ + PCH_SMM_ADDR_TYPE_NULL, \ + { \ + 0 \ + } \ + }, \ + 0, 0 \ + } +// +// I'd like a type to specify the callback's Sts & En bits because they'll +// be commonly used together: +// +#define NUM_EN_BITS 2 +#define NUM_STS_BITS 1 + +// +// Flags +// +typedef UINT8 PCH_SMM_SOURCE_FLAGS; + +// +// Flags required to describe the event source +// +#define PCH_SMM_NO_FLAGS 0 +#define PCH_SMM_SCI_EN_DEPENDENT 1 + +typedef struct { + PCH_SMM_SOURCE_FLAGS Flags; + PCH_SMM_BIT_DESC En[NUM_EN_BITS]; ///< Describes the enable bit(s) for the SMI event + PCH_SMM_BIT_DESC Sts[NUM_STS_BITS]; ///< Describes the secondary status bit for the SMI event. Might be the same as TopLevelSmi + PCH_SMM_BIT_DESC PmcSmiSts; ///< Refereing to the top level status bit in PMC SMI_STS, i.e. R_PCH_SMI_STS +} PCH_SMM_SOURCE_DESC; + +/// +/// Used to initialize null source descriptor +/// +#define NULL_SOURCE_DESC_INITIALIZER \ + { \ + PCH_SMM_NO_FLAGS, \ + { \ + NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \ + }, \ + { \ + NULL_BIT_DESC_INITIALIZER \ + }, \ + NULL_BIT_DESC_INITIALIZER \ + } + +/// +/// Define a PCIE RP event context for SmiProfileHandlerInfo tool +/// +typedef struct { + PCH_SMI_TYPES PchSmiType; + UINTN RpIndex; +} PCH_SMM_PCIE_REGISTER_CONTEXT; + +/// +/// CHILD CONTEXTS +/// To keep consistent w/ the architecture, we'll need to provide the context +/// to the child when we call its callback function. After talking with Will, +/// we agreed that we'll need functions to "dig" the context out of the hardware +/// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to compare those +/// contexts to prevent unnecessary dispatches. I'd like a general type for these +/// "GetContext" functions, so I'll need a union of all the protocol contexts for +/// our internal use: +/// +typedef union { + // + // (in no particular order) + // + EFI_SMM_SX_REGISTER_CONTEXT Sx; + EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer; + EFI_SMM_SW_REGISTER_CONTEXT Sw; + EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT PowerButton; + EFI_SMM_USB_REGISTER_CONTEXT Usb; + EFI_SMM_GPI_REGISTER_CONTEXT Gpi; + PCH_SMM_PCIE_REGISTER_CONTEXT Pcie; +} PCH_SMM_CONTEXT; + +/// +/// Misc data for PchDispatcher usage. +/// For PeriodicTimer, since the ElapsedTime is removed from EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT of EDKII, +/// and PchDispatcher needs it for every record. Thus move it here to support ElapsedTime. +/// +typedef struct { + UINTN ElapsedTime; + /// + /// A switch to control periodic timer SMI enabling + /// + BOOLEAN TimerSmiEnabled; +} PCH_SMM_MISC_DATA; + +// +// Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes +// +typedef struct _DATABASE_RECORD DATABASE_RECORD; + +/// +/// Assumption: the GET_CONTEXT function will be as small and simple as possible. +/// Assumption: We don't need to pass in an enumeration for the protocol because each +/// GET_CONTEXT function is written for only one protocol. +/// We also need a function to compare contexts to see if the child should be dispatched +/// In addition, we need a function to acquire CommBuffer and CommBufferSize for +/// dispatch callback function of EDKII native support. +/// +typedef +VOID +(EFIAPI *GET_CONTEXT) ( + IN DATABASE_RECORD * Record, + OUT PCH_SMM_CONTEXT * Context + ); + +typedef +BOOLEAN +(EFIAPI *CMP_CONTEXT) ( + IN PCH_SMM_CONTEXT * Context1, + IN PCH_SMM_CONTEXT * Context2 + ); + +typedef +VOID +(EFIAPI *GET_COMMBUFFER) ( + IN DATABASE_RECORD * Record, + OUT VOID **CommBuffer, + OUT UINTN * CommBufferSize + ); + +/// +/// Finally, every protocol will require a "Get Context" and "Compare Context" call, so +/// we may as well wrap that up in a table, too. +/// +typedef struct { + GET_CONTEXT GetContext; + CMP_CONTEXT CmpContext; + GET_COMMBUFFER GetCommBuffer; +} CONTEXT_FUNCTIONS; + +extern CONTEXT_FUNCTIONS ContextFunctions[PCH_SMM_PROTOCOL_TYPE_MAX]; + +/// +/// MAPPING CONTEXT TO BIT DESCRIPTIONS +/// I'd like to have a general approach to mapping contexts to bit descriptions. +/// Sometimes, we'll find that we can use table lookups or constant assignments; +/// other times, we'll find that we'll need to use a function to perform the mapping. +/// If we define a macro to mask that process, we'll never have to change the code. +/// I don't know if this is desirable or not -- if it isn't, then we can get rid +/// of the macros and just use function calls or variable assignments. Doesn't matter +/// to me. +/// Mapping complex contexts requires a function +/// + +/** + Maps a USB context to a source description. + + @param[in] Context The context we need to map. Type must be USB. + @param[out] SrcDesc The source description that corresponds to the given context. + +**/ +VOID +MapUsbToSrcDesc ( + IN PCH_SMM_CONTEXT *Context, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Figure out which timer the child is requesting and + send back the source description + + @param[in] DispatchContext The pointer to the Dispatch Context instances + @param[out] SrcDesc The pointer to the source description + +**/ +VOID +MapPeriodicTimerToSrcDesc ( + IN PCH_SMM_CONTEXT *DispatchContext, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ); + +// +// Mapping simple contexts can be done by assignment or lookup table +// +extern CONST PCH_SMM_SOURCE_DESC mSxSourceDesc; +extern CONST PCH_SMM_SOURCE_DESC mPowerButtonSourceDesc; +extern CONST PCH_SMM_SOURCE_DESC mSrcDescNewCentury; +extern CONST PCH_SMM_SOURCE_DESC mGpiSourceDescTemplate; + +/// +/// For PCHx, APMC is UINT8 port, so the MAX SWI Value is 0xFF. +/// +#define MAXIMUM_SWI_VALUE 0xFF +/// +/// Open: Need to make sure this kind of type cast will actually work. +/// May need an intermediate form w/ two VOID* arguments. I'll figure +/// that out when I start compiling. +/// +typedef +VOID +(EFIAPI *PCH_SMM_CLEAR_SOURCE) ( + CONST PCH_SMM_SOURCE_DESC * SrcDesc + ); + +/// +/// "DATABASE" RECORD +/// Linked list data structures +/// +#define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C') + +struct _DATABASE_RECORD { + UINT32 Signature; + LIST_ENTRY Link; + BOOLEAN Processed; + /// + /// Status and Enable bit description + /// + PCH_SMM_SOURCE_DESC SrcDesc; + + /// + /// Callback function + /// + EFI_SMM_HANDLER_ENTRY_POINT2 Callback; + PCH_SMM_CONTEXT ChildContext; + UINTN ContextSize; + + /// + /// Special handling hooks -- init them to NULL if unused/unneeded + /// + PCH_SMM_CLEAR_SOURCE ClearSource; + + /// + /// Functions required to make callback code general + /// + CONTEXT_FUNCTIONS ContextFunctions; + + /// + /// The protocol that this record dispatches + /// + PCH_SMM_PROTOCOL_TYPE ProtocolType; + + /// + /// Misc data for private usage + /// + PCH_SMM_MISC_DATA MiscData; + + /// + /// PCH SMI callback function + /// + PCH_SMI_CALLBACK_FUNCTIONS PchSmiCallback; + /// + /// Indicate the PCH SMI types. + /// + PCH_SMI_TYPES PchSmiType; +}; + +#define DATABASE_RECORD_FROM_LINK(_record) CR (_record, DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE) +#define DATABASE_RECORD_FROM_CHILDCONTEXT(_record) CR (_record, DATABASE_RECORD, ChildContext, DATABASE_RECORD_SIGNATURE) + +/// +/// HOOKING INTO THE ARCHITECTURE +/// +typedef +EFI_STATUS +(EFIAPI *PCH_SMM_GENERIC_REGISTER) ( + IN VOID **This, + IN VOID *DispatchFunction, + IN VOID *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ); +typedef +EFI_STATUS +(EFIAPI *PCH_SMM_GENERIC_UNREGISTER) ( + IN VOID **This, + IN EFI_HANDLE DispatchHandle + ); + +/// +/// Define a memory "stamp" equivalent in size and function to most of the protocols +/// +typedef struct { + PCH_SMM_GENERIC_REGISTER Register; + PCH_SMM_GENERIC_UNREGISTER Unregister; + UINTN Extra1; + UINTN Extra2; ///< may not need this one +} PCH_SMM_GENERIC_PROTOCOL; + +/** + Register a child SMI dispatch function with a parent SMM driver. + + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL instance. + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source. + @param[in] DispatchContext Pointer to the dispatch function's context. + @param[out] DispatchHandle Handle of dispatch function, for when interfacing + with the parent SMM driver, will be the address of linked + list link in the call back record. + + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create database record + @retval EFI_INVALID_PARAMETER The input parameter is invalid + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. +**/ +EFI_STATUS +EFIAPI +PchPiSmmCoreRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN PCH_SMM_CONTEXT *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchPiSmmCoreUnRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE *DispatchHandle + ); + + +/** + Unregister a child SMI source dispatch function with a parent SMM driver. + + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +EFIAPI +PchSmmCoreUnRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE *DispatchHandle + ); + +typedef union { + PCH_SMM_GENERIC_PROTOCOL Generic; + EFI_SMM_USB_DISPATCH2_PROTOCOL Usb; + EFI_SMM_SX_DISPATCH2_PROTOCOL Sx; + EFI_SMM_SW_DISPATCH2_PROTOCOL Sw; + EFI_SMM_GPI_DISPATCH2_PROTOCOL Gpi; + EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL PowerButton; + EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL PeriodicTimer; +} PCH_SMM_PROTOCOL; + +/// +/// Define a structure to help us identify the generic protocol +/// +#define PROTOCOL_SIGNATURE SIGNATURE_32 ('P', 'R', 'O', 'T') + +typedef struct { + UINTN Signature; + + PCH_SMM_PROTOCOL_TYPE Type; + EFI_GUID *Guid; + PCH_SMM_PROTOCOL Protocols; +} PCH_SMM_QUALIFIED_PROTOCOL; + +#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \ + CR ( \ + _generic, \ + PCH_SMM_QUALIFIED_PROTOCOL, \ + Protocols, \ + PROTOCOL_SIGNATURE \ + ) + +/// +/// Create private data for the protocols that we'll publish +/// +typedef struct { + LIST_ENTRY CallbackDataBase; + EFI_HANDLE SmiHandle; + EFI_HANDLE InstallMultProtHandle; + PCH_SMM_QUALIFIED_PROTOCOL Protocols[PCH_SMM_PROTOCOL_TYPE_MAX]; +} PRIVATE_DATA; + +extern PRIVATE_DATA mPrivateData; +extern UINT16 mAcpiBaseAddr; +extern UINT16 mTcoBaseAddr; + +/** + The internal function used to create and insert a database record + + @param[in] InsertRecord Record to insert to database. + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. +**/ +EFI_STATUS +SmmCoreInsertRecord ( + IN DATABASE_RECORD *NewRecord, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Get the Sleep type + + @param[in] Record No use + @param[out] Context The context that includes SLP_TYP bits to be filled +**/ +VOID +EFIAPI +SxGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ); + +/** + Register a child SMI source dispatch function for the specified software SMI. + + This service registers a function (DispatchFunction) which will be called when the software + SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On return, + DispatchHandle contains a unique handle which may be used later to unregister the function + using UnRegister(). + + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance. + @param[in] DispatchFunction Function to register for handler when the specified software + SMI is generated. + @param[in, out] RegisterContext Pointer to the dispatch function's context. + The caller fills this context in before calling + the register function to indicate to the register + function which Software SMI input value the + dispatch function should be invoked for. + @param[out] DispatchHandle Handle generated by the dispatcher to track the + function instance. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_DEVICE_ERROR The SW driver was unable to enable the SMI source. + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI input value + is not within a valid range or is already in use. + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM) to manage this + child. + @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be assigned + for this dispatch. +**/ +EFI_STATUS +EFIAPI +PchSwSmiRegister ( + IN EFI_SMM_SW_DISPATCH2_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function for the specified software SMI. + + This service removes the handler associated with DispatchHandle so that it will no longer be + called in response to a software SMI. + + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully unregistered. + @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid. +**/ +EFI_STATUS +EFIAPI +PchSwSmiUnRegister ( + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +/** + Init required protocol for Pch Sw Dispatch protocol. +**/ +VOID +PchSwDispatchInit ( + VOID + ); + +/** + Check whether sleep type of two contexts match + + @param[in] Context1 Context 1 that includes sleep type 1 + @param[in] Context2 Context 2 that includes sleep type 2 + + @retval FALSE Sleep types match + @retval TRUE Sleep types don't match +**/ +BOOLEAN +EFIAPI +SxCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ); + +/** + Update the elapsed time from the Interval data of DATABASE_RECORD + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] HwContext The Context to be updated. +**/ +VOID +EFIAPI +PeriodicTimerGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ); + +/** + Check whether Periodic Timer of two contexts match + + @param[in] Context1 Context 1 that includes Periodic Timer 1 + @param[in] Context2 Context 2 that includes Periodic Timer 2 + + @retval FALSE Periodic Timer match + @retval TRUE Periodic Timer don't match +**/ +BOOLEAN +EFIAPI +PeriodicTimerCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ); + +/** + Gather the CommBuffer information of SmmPeriodicTimerDispatch2. + + @param[in] Record No use + @param[out] CommBuffer Point to the CommBuffer structure + @param[out] CommBufferSize Point to the Size of CommBuffer structure +**/ +VOID +EFIAPI +PeriodicTimerGetCommBuffer ( + IN DATABASE_RECORD *Record, + OUT VOID **CommBuffer, + OUT UINTN *CommBufferSize + ); + +/** + Get the power button status. + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] Context Calling context from the hardware, will be updated with the current power button status. +**/ +VOID +EFIAPI +PowerButtonGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ); + +/** + Check whether Power Button status of two contexts match + + @param[in] Context1 Context 1 that includes Power Button status 1 + @param[in] Context2 Context 2 that includes Power Button status 2 + + @retval FALSE Power Button status match + @retval TRUE Power Button status don't match +**/ +BOOLEAN +EFIAPI +PowerButtonCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ); + +/** + This function is responsible for calculating and enabling any timers that are required + to dispatch messages to children. The SrcDesc argument isn't acutally used. + + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC instance. +**/ +VOID +EFIAPI +PchSmmPeriodicTimerClearSource ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + This services returns the next SMI tick period that is supported by the chipset. + The order returned is from longest to shortest interval period. + + @param[in] This Pointer to the EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance. + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter SMI interval period that is supported by the child. + + @retval EFI_SUCCESS The service returned successfully. + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is invalid. +**/ +EFI_STATUS +PchSmmPeriodicTimerDispatchGetNextShorterInterval ( + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This, + IN OUT UINT64 **SmiTickInterval + ); + +/** + Install PCH SMM periodic timer control protocol + + @param[in] Handle handle for this driver + + @retval EFI_SUCCESS Driver initialization completed successfully +**/ +EFI_STATUS +EFIAPI +InstallPchSmmPeriodicTimerControlProtocol ( + IN EFI_HANDLE Handle + ); + +/** + Install protocols of PCH specifics SMI types, including + PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC SMI types. + + @retval the result of protocol installation +**/ +EFI_STATUS +InstallPchSmiDispatchProtocols ( + VOID + ); + +/** + The function to dispatch all callback function of PCH SMI types. + + @retval EFI_SUCCESS Function successfully completed + @retval EFI_UNSUPPORTED no +**/ +EFI_STATUS +PchSmiTypeCallbackDispatcher ( + IN DATABASE_RECORD *Record + ); + +/** + The register function used to register SMI handler of IoTrap event. + This is internal function and only used by Iotrap module. + + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[in] IoTrapIndex Index number of IOTRAP register + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. +**/ +EFI_STATUS +PchInternalIoTrapSmiRegister ( + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + IN UINTN IoTrapIndex, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +PchInternalIoTrapSmiUnRegister ( + IN EFI_HANDLE DispatchHandle + ); + +/** + Register an eSPI SMI handler based on the type + + @param[in] DispatchFunction Callback in an event of eSPI SMI + @param[in] PchSmiTypes The eSPI type published by PchSmiDispatch + @param[out] DispatchHandle The callback handle + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS Registration is successful. +**/ +EFI_STATUS +PchInternalEspiSmiRegister ( + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + IN PCH_SMI_TYPES PchSmiTypes, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister an eSPI SMI handler + + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +PchInternalEspiSmiUnRegister ( + IN EFI_HANDLE DispatchHandle + ); + +/** + The internal function used to create and insert a database record + for SMI record of Pch Smi types. + + @param[in] SrcDesc The pointer to the SMI source description + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source + @param[in] PchSmiType Specific SMI type of PCH SMI + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. +**/ +EFI_STATUS +PchSmiRecordInsert ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc, + IN PCH_SMI_CALLBACK_FUNCTIONS DispatchFunction, + IN PCH_SMI_TYPES PchSmiType, + OUT EFI_HANDLE *DispatchHandle + ); + +extern CONST PCH_SMM_SOURCE_DESC mSrcDescSerialIrq; +extern PCH_SMM_SOURCE_DESC mSrcDescLpcBiosWp; + +/** + Clear the TCO SMI status bit and block after the SMI handling is done + + @param[in] SrcDesc Pointer to the PCH SMI source description table + +**/ +VOID +EFIAPI +PchTcoSmiClearSourceAndBlock ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Clear the TCO SMI status bit after the SMI handling is done + + @param[in] SrcDesc Pointer to the PCH SMI source description table + +**/ +VOID +EFIAPI +PchTcoSmiClearSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Initialize Source descriptor structure + + @param[in] SrcDesc Pointer to the PCH SMI source description table +**/ +VOID +EFIAPI +NullInitSourceDesc ( + PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + The register function used to register SMI handler of GPI SMI event. + + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. + @param[in] DispatchFunction Function to register for handler when the specified GPI causes an SMI. + @param[in] RegisterContext Pointer to the dispatch function's context. + The caller fills this context in before calling + the register function to indicate to the register + function the GPI(s) for which the dispatch function + should be invoked. + @param[out] DispatchHandle Handle generated by the dispatcher to track the + function instance. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_ACCESS_DENIED Register is not allowed + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The GPI input value + is not within valid range. + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM) to manage this child. +**/ +EFI_STATUS +EFIAPI +PchGpiSmiRegister ( + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN EFI_SMM_GPI_REGISTER_CONTEXT *RegisterContext, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a GPI SMI source dispatch function with a parent SMM driver + + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +EFIAPI +PchGpiSmiUnRegister ( + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore.c new file mode 100644 index 0000000000..cb889b5ce3 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore.c @@ -0,0 +1,905 @@ +/** @file + This driver is responsible for the registration of child drivers + and the abstraction of the PCH SMI sources. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmm.h" +#include "PchSmmHelpers.h" +#include "PchSmiHelper.h" +#include <Library/SmiHandlerProfileLib.h> +#include <Register/GpioRegs.h> +#include <Register/PmcRegs.h> +#include <Register/TcoRegs.h> +#include <Register/RtcRegs.h> + +#define PROGRESS_CODE_S3_SUSPEND_START PcdGet32 (PcdProgressCodeS3SuspendStart) +// +// MODULE / GLOBAL DATA +// +// Module variables used by the both the main dispatcher and the source dispatchers +// Declared in PchSmm.h +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mAcpiBaseAddr; +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mTcoBaseAddr; +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mReadyToLock; +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mS3SusStart; +GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mNumOfRootPorts; + +GLOBAL_REMOVE_IF_UNREFERENCED PRIVATE_DATA mPrivateData = { + { + NULL, + NULL + }, // CallbackDataBase linked list head + NULL, // EFI handle returned when calling InstallMultipleProtocolInterfaces + NULL, // + { // protocol arrays + // + // elements within the array + // + { + PROTOCOL_SIGNATURE, + UsbType, + &gEfiSmmUsbDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister + }} + }, + { + PROTOCOL_SIGNATURE, + SxType, + &gEfiSmmSxDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister + }} + }, + { + PROTOCOL_SIGNATURE, + SwType, + &gEfiSmmSwDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchSwSmiRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchSwSmiUnRegister, + (UINTN) MAXIMUM_SWI_VALUE + }} + }, + { + PROTOCOL_SIGNATURE, + GpiType, + &gEfiSmmGpiDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchGpiSmiRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchGpiSmiUnRegister, + (UINTN) PCH_GPIO_NUM_SUPPORTED_GPIS + }} + }, + { + PROTOCOL_SIGNATURE, + PowerButtonType, + &gEfiSmmPowerButtonDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister + }} + }, + { + PROTOCOL_SIGNATURE, + PeriodicTimerType, + &gEfiSmmPeriodicTimerDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister, + (UINTN) PchSmmPeriodicTimerDispatchGetNextShorterInterval + }} + }, + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED CONTEXT_FUNCTIONS mContextFunctions[PCH_SMM_PROTOCOL_TYPE_MAX] = { + { + NULL, + NULL, + NULL + }, + { + SxGetContext, + SxCmpContext, + NULL + }, + { + NULL, + NULL, + NULL + }, + { + NULL, + NULL, + NULL + }, + { + PowerButtonGetContext, + PowerButtonCmpContext, + NULL + }, + { + PeriodicTimerGetContext, + PeriodicTimerCmpContext, + PeriodicTimerGetCommBuffer + }, +}; + +// +// PROTOTYPES +// +// Functions use only in this file +// +EFI_STATUS +EFIAPI +PchSmmCoreDispatcher ( + IN EFI_HANDLE SmmImageHandle, + IN CONST VOID *PchSmmCore, OPTIONAL + IN OUT VOID *CommunicationBuffer, + IN OUT UINTN *SourceSize + ); + +// +// FUNCTIONS +// +/** + SMM ready to lock notification event handler. + + @param Protocol Points to the protocol's unique identifier + @param Interface Points to the interface instance + @param Handle The handle on which the interface was installed + + @retval EFI_SUCCESS SmmReadyToLockCallback runs successfully + +**/ +EFI_STATUS +EFIAPI +SmmReadyToLockCallback ( + IN CONST EFI_GUID *Protocol, + IN VOID *Interface, + IN EFI_HANDLE Handle + ) +{ + mReadyToLock = TRUE; + + return EFI_SUCCESS; +} + +/** + <b>PchSmiDispatcher SMM Module Entry Point</b>\n + - <b>Introduction</b>\n + The PchSmiDispatcher module is an SMM driver which provides SMI handler registration + services for PCH generated SMIs. + + - <b>Details</b>\n + This module provides SMI handler registration servicies for PCH SMIs. + NOTE: All the register/unregister functions will be locked after SMM ready to boot signal event. + Please make sure no handler is installed after that. + + - @pre + - EFI_SMM_BASE2_PROTOCOL + - Documented in the System Management Mode Core Interface Specification + - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL + - Documented in the UEFI 2.0 Specification and above + - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL + - This is to ensure that PCI MMIO and IO resource has been prepared and available for this driver to allocate. + - EFI_SMM_CPU_PROTOCOL + + - @result + The PchSmiDispatcher driver produces: + - EFI_SMM_USB_DISPATCH2_PROTOCOL + - EFI_SMM_SX_DISPATCH2_PROTOCOL + - EFI_SMM_SW_DISPATCH2_PROTOCOL + - EFI_SMM_GPI_DISPATCH2_PROTOCOL + - EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL + - EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL + - EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL + - @link _PCH_SMM_IO_TRAP_CONTROL_PROTOCOL PCH_SMM_IO_TRAP_CONTROL_PROTOCOL @endlink + - @link _PCH_PCIE_SMI_DISPATCH_PROTOCOL PCH_PCIE_SMI_DISPATCH_PROTOCOL @endlink + - @link _PCH_TCO_SMI_DISPATCH_PROTOCOL PCH_TCO_SMI_DISPATCH_PROTOCOL @endlink + - @link _PCH_ACPI_SMI_DISPATCH_PROTOCOL PCH_ACPI_SMI_DISPATCH_PROTOCOL @endlink + - @link _PCH_SMI_DISPATCH_PROTOCOL PCH_SMI_DISPATCH_PROTOCOL @endlink + + @param[in] ImageHandle Pointer to the loaded image protocol for this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_SUCCESS PchSmmDispatcher Initialization completed. +**/ +EFI_STATUS +EFIAPI +InitializePchSmmDispatcher ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + VOID *SmmReadyToLockRegistration; + + mS3SusStart = FALSE; + + PchSmiDispatchUpdateDescriptors (); + + // + // Access ACPI Base Addresses Register + // + mAcpiBaseAddr = PmcGetAcpiBase (); + ASSERT (mAcpiBaseAddr != 0); + + // + // Access TCO Base Addresses Register + // + PchTcoBaseGet (&mTcoBaseAddr); + ASSERT (mTcoBaseAddr != 0); + + mNumOfRootPorts = GetPchMaxPciePortNum (); + + // + // Register a callback function to handle subsequent SMIs. This callback + // will be called by SmmCoreDispatcher. + // + Status = gSmst->SmiHandlerRegister (PchSmmCoreDispatcher, NULL, &mPrivateData.SmiHandle); + ASSERT_EFI_ERROR (Status); + // + // Initialize Callback DataBase + // + InitializeListHead (&mPrivateData.CallbackDataBase); + + // + // Enable SMIs on the PCH now that we have a callback + // + PchSmmInitHardware (); + + // + // Install and initialize all the needed protocols + // + PchSwDispatchInit (); + PchSmmPublishDispatchProtocols (); + InstallPchSmiDispatchProtocols (); + InstallPchSmmPeriodicTimerControlProtocol (mPrivateData.InstallMultProtHandle); + + // + // Register EFI_SMM_READY_TO_LOCK_PROTOCOL_GUID notify function. + // + Status = gSmst->SmmRegisterProtocolNotify ( + &gEfiSmmReadyToLockProtocolGuid, + SmmReadyToLockCallback, + &SmmReadyToLockRegistration + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +/** + The internal function used to create and insert a database record + + @param[in] InsertRecord Record to insert to database. + @param[out] DispatchHandle Handle of dispatch function to register. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source description + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database record + @retval EFI_SUCCESS The database record is created successfully. +**/ +EFI_STATUS +SmmCoreInsertRecord ( + IN DATABASE_RECORD *NewRecord, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + if ((NewRecord == NULL) || + (NewRecord->Signature != DATABASE_RECORD_SIGNATURE)) + { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Status = gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof (DATABASE_RECORD), (VOID **) &Record); + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + CopyMem (Record, NewRecord, sizeof (DATABASE_RECORD)); + + // + // After ensuring the source of event is not null, we will insert the record into the database + // + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + + // + // Child's handle will be the address linked list link in the record + // + *DispatchHandle = (EFI_HANDLE) (&Record->Link); + + return EFI_SUCCESS; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchPiSmmCoreUnRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE *DispatchHandle + ) +{ + DATABASE_RECORD *RecordToDelete; + EFI_STATUS Status; + PCH_SMM_QUALIFIED_PROTOCOL *Qualified; + + Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This); + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle); + Status = PchSmmCoreUnRegister (NULL, DispatchHandle); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileUnregisterHandler ( + Qualified->Guid, + RecordToDelete->Callback, + &RecordToDelete->ChildContext, + RecordToDelete->ContextSize + ); + } + return Status; +} + +/** + Register a child SMI dispatch function with a parent SMM driver. + + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL instance. + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source. + @param[in] DispatchContext Pointer to the dispatch function's context. + @param[out] DispatchHandle Handle of dispatch function, for when interfacing + with the parent SMM driver, will be the address of linked + list link in the call back record. + + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create database record + @retval EFI_INVALID_PARAMETER The input parameter is invalid + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. +**/ +EFI_STATUS +EFIAPI +PchPiSmmCoreRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN PCH_SMM_CONTEXT *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD Record; + PCH_SMM_QUALIFIED_PROTOCOL *Qualified; + PCH_SMM_SOURCE_DESC NullSourceDesc; + + // + // Initialize NullSourceDesc + // + NullInitSourceDesc (&NullSourceDesc); + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + ZeroMem (&Record, sizeof (DATABASE_RECORD)); + + // + // Gather information about the registration request + // + Record.Callback = DispatchFunction; + + Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This); + + Record.ProtocolType = Qualified->Type; + + Record.ContextFunctions = mContextFunctions[Qualified->Type]; + // + // Perform linked list housekeeping + // + Record.Signature = DATABASE_RECORD_SIGNATURE; + + switch (Qualified->Type) { + // + // By the end of this switch statement, we'll know the + // source description the child is registering for + // + case UsbType: + Record.ContextSize = sizeof (EFI_SMM_USB_REGISTER_CONTEXT); + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize); + // + // Check the validity of Context Type + // + if ((Record.ChildContext.Usb.Type < UsbLegacy) || (Record.ChildContext.Usb.Type > UsbWake)) { + return EFI_INVALID_PARAMETER; + } + + PchSmmUsbUpdateDescriptors (); + MapUsbToSrcDesc (DispatchContext, &Record.SrcDesc); + Record.ClearSource = NULL; + // + // use default clear source function + // + break; + + case SxType: + Record.ContextSize = sizeof (EFI_SMM_SX_REGISTER_CONTEXT); + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize); + // + // Check the validity of Context Type and Phase + // + if ((Record.ChildContext.Sx.Type < SxS0) || + (Record.ChildContext.Sx.Type >= EfiMaximumSleepType) || + (Record.ChildContext.Sx.Phase < SxEntry) || + (Record.ChildContext.Sx.Phase >= EfiMaximumPhase) + ) { + return EFI_INVALID_PARAMETER; + } + + CopyMem (&Record.SrcDesc, &mSxSourceDesc, sizeof (PCH_SMM_SOURCE_DESC)); + Record.ClearSource = NULL; + // + // use default clear source function + // + break; + + case PowerButtonType: + Record.ContextSize = sizeof (EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT); + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize); + // + // Check the validity of Context Phase + // + if ((Record.ChildContext.PowerButton.Phase < EfiPowerButtonEntry) || + (Record.ChildContext.PowerButton.Phase > EfiPowerButtonExit)) + { + return EFI_INVALID_PARAMETER; + } + + CopyMem (&Record.SrcDesc, &mPowerButtonSourceDesc, sizeof (PCH_SMM_SOURCE_DESC)); + Record.ClearSource = NULL; + // + // use default clear source function + // + break; + + case PeriodicTimerType: + Record.ContextSize = sizeof (EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT); + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize); + // + // Check the validity of timer value + // + if (DispatchContext->PeriodicTimer.SmiTickInterval <= 0) { + return EFI_INVALID_PARAMETER; + } + + MapPeriodicTimerToSrcDesc (DispatchContext, &Record.SrcDesc); + Record.MiscData.TimerSmiEnabled = TRUE; + Record.ClearSource = PchSmmPeriodicTimerClearSource; + break; + + default: + return EFI_INVALID_PARAMETER; + break; + } + + if (CompareSources (&Record.SrcDesc, &NullSourceDesc)) { + return EFI_INVALID_PARAMETER; + } + + // + // After ensuring the source of event is not null, we will insert the record into the database + // Child's handle will be the address linked list link in the record + // + Status = SmmCoreInsertRecord ( + &Record, + DispatchHandle + ); + ASSERT_EFI_ERROR (Status); + + if (Record.ClearSource == NULL) { + // + // Clear the SMI associated w/ the source using the default function + // + PchSmmClearSource (&Record.SrcDesc); + } else { + // + // This source requires special handling to clear + // + Record.ClearSource (&Record.SrcDesc); + } + + PchSmmEnableSource (&Record.SrcDesc); + SmiHandlerProfileRegisterHandler ( + Qualified->Guid, + DispatchFunction, + (UINTN)RETURN_ADDRESS (0), + DispatchContext, + Record.ContextSize + ); + + return EFI_SUCCESS; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver. + + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +EFIAPI +PchSmmCoreUnRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + BOOLEAN NeedClearEnable; + UINTN DescIndex; + DATABASE_RECORD *RecordToDelete; + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + + if (DispatchHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle); + + // + // Take the entry out of the linked list + // + if (RecordToDelete->Link.ForwardLink == (LIST_ENTRY *) EFI_BAD_POINTER) { + return EFI_INVALID_PARAMETER; + } + + RemoveEntryList (&RecordToDelete->Link); + + // + // Loop through all the souces in record linked list to see if any source enable is equal. + // If any source enable is equal, we do not want to disable it. + // + for (DescIndex = 0; DescIndex < NUM_EN_BITS; ++DescIndex) { + if (IS_BIT_DESC_NULL (RecordToDelete->SrcDesc.En[DescIndex])) { + continue; + } + NeedClearEnable = TRUE; + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + if (IsBitEqualToAnySourceEn (&RecordToDelete->SrcDesc.En[DescIndex], &RecordInDb->SrcDesc)) { + NeedClearEnable = FALSE; + break; + } + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + } + if (NeedClearEnable == FALSE) { + continue; + } + WriteBitDesc (&RecordToDelete->SrcDesc.En[DescIndex], 0, FALSE); + } + Status = gSmst->SmmFreePool (RecordToDelete); + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + return Status; + } + return EFI_SUCCESS; +} + +/** + This function clears the pending SMI status before set EOS. + NOTE: This only clears the pending SMI with known reason. + Please do not clear unknown pending SMI status since that will hide potential issues. + + @param[in] SmiStsValue SMI status + @param[in] SciEn Sci Enable status +**/ +STATIC +VOID +ClearPendingSmiStatus ( + UINT32 SmiStsValue, + BOOLEAN SciEn + ) +{ + // + // Clear NewCentury status if it's not handled. + // + if (SmiStsValue & B_ACPI_IO_SMI_STS_TCO) { + if (IoRead16 (mTcoBaseAddr + R_TCO_IO_TCO1_STS) & B_TCO_IO_TCO1_STS_NEWCENTURY) { + PchTcoSmiClearSourceAndBlock (&mSrcDescNewCentury); + } + } + // Clear PWRBTNOR_STS if it's not handled. + // + if (IoRead16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS) & B_ACPI_IO_PM1_STS_PRBTNOR) { + IoWrite16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS, B_ACPI_IO_PM1_STS_PRBTNOR); + } + // + // Clear WADT_STS if this is triggered by WADT timer. + // + if (!SciEn) { + if ((IoRead32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_EN_127_96) & B_ACPI_IO_GPE0_EN_127_96_WADT) && + (IoRead32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96) & B_ACPI_IO_GPE0_STS_127_96_WADT)) { + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96, B_ACPI_IO_GPE0_STS_127_96_WADT); + } + } + // + // Clear GPIO_UNLOCK_SMI_STS in case it is set as GPIO Unlock SMI is not supported + // + if (SmiStsValue & B_ACPI_IO_SMI_STS_GPIO_UNLOCK) { + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_SMI_STS, B_ACPI_IO_SMI_STS_GPIO_UNLOCK); + } +} + +/** + The callback function to handle subsequent SMIs. This callback will be called by SmmCoreDispatcher. + + @param[in] SmmImageHandle Not used + @param[in] PchSmmCore Not used + @param[in, out] CommunicationBuffer Not used + @param[in, out] SourceSize Not used + + @retval EFI_SUCCESS Function successfully completed +**/ +EFI_STATUS +EFIAPI +PchSmmCoreDispatcher ( + IN EFI_HANDLE SmmImageHandle, + IN CONST VOID *PchSmmCore, + IN OUT VOID *CommunicationBuffer, + IN OUT UINTN *SourceSize + ) +{ + // + // Used to prevent infinite loops + // + UINTN EscapeCount; + + BOOLEAN ContextsMatch; + BOOLEAN EosSet; + BOOLEAN SxChildWasDispatched; + + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + DATABASE_RECORD *RecordToExhaust; + LIST_ENTRY *LinkToExhaust; + + PCH_SMM_CONTEXT Context; + VOID *CommBuffer; + UINTN CommBufferSize; + + EFI_STATUS Status; + BOOLEAN SciEn; + UINT32 SmiEnValue; + UINT32 SmiStsValue; + UINT8 Port74Save; + UINT8 Port76Save; + + PCH_SMM_SOURCE_DESC ActiveSource; + + // + // Initialize ActiveSource + // + NullInitSourceDesc (&ActiveSource); + + EscapeCount = 3; + ContextsMatch = FALSE; + EosSet = FALSE; + SxChildWasDispatched = FALSE; + Status = EFI_SUCCESS; + + // + // Save IO index registers + // @note: Save/Restore port 70h directly might break NMI_EN# setting, + // then save/restore 74h/76h instead. + // @note: CF8 is not saved. Prefer method is to use MMIO instead of CF8 + // + Port76Save = IoRead8 (R_RTC_IO_EXT_INDEX_ALT); + Port74Save = IoRead8 (R_RTC_IO_INDEX_ALT); + + if (!IsListEmpty (&mPrivateData.CallbackDataBase)) { + // + // We have children registered w/ us -- continue + // + while ((!EosSet) && (EscapeCount > 0)) { + EscapeCount--; + + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + + // + // Cache SciEn, SmiEnValue and SmiStsValue to determine if source is active + // + SciEn = PchSmmGetSciEn (); + SmiEnValue = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); + SmiStsValue = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS)); + + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + + // + // look for the first active source + // + if (!SourceIsActive (&RecordInDb->SrcDesc, SciEn, SmiEnValue, SmiStsValue)) { + // + // Didn't find the source yet, keep looking + // + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + + // + // if it's the last one, try to clear EOS + // + if (IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + // + // Clear pending SMI status before EOS + // + ClearPendingSmiStatus (SmiStsValue, SciEn); + EosSet = PchSmmSetAndCheckEos (); + } + } else { + // + // We found a source. If this is a sleep type, we have to go to + // appropriate sleep state anyway.No matter there is sleep child or not + // + if (RecordInDb->ProtocolType == SxType) { + SxChildWasDispatched = TRUE; + } + // + // "cache" the source description and don't query I/O anymore + // + CopyMem ((VOID *) &ActiveSource, (VOID *) &(RecordInDb->SrcDesc), sizeof (PCH_SMM_SOURCE_DESC)); + LinkToExhaust = LinkInDb; + + // + // exhaust the rest of the queue looking for the same source + // + while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) { + RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust); + // + // RecordToExhaust->Link might be removed (unregistered) by Callback function, and then the + // system will hang in ASSERT() while calling GetNextNode(). + // To prevent the issue, we need to get next record in DB here (before Callback function). + // + LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, &RecordToExhaust->Link); + + if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) { + // + // These source descriptions are equal, so this callback should be + // dispatched. + // + if (RecordToExhaust->ContextFunctions.GetContext != NULL) { + // + // This child requires that we get a calling context from + // hardware and compare that context to the one supplied + // by the child. + // + ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL); + + // + // Make sure contexts match before dispatching event to child + // + RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context); + ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext); + + } else { + // + // This child doesn't require any more calling context beyond what + // it supplied in registration. Simply pass back what it gave us. + // + Context = RecordToExhaust->ChildContext; + ContextsMatch = TRUE; + } + + if (ContextsMatch) { + if (RecordToExhaust->ProtocolType == PchSmiDispatchType) { + // + // For PCH SMI dispatch protocols + // + PchSmiTypeCallbackDispatcher (RecordToExhaust); + } else { + if ((RecordToExhaust->ProtocolType == SxType) && (Context.Sx.Type == SxS3) && (Context.Sx.Phase == SxEntry) && !mS3SusStart) { + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PROGRESS_CODE_S3_SUSPEND_START); + mS3SusStart = TRUE; + } + // + // For EFI standard SMI dispatch protocols + // + if (RecordToExhaust->Callback != NULL) { + if (RecordToExhaust->ContextFunctions.GetCommBuffer != NULL) { + // + // This callback function needs CommBuffer and CommBufferSize. + // Get those from child and then pass to callback function. + // + RecordToExhaust->ContextFunctions.GetCommBuffer (RecordToExhaust, &CommBuffer, &CommBufferSize); + } else { + // + // Child doesn't support the CommBuffer and CommBufferSize. + // Just pass NULL value to callback function. + // + CommBuffer = NULL; + CommBufferSize = 0; + } + + PERF_START_EX (NULL, "SmmFunction", NULL, AsmReadTsc (), RecordToExhaust->ProtocolType); + RecordToExhaust->Callback ((EFI_HANDLE) & RecordToExhaust->Link, &Context, CommBuffer, &CommBufferSize); + PERF_END_EX (NULL, "SmmFunction", NULL, AsmReadTsc (), RecordToExhaust->ProtocolType); + if (RecordToExhaust->ProtocolType == SxType) { + SxChildWasDispatched = TRUE; + } + } else { + ASSERT (FALSE); + } + } + } + } + } + + if (RecordInDb->ClearSource == NULL) { + // + // Clear the SMI associated w/ the source using the default function + // + PchSmmClearSource (&ActiveSource); + } else { + // + // This source requires special handling to clear + // + RecordInDb->ClearSource (&ActiveSource); + } + // + // Clear pending SMI status before EOS + // + ClearPendingSmiStatus (SmiStsValue, SciEn); + // + // Also, try to clear EOS + // + EosSet = PchSmmSetAndCheckEos (); + // + // Queue is empty, reset the search + // + break; + } + } + } + } + // + // Restore IO index registers + // @note: Save/Restore port 70h directly might break NMI_EN# setting, + // then save/restore 74h/76h instead. + // + IoWrite8 (R_RTC_IO_EXT_INDEX_ALT, Port76Save); + IoWrite8 (R_RTC_IO_INDEX_ALT, Port74Save); + + return Status; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c new file mode 100644 index 0000000000..4c59c07bac --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c @@ -0,0 +1,255 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Gpi dispatch protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmm.h" +#include "PchSmmHelpers.h" +#include <Library/SmiHandlerProfileLib.h> +#include <Register/GpioRegs.h> +#include <Register/PmcRegs.h> + +// +// Structure for GPI SMI is a template which needs to have +// GPI Smi bit offset and Smi Status & Enable registers updated (accordingly +// to choosen group and pad number) after adding it to SMM Callback database +// + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mPchGpiSourceDescTemplate = { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + GPIO_ADDR_TYPE, {0x0} + }, + S_GPIO_PCR_GP_SMI_STS, 0x0, + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_GPIO_SMI + } +}; + +/** + The register function used to register SMI handler of GPI SMI event. + + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. + @param[in] DispatchFunction Function to register for handler when the specified GPI causes an SMI. + @param[in] RegisterContext Pointer to the dispatch function's context. + The caller fills this context in before calling + the register function to indicate to the register + function the GPI(s) for which the dispatch function + should be invoked. + @param[out] DispatchHandle Handle generated by the dispatcher to track the + function instance. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_ACCESS_DENIED Register is not allowed + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The GPI input value + is not within valid range. + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM) to manage this child. +**/ +EFI_STATUS +EFIAPI +PchGpiSmiRegister ( + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN EFI_SMM_GPI_REGISTER_CONTEXT *RegisterContext, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD Record; + GPIO_PAD GpioPad; + UINT8 GpiSmiBitOffset; + UINT32 GpiHostSwOwnRegAddress; + UINT32 GpiSmiStsRegAddress; + UINT32 Data32And; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status = GpioGetPadAndSmiRegs ( + (UINT32) RegisterContext->GpiNum, + &GpioPad, + &GpiSmiBitOffset, + &GpiHostSwOwnRegAddress, + &GpiSmiStsRegAddress + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem (&Record, sizeof (DATABASE_RECORD)); + + // + // Gather information about the registration request + // + Record.Callback = DispatchFunction; + Record.ChildContext.Gpi = *RegisterContext; + Record.ProtocolType = GpiType; + Record.Signature = DATABASE_RECORD_SIGNATURE; + + CopyMem (&Record.SrcDesc, &mPchGpiSourceDescTemplate, sizeof (PCH_SMM_SOURCE_DESC) ); + + Record.SrcDesc.Sts[0].Reg.Data.raw = GpiSmiStsRegAddress; // GPI SMI Status register + Record.SrcDesc.Sts[0].Bit = GpiSmiBitOffset; // Bit position for selected pad + + // + // Insert GpiSmi handler to PchSmmCore database + // + *DispatchHandle = NULL; + + Status = SmmCoreInsertRecord ( + &Record, + DispatchHandle + ); + ASSERT_EFI_ERROR (Status); + + SmiHandlerProfileRegisterHandler ( + &gEfiSmmGpiDispatch2ProtocolGuid, + (EFI_SMM_HANDLER_ENTRY_POINT2) DispatchFunction, + (UINTN)RETURN_ADDRESS (0), + RegisterContext, + sizeof(*RegisterContext) + ); + + // + // Enable GPI SMI + // HOSTSW_OWN with respect to generating GPI SMI has negative logic: + // - 0 (ACPI mode) - GPIO pad will be capable of generating SMI/NMI/SCI + // - 1 (GPIO mode) - GPIO pad will not generate SMI/NMI/SCI + // + Data32And = (UINT32)~(1u << GpiSmiBitOffset); + MmioAnd32 (GpiHostSwOwnRegAddress, Data32And); + + return EFI_SUCCESS; +} + +/** + Unregister a GPI SMI source dispatch function with a parent SMM driver + + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +EFIAPI +PchGpiSmiUnRegister ( + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *RecordToDelete; + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + GPIO_PAD GpioPad; + UINT8 GpiSmiBitOffset; + UINT32 GpiHostSwOwnRegAddress; + UINT32 GpiSmiStsRegAddress; + UINT32 Data32Or; + UINT32 Data32And; + BOOLEAN DisableGpiSmiSource; + + + if (DispatchHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle); + if ((RecordToDelete->Signature != DATABASE_RECORD_SIGNATURE) || + (RecordToDelete->ProtocolType != GpiType)) { + return EFI_INVALID_PARAMETER; + } + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + DisableGpiSmiSource = TRUE; + // + // Loop through all sources in record linked list to see if any other GPI SMI + // is installed on the same pin. If no then disable GPI SMI capability on this pad + // + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + // + // If this is the record to delete skip it + // + if (RecordInDb == RecordToDelete) { + continue; + } + // + // Check if record is GPI SMI type + // + if (RecordInDb->ProtocolType == GpiType) { + // + // Check if same GPIO pad is the source of this SMI + // + if (RecordInDb->ChildContext.Gpi.GpiNum == RecordToDelete->ChildContext.Gpi.GpiNum) { + DisableGpiSmiSource = FALSE; + break; + } + } + } + + if (DisableGpiSmiSource) { + GpioGetPadAndSmiRegs ( + (UINT32) RecordToDelete->ChildContext.Gpi.GpiNum, + &GpioPad, + &GpiSmiBitOffset, + &GpiHostSwOwnRegAddress, + &GpiSmiStsRegAddress + ); + + Data32Or = 1u << GpiSmiBitOffset; + Data32And = 0xFFFFFFFF; + MmioOr32 (GpiHostSwOwnRegAddress, Data32Or); + } + + + RemoveEntryList (&RecordToDelete->Link); + ZeroMem (RecordToDelete, sizeof (DATABASE_RECORD)); + Status = gSmst->SmmFreePool (RecordToDelete); + + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + return Status; + } + SmiHandlerProfileUnregisterHandler ( + &gEfiSmmGpiDispatch2ProtocolGuid, + RecordToDelete->Callback, + &RecordToDelete->ChildContext, + RecordToDelete->ContextSize + ); + return EFI_SUCCESS; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c new file mode 100644 index 0000000000..724a383855 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c @@ -0,0 +1,332 @@ +/** @file + Helper functions for PCH SMM dispatcher. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#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. + /// + } + } + } +} + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h new file mode 100644 index 0000000000..93ab8564ff --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h @@ -0,0 +1,163 @@ +/** @file + Helper functions for PCH SMM + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef PCH_SMM_HELPERS_H +#define PCH_SMM_HELPERS_H + +#include "PchSmm.h" +#include "PchxSmmHelpers.h" +// +// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SUPPORT / HELPER FUNCTIONS (PCH version-independent) +// + +/** + Publish SMI Dispatch protocols. + + +**/ +VOID +PchSmmPublishDispatchProtocols ( + VOID + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + Performs update of SmmUsb descriptors with values that have to be evaluated during runtime. +**/ +VOID +PchSmmUsbUpdateDescriptors ( + VOID + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c new file mode 100644 index 0000000000..3078d0c696 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c @@ -0,0 +1,670 @@ +/** @file + File to contain all the hardware specific stuff for the Periodical Timer dispatch protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include <Protocol/PchSmmPeriodicTimerControl.h> +#include <Library/PmcPrivateLib.h> + +// +// There is only one instance for PeriodicTimerCommBuffer. +// It's safe in SMM since there is no re-entry for the function. +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_PERIODIC_TIMER_CONTEXT mPchPeriodicTimerCommBuffer; + +typedef enum { + PERIODIC_TIMER= 0, + SWSMI_TIMER, + NUM_TIMERS +} SUPPORTED_TIMER; + +typedef struct _TIMER_INTERVAL { + UINT64 Interval; + UINT8 AssociatedTimer; +} TIMER_INTERVAL; + +#define NUM_INTERVALS 8 + +// +// Time constants, in 100 nano-second units +// +#define TIME_64s 640000000 ///< 64 s +#define TIME_32s 320000000 ///< 32 s +#define TIME_16s 160000000 ///< 16 s +#define TIME_8s 80000000 ///< 8 s +#define TIME_64ms 640000 ///< 64 ms +#define TIME_32ms 320000 ///< 32 ms +#define TIME_16ms 160000 ///< 16 ms +#define TIME_1_5ms 15000 ///< 1.5 ms + +typedef enum { + INDEX_TIME_64s = 0, + INDEX_TIME_32s, + INDEX_TIME_16s, + INDEX_TIME_8s, + INDEX_TIME_64ms, + INDEX_TIME_32ms, + INDEX_TIME_16ms, + INDEX_TIME_1_5ms, + INDEX_TIME_MAX +} TIMER_INTERVAL_INDEX; + +static TIMER_INTERVAL mSmmPeriodicTimerIntervals[NUM_INTERVALS] = { + { + TIME_64s, + PERIODIC_TIMER + }, + { + TIME_32s, + PERIODIC_TIMER + }, + { + TIME_16s, + PERIODIC_TIMER + }, + { + TIME_8s, + PERIODIC_TIMER + }, + { + TIME_64ms, + SWSMI_TIMER + }, + { + TIME_32ms, + SWSMI_TIMER + }, + { + TIME_16ms, + SWSMI_TIMER + }, + { + TIME_1_5ms, + SWSMI_TIMER + }, +}; + +typedef struct _TIMER_INFO { + UINTN NumChildren; ///< number of children using this timer + UINT64 MinReqInterval; ///< minimum interval required by children + UINTN CurrentSetting; ///< interval this timer is set at right now (index into interval table) +} TIMER_INFO; + +GLOBAL_REMOVE_IF_UNREFERENCED TIMER_INFO mTimers[NUM_TIMERS]; + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mTimerSourceDesc[NUM_TIMERS] = { + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_PERIODIC + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_PERIODIC + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_PERIODIC + } + }, + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_SWSMI_TMR + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SWSMI_TMR + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SWSMI_TMR + } + } +}; + +/** + Program Smm Periodic Timer + + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC instance. +**/ +VOID +PchSmmPeriodicTimerProgramTimers ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Convert the dispatch context to the timer interval, this function will assert if then either: + (1) The context contains an invalid interval + (2) The timer interval table is corrupt + + @param[in] DispatchContext The pointer to the Dispatch Context + + @retval TIMER_INTERVAL The timer interval of input dispatch context +**/ +TIMER_INTERVAL * +ContextToTimerInterval ( + IN PCH_SMM_CONTEXT *DispatchContext + ) +{ + UINTN loopvar; + + /// + /// Determine which timer this child is using + /// + for (loopvar = 0; loopvar < NUM_INTERVALS; loopvar++) { + if (((DispatchContext->PeriodicTimer.SmiTickInterval == 0) && + (DispatchContext->PeriodicTimer.Period >= mSmmPeriodicTimerIntervals[loopvar].Interval)) || + (DispatchContext->PeriodicTimer.SmiTickInterval == mSmmPeriodicTimerIntervals[loopvar].Interval)) { + return &mSmmPeriodicTimerIntervals[loopvar]; + } + } + /// + /// If this assertion fires, then either: + /// (1) the context contains an invalid interval + /// (2) the timer interval table is corrupt + /// + ASSERT (FALSE); + + return NULL; +} + +/** + Figure out which timer the child is requesting and + send back the source description + + @param[in] DispatchContext The pointer to the Dispatch Context instances + @param[out] SrcDesc The pointer to the source description + +**/ +VOID +MapPeriodicTimerToSrcDesc ( + IN PCH_SMM_CONTEXT *DispatchContext, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + TIMER_INTERVAL *TimerInterval; + + /// + /// Figure out which timer the child is requesting and + /// send back the source description + /// + TimerInterval = ContextToTimerInterval (DispatchContext); + if (TimerInterval == NULL) { + return; + } + + CopyMem ( + (VOID *) SrcDesc, + (VOID *) (&mTimerSourceDesc[TimerInterval->AssociatedTimer]), + sizeof (PCH_SMM_SOURCE_DESC) + ); + + /// + /// Program the value of the interval into hardware + /// + PchSmmPeriodicTimerProgramTimers (SrcDesc); +} + +/** + Update the elapsed time from the Interval data of DATABASE_RECORD + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] HwContext The Context to be updated. + +**/ +VOID +EFIAPI +PeriodicTimerGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *HwContext + ) +{ + TIMER_INTERVAL *TimerInterval; + + ASSERT (Record->ProtocolType == PeriodicTimerType); + + TimerInterval = ContextToTimerInterval (&Record->ChildContext); + if (TimerInterval == NULL) { + return; + } + /// + /// Ignore the hardware context. It's not required for this protocol. + /// Instead, just increment the child's context. + /// Update the elapsed time w/ the data from our tables + /// + Record->MiscData.ElapsedTime += mTimers[TimerInterval->AssociatedTimer].MinReqInterval; + *HwContext = Record->ChildContext; +} + +/** + Check whether Periodic Timer of two contexts match + + @param[in] Context1 Context 1 that includes Periodic Timer 1 + @param[in] Context2 Context 2 that includes Periodic Timer 2 + + @retval FALSE Periodic Timer match + @retval TRUE Periodic Timer don't match +**/ +BOOLEAN +EFIAPI +PeriodicTimerCmpContext ( + IN PCH_SMM_CONTEXT *HwContext, + IN PCH_SMM_CONTEXT *ChildContext + ) +{ + DATABASE_RECORD *Record; + Record = DATABASE_RECORD_FROM_CHILDCONTEXT (ChildContext); + + if (!Record->MiscData.TimerSmiEnabled) { + return FALSE; + } + if (Record->MiscData.ElapsedTime >= ChildContext->PeriodicTimer.Period) { + /// + /// For EDKII, the ElapsedTime is reset when PeriodicTimerGetCommBuffer + /// + return TRUE; + } else { + return FALSE; + } +} + +/** + Gather the CommBuffer information of SmmPeriodicTimerDispatch2. + + @param[in] Record No use + @param[out] CommBuffer Point to the CommBuffer structure + @param[out] CommBufferSize Point to the Size of CommBuffer structure + +**/ +VOID +EFIAPI +PeriodicTimerGetCommBuffer ( + IN DATABASE_RECORD *Record, + OUT VOID **CommBuffer, + OUT UINTN *CommBufferSize + ) +{ + ASSERT (Record->ProtocolType == PeriodicTimerType); + + mPchPeriodicTimerCommBuffer.ElapsedTime = Record->MiscData.ElapsedTime; + + /// + /// For EDKII, the ElapsedTime is reset here + /// + Record->MiscData.ElapsedTime = 0; + + /// + /// Return the CommBuffer + /// + *CommBuffer = (VOID *) &mPchPeriodicTimerCommBuffer; + *CommBufferSize = sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT); +} + +/** + Program Smm Periodic Timer + + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC instance. +**/ +VOID +PchSmmPeriodicTimerProgramTimers ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + SUPPORTED_TIMER Timer; + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + TIMER_INTERVAL *TimerInterval; + + /// + /// Find the minimum required interval for each timer + /// + for (Timer = 0; Timer < NUM_TIMERS; Timer++) { + mTimers[Timer].MinReqInterval = ~ (UINT64) 0x0; + mTimers[Timer].NumChildren = 0; + } + + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + if (RecordInDb->ProtocolType == PeriodicTimerType) { + if (RecordInDb->MiscData.TimerSmiEnabled) { + /// + /// This child is registerd with the PeriodicTimer protocol + /// + TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext); + if (TimerInterval == NULL) { + return; + } + + Timer = TimerInterval->AssociatedTimer; + if (Timer < 0 || Timer >= NUM_TIMERS) { + ASSERT (FALSE); + CpuDeadLoop (); + return; + } + if (mTimers[Timer].MinReqInterval > RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval) { + mTimers[Timer].MinReqInterval = RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval; + } + mTimers[Timer].NumChildren++; + } + } + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + } + /// + /// Program the hardware + /// + if (mTimers[PERIODIC_TIMER].NumChildren > 0) { + switch (mTimers[PERIODIC_TIMER].MinReqInterval) { + case TIME_64s: + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate64s); + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64s; + break; + + case TIME_32s: + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate32s); + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s; + break; + + case TIME_16s: + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate16s); + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s; + break; + + case TIME_8s: + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate8s); + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s; + break; + + default: + ASSERT (FALSE); + break; + } + + /// + /// Restart the timer here, just need to clear the SMI + /// + if (SrcDesc->Sts[0].Bit == N_ACPI_IO_SMI_STS_PERIODIC) { + PchSmmClearSource (&mTimerSourceDesc[PERIODIC_TIMER]); + } + } else { + PchSmmDisableSource (&mTimerSourceDesc[PERIODIC_TIMER]); + } + + if (mTimers[SWSMI_TIMER].NumChildren > 0) { + switch (mTimers[SWSMI_TIMER].MinReqInterval) { + case TIME_64ms: + PmcSetSwSmiRate (PmcSwSmiRate64ms); + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_64ms; + break; + + case TIME_32ms: + PmcSetSwSmiRate (PmcSwSmiRate32ms); + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_32ms; + break; + + case TIME_16ms: + PmcSetSwSmiRate (PmcSwSmiRate16ms); + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_16ms; + break; + + case TIME_1_5ms: + PmcSetSwSmiRate (PmcSwSmiRate1p5ms); + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_1_5ms; + break; + + default: + ASSERT (FALSE); + break; + } + + /// + /// Restart the timer here, need to disable, clear, then enable to restart this timer + /// + if (SrcDesc->Sts[0].Bit == N_ACPI_IO_SMI_STS_SWSMI_TMR) { + PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]); + PchSmmClearSource (&mTimerSourceDesc[SWSMI_TIMER]); + PchSmmEnableSource (&mTimerSourceDesc[SWSMI_TIMER]); + } + } else { + PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]); + } +} + +/** + This services returns the next SMI tick period that is supported by the chipset. + The order returned is from longest to shortest interval period. + + @param[in] This Pointer to the EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance. + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter SMI interval period that is supported by the child. + + @retval EFI_SUCCESS The service returned successfully. + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is invalid. +**/ +EFI_STATUS +PchSmmPeriodicTimerDispatchGetNextShorterInterval ( + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This, + IN OUT UINT64 **SmiTickInterval + ) +{ + TIMER_INTERVAL *IntervalPointer; + + ASSERT (SmiTickInterval != NULL); + if (SmiTickInterval == NULL) { + return EFI_INVALID_PARAMETER; + } + + IntervalPointer = (TIMER_INTERVAL *) *SmiTickInterval; + + if (IntervalPointer == NULL) { + /// + /// The first time child requesting an interval + /// + IntervalPointer = &mSmmPeriodicTimerIntervals[0]; + } else if (IntervalPointer == &mSmmPeriodicTimerIntervals[NUM_INTERVALS - 1]) { + /// + /// At end of the list + /// + IntervalPointer = NULL; + } else { + if ((IntervalPointer >= &mSmmPeriodicTimerIntervals[0]) && + (IntervalPointer < &mSmmPeriodicTimerIntervals[NUM_INTERVALS - 1]) + ) { + /// + /// Get the next interval in the list + /// + IntervalPointer++; + } else { + /// + /// Input is out of range + /// + return EFI_INVALID_PARAMETER; + } + } + + if (IntervalPointer != NULL) { + *SmiTickInterval = &IntervalPointer->Interval; + } else { + *SmiTickInterval = NULL; + } + + return EFI_SUCCESS; +} + +/** + This function is responsible for calculating and enabling any timers that are required + to dispatch messages to children. The SrcDesc argument isn't acutally used. + + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC instance. + +**/ +VOID +EFIAPI +PchSmmPeriodicTimerClearSource ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + PchSmmPeriodicTimerProgramTimers (SrcDesc); +} + + +/** + Check if the handle is in type of PeriodicTimer + + @retval TRUE The handle is in type of PeriodicTimer. + @retval FALSE The handle is not in type of PeriodicTimer. +**/ +BOOLEAN +IsSmmPeriodicTimerHandle ( + IN EFI_HANDLE DispatchHandle + ) +{ + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + if (DispatchHandle == (EFI_HANDLE) LinkInDb) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + if (RecordInDb->ProtocolType == PeriodicTimerType) { + return TRUE; + } + } + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, LinkInDb); + } + return FALSE; +} + +/** + Pause SMM periodic timer callback function. + + This function disable the SMI enable of SMI timer according to the DispatchHandle, + which is returned by SMM periodic timer callback registration. + + @retval EFI_SUCCESS This operation is complete. + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. +**/ +EFI_STATUS +EFIAPI +PchSmmPeriodicTimerControlPause ( + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + DATABASE_RECORD *RecordInDb; + + if (IsSmmPeriodicTimerHandle (DispatchHandle) == FALSE) { + return EFI_INVALID_PARAMETER; + } + + RecordInDb = DATABASE_RECORD_FROM_LINK (DispatchHandle); + RecordInDb->MiscData.TimerSmiEnabled = FALSE; + // + // reset the timer interval per SMI trigger due to stop a periodic timer SMI + // + PchSmmPeriodicTimerProgramTimers (&RecordInDb->SrcDesc); + return EFI_SUCCESS; +} + +/** + Resume SMM periodic timer callback function. + + This function enable the SMI enable of SMI timer according to the DispatchHandle, + which is returned by SMM periodic timer callback registration. + + @retval EFI_SUCCESS This operation is complete. + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. +**/ +EFI_STATUS +EFIAPI +PchSmmPeriodicTimerControlResume ( + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + DATABASE_RECORD *RecordInDb; + + if (IsSmmPeriodicTimerHandle (DispatchHandle) == FALSE) { + return EFI_INVALID_PARAMETER; + } + RecordInDb = DATABASE_RECORD_FROM_LINK (DispatchHandle); + RecordInDb->MiscData.TimerSmiEnabled = TRUE; + // + // reset the timer interval per SMI trigger due to resume a periodic timer SMI + // + PchSmmPeriodicTimerProgramTimers (&RecordInDb->SrcDesc); + return EFI_SUCCESS; +} + +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL mPchSmmPeriodicTimerControlProtocol = { + PchSmmPeriodicTimerControlPause, + PchSmmPeriodicTimerControlResume +}; + +/** + Install PCH SMM periodic timer control protocol + + @param[in] Handle handle for this driver + + @retval EFI_SUCCESS Driver initialization completed successfully +**/ +EFI_STATUS +EFIAPI +InstallPchSmmPeriodicTimerControlProtocol ( + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + + // + // Install protocol interface + // + Status = gSmst->SmmInstallProtocolInterface ( + &Handle, + &gPchSmmPeriodicTimerControlGuid, + EFI_NATIVE_INTERFACE, + &mPchSmmPeriodicTimerControlProtocol + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowerButton.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowerButton.c new file mode 100644 index 0000000000..e6d3bf012f --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowerButton.c @@ -0,0 +1,77 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Power Button dispatch protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <PchSmmHelpers.h> +#include <Library/PmcPrivateLib.h> + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mPowerButtonSourceDesc = { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_EN} + }, + S_ACPI_IO_PM1_EN, + N_ACPI_IO_PM1_EN_PWRBTN + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_STS} + }, + S_ACPI_IO_PM1_STS, + N_ACPI_IO_PM1_STS_PWRBTN + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_PM1_STS_REG + } +}; + +/** + Get the power button status. + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] Context Calling context from the hardware, will be updated with the current power button status. + +**/ +VOID +EFIAPI +PowerButtonGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ) +{ + return; +} + +/** + Check whether Power Button status of two contexts match + + @param[in] Context1 Context 1 that includes Power Button status 1 + @param[in] Context2 Context 2 that includes Power Button status 2 + + @retval FALSE Power Button status match + @retval TRUE Power Button status don't match +**/ +BOOLEAN +EFIAPI +PowerButtonCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ) +{ + return TRUE; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c new file mode 100644 index 0000000000..311a21820c --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c @@ -0,0 +1,381 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Sw dispatch protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include <Protocol/SmmCpu.h> +#include <Register/PchRegsLpc.h> +#include <Register/PmcRegs.h> + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_CPU_PROTOCOL *mSmmCpuProtocol; + +STATIC LIST_ENTRY mSwSmiCallbackDataBase; + +// +// "SWSMI" RECORD +// Linked list data structures +// +#define SW_SMI_RECORD_SIGNATURE SIGNATURE_32 ('S', 'W', 'S', 'M') + +#define SW_SMI_RECORD_FROM_LINK(_record) CR (_record, SW_SMI_RECORD, Link, SW_SMI_RECORD_SIGNATURE) + +typedef struct { + UINT32 Signature; + LIST_ENTRY Link; + EFI_SMM_SW_REGISTER_CONTEXT Context; + EFI_SMM_HANDLER_ENTRY_POINT2 Callback; +} SW_SMI_RECORD; + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSwSourceDesc = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_APMC + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_APM + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_APM + } +}; + +/** + Check the SwSmiInputValue to see if there is a duplicated one in the database + + @param[in] SwSmiInputValue SwSmiInputValue + + @retval EFI_SUCCESS There is no duplicated SwSmiInputValue + @retval EFI_INVALID_PARAMETER There is a duplicated SwSmiInputValue +**/ +EFI_STATUS +SmiInputValueDuplicateCheck ( + IN UINTN SwSmiInputValue + ) +{ + SW_SMI_RECORD *SwSmiRecord; + LIST_ENTRY *LinkInDb; + + LinkInDb = GetFirstNode (&mSwSmiCallbackDataBase); + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) { + SwSmiRecord = SW_SMI_RECORD_FROM_LINK (LinkInDb); + if (SwSmiRecord->Context.SwSmiInputValue == SwSmiInputValue) { + return EFI_INVALID_PARAMETER; + } + LinkInDb = GetNextNode (&mSwSmiCallbackDataBase, &SwSmiRecord->Link); + } + + return EFI_SUCCESS; +} + +/** + Register a child SMI source dispatch function for the specified software SMI. + + This service registers a function (DispatchFunction) which will be called when the software + SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On return, + DispatchHandle contains a unique handle which may be used later to unregister the function + using UnRegister(). + + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance. + @param[in] DispatchFunction Function to register for handler when the specified software + SMI is generated. + @param[in, out] RegisterContext Pointer to the dispatch function's context. + The caller fills this context in before calling + the register function to indicate to the register + function which Software SMI input value the + dispatch function should be invoked for. + @param[out] DispatchHandle Handle generated by the dispatcher to track the + function instance. + + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. + @retval EFI_DEVICE_ERROR The SW driver was unable to enable the SMI source. + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI input value + is not within a valid range or is already in use. + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM) to manage this + child. + @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be assigned + for this dispatch. +**/ +EFI_STATUS +EFIAPI +PchSwSmiRegister ( + IN EFI_SMM_SW_DISPATCH2_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + SW_SMI_RECORD *SwSmiRecord; + UINTN Index; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + // + // Find available SW SMI value if the input is -1 + // + if (DispatchContext->SwSmiInputValue == (UINTN) -1) { + for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) { + if (!EFI_ERROR (SmiInputValueDuplicateCheck (Index))) { + DispatchContext->SwSmiInputValue = Index; + break; + } + } + if (DispatchContext->SwSmiInputValue == (UINTN) -1) { + return EFI_OUT_OF_RESOURCES; + } + } + // + // Check if it's a valid SW SMI value. + // The value must not bigger than 0xFF. + // And the value must not be 0xFF sincie it's used for SmmControll protocol. + // + if (DispatchContext->SwSmiInputValue >= MAXIMUM_SWI_VALUE) { + return EFI_INVALID_PARAMETER; + } + + if (EFI_ERROR (SmiInputValueDuplicateCheck (DispatchContext->SwSmiInputValue))) { + return EFI_INVALID_PARAMETER; + } + + // + // Create database record and add to database + // + Status = gSmst->SmmAllocatePool ( + EfiRuntimeServicesData, + sizeof (SW_SMI_RECORD), + (VOID **) &SwSmiRecord + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to allocate memory for SwSmiRecord! \n")); + return EFI_OUT_OF_RESOURCES; + } + // + // Gather information about the registration request + // + SwSmiRecord->Signature = SW_SMI_RECORD_SIGNATURE; + SwSmiRecord->Context.SwSmiInputValue = DispatchContext->SwSmiInputValue; + SwSmiRecord->Callback = DispatchFunction; + // + // Publish the S/W SMI numbers in Serial logs used for Debug build. + // + DEBUG ((DEBUG_INFO, "SW SMI NUM %x Sw Record at Address 0x%X\n", SwSmiRecord->Context.SwSmiInputValue, SwSmiRecord)); + + InsertTailList (&mSwSmiCallbackDataBase, &SwSmiRecord->Link); + + // + // Child's handle will be the address linked list link in the record + // + *DispatchHandle = (EFI_HANDLE) (&SwSmiRecord->Link); + + return EFI_SUCCESS; +} + +/** + Unregister a child SMI source dispatch function for the specified software SMI. + + This service removes the handler associated with DispatchHandle so that it will no longer be + called in response to a software SMI. + + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully unregistered. + @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid. +**/ +EFI_STATUS +EFIAPI +PchSwSmiUnRegister ( + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + EFI_STATUS Status; + SW_SMI_RECORD *RecordToDelete; + + if (DispatchHandle == 0) { + return EFI_INVALID_PARAMETER; + } + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock == TRUE) { + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + RecordToDelete = SW_SMI_RECORD_FROM_LINK (DispatchHandle); + // + // Take the entry out of the linked list + // + if (RecordToDelete->Signature != SW_SMI_RECORD_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + RemoveEntryList (&RecordToDelete->Link); + ZeroMem (RecordToDelete, sizeof (SW_SMI_RECORD)); + Status = gSmst->SmmFreePool (RecordToDelete); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +/** + Main entry point for an SMM handler dispatch or communicate-based callback. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] Context Points to an optional handler context which was specified when the + handler was registered. + @param[in,out] CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in,out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers + should still be called. + @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should + still be called. + @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still + be called. + @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced. +**/ +EFI_STATUS +EFIAPI +PchSwSmiDispatcher ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + EFI_SMM_SAVE_STATE_IO_INFO SmiIoInfo; + UINTN CpuIndex; + SW_SMI_RECORD *SwSmiRecord; + LIST_ENTRY *LinkInDb; + EFI_SMM_SW_CONTEXT SwSmiCommBuffer; + UINTN SwSmiCommBufferSize; + + SwSmiCommBufferSize = sizeof (EFI_SMM_SW_CONTEXT); + // + // The value in DataPort might not be accurate in multiple thread environment. + // There might be racing condition for R_PCH_IO_APM_STS port. + // Therefor, this is just for reference. + // + SwSmiCommBuffer.DataPort = IoRead8 (R_PCH_IO_APM_STS); + + for (CpuIndex = 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) { + Status = mSmmCpuProtocol->ReadSaveState ( + mSmmCpuProtocol, + sizeof (EFI_SMM_SAVE_STATE_IO_INFO), + EFI_SMM_SAVE_STATE_REGISTER_IO, + CpuIndex, + &SmiIoInfo + ); + // + // If this is not the SMI source, skip it. + // + if (EFI_ERROR (Status)) { + continue; + } + // + // If the IO address is not "BYTE" "WRITE" to "R_PCH_IO_APM_CNT (0xB2)", skip it. + // + if ((SmiIoInfo.IoPort != R_PCH_IO_APM_CNT) || + (SmiIoInfo.IoType != EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT) || + (SmiIoInfo.IoWidth != EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8)) + { + continue; + } + // + // If the IO data is used for SmmControl protocol, skip it. + // + if (SmiIoInfo.IoData == 0xFF) { + continue; + } + + SwSmiCommBuffer.SwSmiCpuIndex = CpuIndex; + SwSmiCommBuffer.CommandPort = (UINT8) SmiIoInfo.IoData; + + LinkInDb = GetFirstNode (&mSwSmiCallbackDataBase); + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) { + SwSmiRecord = SW_SMI_RECORD_FROM_LINK (LinkInDb); + if (SwSmiRecord->Context.SwSmiInputValue == SmiIoInfo.IoData) { + SwSmiRecord->Callback ((EFI_HANDLE) &SwSmiRecord->Link, &SwSmiRecord->Context, &SwSmiCommBuffer, &SwSmiCommBufferSize); + } + LinkInDb = GetNextNode (&mSwSmiCallbackDataBase, &SwSmiRecord->Link); + } + } + + return EFI_SUCCESS; +} + +/** + Init required protocol for Pch Sw Dispatch protocol. +**/ +VOID +PchSwDispatchInit ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE DispatchHandle; + DATABASE_RECORD Record; + + // + // Locate PI SMM CPU protocol + // + Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **)&mSmmCpuProtocol); + ASSERT_EFI_ERROR (Status); + + // + // Initialize SW SMI Callback DataBase + // + InitializeListHead (&mSwSmiCallbackDataBase); + + // + // Insert SwSmi handler to PchSmmCore database + // There will always be one SwType record in PchSmmCore database + // + ZeroMem (&Record, sizeof (DATABASE_RECORD)); + Record.Signature = DATABASE_RECORD_SIGNATURE; + Record.Callback = PchSwSmiDispatcher; + Record.ProtocolType = SwType; + + CopyMem (&Record.SrcDesc, &mSwSourceDesc, sizeof (PCH_SMM_SOURCE_DESC)); + + DispatchHandle = NULL; + Status = SmmCoreInsertRecord ( + &Record, + &DispatchHandle + ); + ASSERT_EFI_ERROR (Status); +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c new file mode 100644 index 0000000000..798fb33347 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c @@ -0,0 +1,117 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Sx dispatch protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include <Register/PmcRegs.h> +#include "PchSmiHelper.h" + +extern BOOLEAN mS3SusStart; +#define PROGRESS_CODE_S3_SUSPEND_END PcdGet32 (PcdProgressCodeS3SuspendEnd) + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSxSourceDesc = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_ON_SLP_EN + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_ON_SLP_EN + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_ON_SLP_EN + } +}; + +/** + Get the Sleep type + + @param[in] Record No use + @param[out] Context The context that includes SLP_TYP bits to be filled + +**/ +VOID +EFIAPI +SxGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ) +{ + UINT32 Pm1Cnt; + + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); + + /// + /// By design, the context phase will always be ENTRY + /// + Context->Sx.Phase = SxEntry; + + /// + /// Map the PM1_CNT register's SLP_TYP bits to the context type + /// + switch (Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) { + case V_ACPI_IO_PM1_CNT_S0: + Context->Sx.Type = SxS0; + break; + + case V_ACPI_IO_PM1_CNT_S1: + Context->Sx.Type = SxS1; + break; + + case V_ACPI_IO_PM1_CNT_S3: + Context->Sx.Type = SxS3; + break; + + case V_ACPI_IO_PM1_CNT_S4: + Context->Sx.Type = SxS4; + break; + + case V_ACPI_IO_PM1_CNT_S5: + Context->Sx.Type = SxS5; + break; + + default: + ASSERT (FALSE); + break; + } +} + +/** + Check whether sleep type of two contexts match + + @param[in] Context1 Context 1 that includes sleep type 1 + @param[in] Context2 Context 2 that includes sleep type 2 + + @retval FALSE Sleep types match + @retval TRUE Sleep types don't match +**/ +BOOLEAN +EFIAPI +SxCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ) +{ + return (BOOLEAN) (Context1->Sx.Type == Context2->Sx.Type); +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c new file mode 100644 index 0000000000..6b23956c4a --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c @@ -0,0 +1,244 @@ +/** @file + File to contain all the hardware specific stuff for the Smm USB dispatch protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include <Register/PmcRegs.h> +#include <Library/PchPciBdfLib.h> + +typedef enum { + PchUsbControllerLpc0 = 0, + PchUsbControllerXhci, + PchUsbControllerTypeMax +} PCH_USB_CONTROLLER_TYPE; + +typedef struct { + UINT8 Function; + UINT8 Device; + PCH_USB_CONTROLLER_TYPE UsbConType; +} PCH_USB_CONTROLLER; + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mUsb1Legacy = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_LEGACY_USB + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_LEGACY_USB + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_LEGACY_USB + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mUsb3Legacy = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_LEGACY_USB3 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_LEGACY_USB3 + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_LEGACY_USB3 + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED PCH_USB_CONTROLLER mUsbControllersMap[] = { + { + 0xFF, // to be updated in PchSmmUsbUpdateDescriptors + 0xFF, // to be updated in PchSmmUsbUpdateDescriptors + PchUsbControllerLpc0 + }, + { + 0xFF, // to be updated in PchSmmUsbUpdateDescriptors + 0xFF, // to be updated in PchSmmUsbUpdateDescriptors + PchUsbControllerXhci + } +}; + +/** + Performs update of SmmUsb descriptors with values that have to be evaluated during runtime. +**/ +VOID +PchSmmUsbUpdateDescriptors ( + VOID + ) +{ + // + // mUsbControllersMap + // + mUsbControllersMap[0].Function = LpcFuncNumber (); + mUsbControllersMap[0].Device = LpcDevNumber (); + mUsbControllersMap[1].Function = PchXhciFuncNumber (); + mUsbControllersMap[1].Device = PchXhciDevNumber (); +} + +/** + Find the handle that best matches the input Device Path and return the USB controller type + + @param[in] DevicePath Pointer to the device Path table + @param[out] Controller Returned with the USB controller type of the input device path + + @retval EFI_SUCCESS Find the handle that best matches the input Device Path + @exception EFI_UNSUPPORTED Invalid device Path table or can't find any match USB device path + PCH_USB_CONTROLLER_TYPE The USB controller type of the input + device path +**/ +EFI_STATUS +DevicePathToSupportedController ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT PCH_USB_CONTROLLER_TYPE *Controller + ) +{ + EFI_STATUS Status; + EFI_HANDLE DeviceHandle; + ACPI_HID_DEVICE_PATH *AcpiNode; + PCI_DEVICE_PATH *PciNode; + EFI_DEVICE_PATH_PROTOCOL *RemaingDevicePath; + UINT8 UsbIndex; + /// + /// Find the handle that best matches the Device Path. If it is only a + /// partial match the remaining part of the device path is returned in + /// RemainingDevicePath. + /// + RemaingDevicePath = DevicePath; + Status = gBS->LocateDevicePath ( + &gEfiPciRootBridgeIoProtocolGuid, + &DevicePath, + &DeviceHandle + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + DevicePath = RemaingDevicePath; + + /// + /// Get first node: Acpi Node + /// + AcpiNode = (ACPI_HID_DEVICE_PATH *) RemaingDevicePath; + + if (AcpiNode->Header.Type != ACPI_DEVICE_PATH || + AcpiNode->Header.SubType != ACPI_DP || + DevicePathNodeLength (&AcpiNode->Header) != sizeof (ACPI_HID_DEVICE_PATH) || + AcpiNode->HID != EISA_PNP_ID (0x0A03) || + AcpiNode->UID != 0 + ) { + return EFI_UNSUPPORTED; + } else { + /// + /// Get the next node: Pci Node + /// + RemaingDevicePath = NextDevicePathNode (RemaingDevicePath); + PciNode = (PCI_DEVICE_PATH *) RemaingDevicePath; + if (PciNode->Header.Type != HARDWARE_DEVICE_PATH || + PciNode->Header.SubType != HW_PCI_DP || + DevicePathNodeLength (&PciNode->Header) != sizeof (PCI_DEVICE_PATH) + ) { + return EFI_UNSUPPORTED; + } + + for (UsbIndex = 0; UsbIndex < sizeof (mUsbControllersMap) / sizeof (PCH_USB_CONTROLLER); UsbIndex++) { + if ((PciNode->Device == mUsbControllersMap[UsbIndex].Device) && + (PciNode->Function == mUsbControllersMap[UsbIndex].Function)) { + *Controller = mUsbControllersMap[UsbIndex].UsbConType; + return EFI_SUCCESS; + } + } + + return EFI_UNSUPPORTED; + } +} + +/** + Maps a USB context to a source description. + + @param[in] Context The context we need to map. Type must be USB. + @param[in] SrcDesc The source description that corresponds to the given context. + +**/ +VOID +MapUsbToSrcDesc ( + IN PCH_SMM_CONTEXT *Context, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + PCH_USB_CONTROLLER_TYPE Controller; + EFI_STATUS Status; + + Status = DevicePathToSupportedController (Context->Usb.Device, &Controller); + /// + /// Either the device path passed in by the child is incorrect or + /// the ones stored here internally are incorrect. + /// + ASSERT_EFI_ERROR (Status); + + switch (Context->Usb.Type) { + case UsbLegacy: + switch (Controller) { + case PchUsbControllerLpc0: + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb1Legacy), sizeof (PCH_SMM_SOURCE_DESC)); + break; + + case PchUsbControllerXhci: + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb3Legacy), sizeof (PCH_SMM_SOURCE_DESC)); + break; + + default: + ASSERT (FALSE); + break; + } + break; + + case UsbWake: + ASSERT (FALSE); + break; + + default: + ASSERT (FALSE); + break; + } +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.c new file mode 100644 index 0000000000..c0ce5785fd --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.c @@ -0,0 +1,682 @@ +/** @file + This driver is responsible for the registration of child drivers + and the abstraction of the PCH SMI sources. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include <Register/PchRegs.h> +#include <Register/PmcRegs.h> +#include <Register/TcoRegs.h> + +extern UINT32 mTco1StsClear; +// +// Help handle porting bit shifts to IA-64. +// +#define BIT_ZERO 0x00000001 + +/** + Publish SMI Dispatch protocols. + + +**/ +VOID +PchSmmPublishDispatchProtocols ( + VOID + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINTN Index; + // + // Install protocol interfaces. + // + for (Index = 0; Index < PCH_SMM_PROTOCOL_TYPE_MAX; Index++) { + Status = gSmst->SmmInstallProtocolInterface ( + &mPrivateData.InstallMultProtHandle, + mPrivateData.Protocols[Index].Guid, + EFI_NATIVE_INTERFACE, + &mPrivateData.Protocols[Index].Protocols.Generic + ); + } + ASSERT_EFI_ERROR (Status); +} + +/** + Initialize bits that aren't necessarily related to an SMI source. + + + @retval EFI_SUCCESS SMI source initialization completed. + @retval Asserts Global Smi Bit is not enabled successfully. +**/ +EFI_STATUS +PchSmmInitHardware ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Clear all SMIs + // + PchSmmClearSmi (); + + Status = PchSmmEnableGlobalSmiBit (); + ASSERT_EFI_ERROR (Status); + + // + // Be *really* sure to clear all SMIs + // + PchSmmClearSmi (); + + return EFI_SUCCESS; +} + +/** + Enables the PCH to generate SMIs. Note that no SMIs will be generated + if no SMI sources are enabled. Conversely, no enabled SMI source will + generate SMIs if SMIs are not globally enabled. This is the main + switchbox for SMI generation. + + + @retval EFI_SUCCESS Enable Global Smi Bit completed +**/ +EFI_STATUS +PchSmmEnableGlobalSmiBit ( + VOID + ) +{ + UINT32 SmiEn; + + SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); + + // + // Set the "global smi enable" bit + // + SmiEn |= B_ACPI_IO_SMI_EN_GBL_SMI; + + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn); + + return EFI_SUCCESS; +} + +/** + Clears the SMI after all SMI source have been processed. + Note that this function will not work correctly (as it is + written) unless all SMI sources have been processed. + A revision of this function could manually clear all SMI + status bits to guarantee success. + + + @retval EFI_SUCCESS Clears the SMIs completed + @retval Asserts EOS was not set to a 1 +**/ +EFI_STATUS +PchSmmClearSmi ( + VOID + ) +{ + return EFI_SUCCESS; +} + +/** + Set the SMI EOS bit after all SMI source have been processed. + + + @retval FALSE EOS was not set to a 1; this is an error + @retval TRUE EOS was correctly set to a 1 +**/ +BOOLEAN +PchSmmSetAndCheckEos ( + VOID + ) +{ + UINT32 SmiEn; + + SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); + + // + // Reset the PCH to generate subsequent SMIs + // + SmiEn |= B_ACPI_IO_SMI_EN_EOS; + + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn); + + // + // Double check that the assert worked + // + SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); + + // + // Return TRUE if EOS is set correctly + // + if ((SmiEn & B_ACPI_IO_SMI_EN_EOS) == 0) { + // + // EOS was not set to a 1; this is an error + // + return FALSE; + } else { + // + // EOS was correctly set to a 1 + // + return TRUE; + } +} + +/** + Determine whether an ACPI OS is present (via the SCI_EN bit) + + + @retval TRUE ACPI OS is present + @retval FALSE ACPI OS is not present +**/ +BOOLEAN +PchSmmGetSciEn ( + VOID + ) +{ + BOOLEAN SciEn; + UINT32 Pm1Cnt; + + // + // Determine whether an ACPI OS is present (via the SCI_EN bit) + // + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); + SciEn = (BOOLEAN) ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) == B_ACPI_IO_PM1_CNT_SCI_EN); + + return SciEn; +} + +/** + Read a specifying bit with the register + These may or may not need to change w/ the PCH version; they're highly IA-32 dependent, though. + + @param[in] BitDesc The struct that includes register address, size in byte and bit number + + @retval TRUE The bit is enabled + @retval FALSE The bit is disabled +**/ +BOOLEAN +ReadBitDesc ( + CONST PCH_SMM_BIT_DESC *BitDesc + ) +{ + EFI_STATUS Status; + UINT64 Register; + UINT32 PciBus; + UINT32 PciDev; + UINT32 PciFun; + UINT32 PciReg; + UINTN RegSize; + BOOLEAN BitWasOne; + UINTN ShiftCount; + UINTN RegisterOffset; + UINT32 BaseAddr; + UINT64 PciBaseAddress; + + ASSERT (BitDesc != NULL); + if (BitDesc == NULL) { + return FALSE; + } + ASSERT (!IS_BIT_DESC_NULL (*BitDesc)); + + RegSize = 0; + Register = 0; + ShiftCount = 0; + BitWasOne = FALSE; + + switch (BitDesc->Reg.Type) { + + case ACPI_ADDR_TYPE: + case TCO_ADDR_TYPE: + if (BitDesc->Reg.Type == ACPI_ADDR_TYPE) { + RegisterOffset = BitDesc->Reg.Data.acpi; + BaseAddr = mAcpiBaseAddr; + } else { + RegisterOffset = BitDesc->Reg.Data.tco; + BaseAddr = mTcoBaseAddr; + } + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized. + // Check your assignments to bit descriptions. + // + ASSERT (FALSE); + break; + + case 1: + RegSize = SMM_IO_UINT8; + break; + + case 2: + RegSize = SMM_IO_UINT16; + break; + + case 4: + RegSize = SMM_IO_UINT32; + break; + + case 8: + RegSize = SMM_IO_UINT64; + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + // + // Double check that we correctly read in the acpi base address + // + ASSERT ((BaseAddr != 0x0) && ((BaseAddr & 0x1) != 0x1)); + + ShiftCount = BitDesc->Bit; + // + // As current CPU Smm Io can only support at most + // 32-bit read/write,if Operation is 64 bit, + // we do a 32 bit operation according to BitDesc->Bit + // + if (RegSize == SMM_IO_UINT64) { + RegSize = SMM_IO_UINT32; + // + // If the operation is for high 32 bits + // + if (BitDesc->Bit >= 32) { + RegisterOffset += 4; + ShiftCount -= 32; + } + } + + Status = gSmst->SmmIo.Io.Read ( + &gSmst->SmmIo, + RegSize, + BaseAddr + RegisterOffset, + 1, + &Register + ); + ASSERT_EFI_ERROR (Status); + + if ((Register & (LShiftU64 (BIT_ZERO, ShiftCount))) != 0) { + BitWasOne = TRUE; + } else { + BitWasOne = FALSE; + } + break; + + case GPIO_ADDR_TYPE: + case MEMORY_MAPPED_IO_ADDRESS_TYPE: + // + // Read the register, and it with the bit to read + // + switch (BitDesc->SizeInBytes) { + case 1: + Register = (UINT64) MmioRead8 ((UINTN) BitDesc->Reg.Data.Mmio); + break; + + case 2: + Register = (UINT64) MmioRead16 ((UINTN) BitDesc->Reg.Data.Mmio); + break; + + case 4: + Register = (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio); + break; + + case 8: + Register = (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio); + *((UINT32 *) (&Register) + 1) = MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio + 4); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + + Register = Register & (LShiftU64 (BIT0, BitDesc->Bit)); + if (Register) { + BitWasOne = TRUE; + } else { + BitWasOne = FALSE; + } + break; + + case PCIE_ADDR_TYPE: + PciBus = BitDesc->Reg.Data.pcie.Fields.Bus; + PciDev = BitDesc->Reg.Data.pcie.Fields.Dev; + PciFun = BitDesc->Reg.Data.pcie.Fields.Fnc; + PciReg = BitDesc->Reg.Data.pcie.Fields.Reg; + PciBaseAddress = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0); + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized. + // Check your assignments to bit descriptions. + // + ASSERT (FALSE); + break; + + case 1: + Register = (UINT64) PciSegmentRead8 (PciBaseAddress + PciReg); + break; + + case 2: + Register = (UINT64) PciSegmentRead16 (PciBaseAddress + PciReg); + break; + + case 4: + Register = (UINT64) PciSegmentRead32 (PciBaseAddress + PciReg); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + + if ((Register & (LShiftU64 (BIT_ZERO, BitDesc->Bit))) != 0) { + BitWasOne = TRUE; + } else { + BitWasOne = FALSE; + } + break; + + case PCR_ADDR_TYPE: + // + // Read the register, and it with the bit to read + // + switch (BitDesc->SizeInBytes) { + case 1: + Register = PchPcrRead8 (BitDesc->Reg.Data.Pcr.Fields.Pid, BitDesc->Reg.Data.Pcr.Fields.Offset); + break; + + case 2: + Register = PchPcrRead16 (BitDesc->Reg.Data.Pcr.Fields.Pid, BitDesc->Reg.Data.Pcr.Fields.Offset); + break; + + case 4: + Register = PchPcrRead32 (BitDesc->Reg.Data.Pcr.Fields.Pid, BitDesc->Reg.Data.Pcr.Fields.Offset); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + + Register = Register & (LShiftU64 (BIT0, BitDesc->Bit)); + if (Register) { + BitWasOne = TRUE; + } else { + BitWasOne = FALSE; + } + break; + + default: + // + // This address type is not yet implemented + // + ASSERT (FALSE); + break; + } + + return BitWasOne; +} + +/** + Write a specifying bit with the register + + @param[in] BitDesc The struct that includes register address, size in byte and bit number + @param[in] ValueToWrite The value to be wrote + @param[in] WriteClear If the rest bits of the register is write clear + +**/ +VOID +WriteBitDesc ( + CONST PCH_SMM_BIT_DESC *BitDesc, + CONST BOOLEAN ValueToWrite, + CONST BOOLEAN WriteClear + ) +{ + EFI_STATUS Status; + UINT64 Register; + UINT64 AndVal; + UINT64 OrVal; + UINT32 RegSize; + UINT32 PciBus; + UINT32 PciDev; + UINT32 PciFun; + UINT32 PciReg; + UINTN RegisterOffset; + UINT32 BaseAddr; + UINT64 PciBaseAddress; + + ASSERT (BitDesc != NULL); + if (BitDesc == NULL) { + return; + } + ASSERT (!IS_BIT_DESC_NULL (*BitDesc)); + + RegSize = 0; + Register = 0; + + if (WriteClear) { + AndVal = LShiftU64 (BIT_ZERO, BitDesc->Bit); + } else { + AndVal = ~(LShiftU64 (BIT_ZERO, BitDesc->Bit)); + } + + OrVal = (LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit)); + + switch (BitDesc->Reg.Type) { + + case ACPI_ADDR_TYPE: + case TCO_ADDR_TYPE: + if (BitDesc->Reg.Type == ACPI_ADDR_TYPE) { + RegisterOffset = BitDesc->Reg.Data.acpi; + BaseAddr = mAcpiBaseAddr; + } else { + RegisterOffset = BitDesc->Reg.Data.tco; + BaseAddr = mTcoBaseAddr; + } + + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized. + // Check your assignments to bit descriptions. + // + ASSERT (FALSE); + break; + + case 1: + RegSize = SMM_IO_UINT8; + break; + + case 2: + RegSize = SMM_IO_UINT16; + break; + + case 4: + RegSize = SMM_IO_UINT32; + break; + + case 8: + RegSize = SMM_IO_UINT64; + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + // + // Double check that we correctly read in the acpi base address + // + ASSERT ((BaseAddr != 0x0) && ((BaseAddr & 0x1) != 0x1)); + + // + // As current CPU Smm Io can only support at most + // 32-bit read/write,if Operation is 64 bit, + // we do a 32 bit operation according to BitDesc->Bit + // + if (RegSize == SMM_IO_UINT64) { + RegSize = SMM_IO_UINT32; + // + // If the operation is for high 32 bits + // + if (BitDesc->Bit >= 32) { + RegisterOffset += 4; + + if (WriteClear) { + AndVal = LShiftU64 (BIT_ZERO, BitDesc->Bit - 32); + } else { + AndVal = ~(LShiftU64 (BIT_ZERO, BitDesc->Bit - 32)); + } + + OrVal = LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit - 32); + } + } + + Status = gSmst->SmmIo.Io.Read ( + &gSmst->SmmIo, + RegSize, + BaseAddr + RegisterOffset, + 1, + &Register + ); + ASSERT_EFI_ERROR (Status); + + Register &= AndVal; + Register |= OrVal; + + Status = gSmst->SmmIo.Io.Write ( + &gSmst->SmmIo, + RegSize, + BaseAddr + RegisterOffset, + 1, + &Register + ); + ASSERT_EFI_ERROR (Status); + break; + + case GPIO_ADDR_TYPE: + case MEMORY_MAPPED_IO_ADDRESS_TYPE: + // + // Read the register, or it with the bit to set, then write it back. + // + switch (BitDesc->SizeInBytes) { + case 1: + MmioAndThenOr8 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT8) AndVal, (UINT8) OrVal); + break; + + case 2: + MmioAndThenOr16 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT16) AndVal, (UINT16) OrVal); + break; + + case 4: + MmioAndThenOr32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) AndVal, (UINT32) OrVal); + break; + + case 8: + Register = (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio); + *((UINT32 *) (&Register) + 1) = MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio + 4); + Register &= AndVal; + Register |= OrVal; + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) Register); + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio + 4, *((UINT32 *) (&Register) + 1)); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + break; + + case PCIE_ADDR_TYPE: + PciBus = BitDesc->Reg.Data.pcie.Fields.Bus; + PciDev = BitDesc->Reg.Data.pcie.Fields.Dev; + PciFun = BitDesc->Reg.Data.pcie.Fields.Fnc; + PciReg = BitDesc->Reg.Data.pcie.Fields.Reg; + PciBaseAddress = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0); + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized -- check your assignments + // to bit descriptions. + // + ASSERT (FALSE); + break; + + case 1: + PciSegmentAndThenOr8 (PciBaseAddress + PciReg, (UINT8) AndVal, (UINT8) OrVal); + break; + + case 2: + PciSegmentAndThenOr16 (PciBaseAddress + PciReg, (UINT16) AndVal, (UINT16) OrVal); + break; + + case 4: + PciSegmentAndThenOr32 (PciBaseAddress + PciReg, (UINT32) AndVal, (UINT32) OrVal); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + break; + + case PCR_ADDR_TYPE: + // + // Read the register, or it with the bit to set, then write it back. + // + switch (BitDesc->SizeInBytes) { + case 1: + PchPcrAndThenOr8 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pid, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT8) AndVal, (UINT8) OrVal); + break; + + case 2: + PchPcrAndThenOr16 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pid, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT16) AndVal, (UINT16) OrVal); + break; + + case 4: + PchPcrAndThenOr32 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pid, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT32) AndVal, (UINT32) OrVal); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + break; + + default: + // + // This address type is not yet implemented + // + ASSERT (FALSE); + break; + } +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.h new file mode 100644 index 0000000000..998b38e159 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.h @@ -0,0 +1,107 @@ +/** @file + This driver is responsible for the registration of child drivers + and the abstraction of the PCH SMI sources. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCHX_SMM_HELPERS_H_ +#define _PCHX_SMM_HELPERS_H_ + +#include "PchSmm.h" + +/** + Initialize bits that aren't necessarily related to an SMI source. + + + @retval EFI_SUCCESS SMI source initialization completed. + @retval Asserts Global Smi Bit is not enabled successfully. +**/ +EFI_STATUS +PchSmmInitHardware ( + VOID + ); + +/** + Enables the PCH to generate SMIs. Note that no SMIs will be generated + if no SMI sources are enabled. Conversely, no enabled SMI source will + generate SMIs if SMIs are not globally enabled. This is the main + switchbox for SMI generation. + + + @retval EFI_SUCCESS Enable Global Smi Bit completed +**/ +EFI_STATUS +PchSmmEnableGlobalSmiBit ( + VOID + ); + +/** + Clears the SMI after all SMI source have been processed. + Note that this function will not work correctly (as it is + written) unless all SMI sources have been processed. + A revision of this function could manually clear all SMI + status bits to guarantee success. + + + @retval EFI_SUCCESS Clears the SMIs completed + @retval Asserts EOS was not set to a 1 +**/ +EFI_STATUS +PchSmmClearSmi ( + VOID + ); + +/** + Set the SMI EOS bit after all SMI source have been processed. + + + @retval FALSE EOS was not set to a 1; this is an error + @retval TRUE EOS was correctly set to a 1 +**/ +BOOLEAN +PchSmmSetAndCheckEos ( + VOID + ); + +/** + Determine whether an ACPI OS is present (via the SCI_EN bit) + + + @retval TRUE ACPI OS is present + @retval FALSE ACPI OS is not present +**/ +BOOLEAN +PchSmmGetSciEn ( + VOID + ); + +/** + Read a specifying bit with the register + + @param[in] BitDesc The struct that includes register address, size in byte and bit number + + @retval TRUE The bit is enabled + @retval FALSE The bit is disabled +**/ +BOOLEAN +ReadBitDesc ( + CONST PCH_SMM_BIT_DESC *BitDesc + ); + +/** + Write a specifying bit with the register + + @param[in] BitDesc The struct that includes register address, size in byte and bit number + @param[in] ValueToWrite The value to be wrote + @param[in] WriteClear If the rest bits of the register is write clear + +**/ +VOID +WriteBitDesc ( + CONST PCH_SMM_BIT_DESC *BitDesc, + CONST BOOLEAN ValueToWrite, + CONST BOOLEAN WriteClear + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PcieSmmClient.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PcieSmmClient.c new file mode 100644 index 0000000000..6d210f671b --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PcieSmmClient.c @@ -0,0 +1,38 @@ +/** @file + This function handle the register/unregister of PCH PCIe specific SMI events. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include <Register/PmcRegs.h> +#include <Register/PchPcieRpRegs.h> +#include <Library/CpuPcieInfoFruLib.h> +#include <CpuPcieInfo.h> +#include <Library/PchPcieRpLib.h> +#include <Library/PchInfoLib.h> +#include <Library/PchPciBdfLib.h> + +extern UINT32 mNumOfRootPorts; + +/** + Get CPU or PCH Pcie Root Port Device and Function Number by Root Port physical Number + + @param[in] RpNumber Root port physical number. (0-based) + @param[out] RpDev Return corresponding root port device number. + @param[out] RpFun Return corresponding root port function number. +**/ +VOID +GetPcieRpDevFun ( + IN UINTN RpIndex, + OUT UINTN *RpDev, + OUT UINTN *RpFun + ) +{ + if (RpIndex >= CpuRpIndex0 && RpIndex <= CpuRpIndex3) { + GetCpuPcieRpDevFun ((RpIndex - CpuRpIndex0), RpDev, RpFun); + } else { + *RpDev = PchPcieRpDevNumber (RpIndex); + *RpFun = PchPcieRpFuncNumber (RpIndex); + } +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/SmmGlobalsPch.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/SmmGlobalsPch.c new file mode 100644 index 0000000000..f66079884f --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/SmmGlobalsPch.c @@ -0,0 +1,20 @@ +/** @file + This driver is responsible for the registration of child drivers + and the abstraction of the PCH SMI sources. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <Register/TcoRegs.h> + +GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mTco1StsClear = + ( + B_TCO_IO_TCO1_STS_DMISERR | + B_TCO_IO_TCO1_STS_DMISMI | + B_TCO_IO_TCO1_STS_DMISCI | + B_TCO_IO_TCO1_STS_BIOSWR | + B_TCO_IO_TCO1_STS_NEWCENTURY | + B_TCO_IO_TCO1_STS_TIMEOUT | + B_TCO_IO_TCO1_STS_TCO_INT | + B_TCO_IO_TCO1_STS_SW_TCO_SMI + ); diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf new file mode 100644 index 0000000000..d73c12f964 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf @@ -0,0 +1,53 @@ +## @file +# Component description file for SmmControl module +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = SmmControl +FILE_GUID = A0BAD9F7-AB78-491b-B583-C52B7F84B9E0 +VERSION_STRING = 1.0 +MODULE_TYPE = DXE_RUNTIME_DRIVER +ENTRY_POINT = SmmControlDriverEntryInit +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + + + +[LibraryClasses] +IoLib +UefiDriverEntryPoint +DebugLib +UefiBootServicesTableLib +UefiRuntimeServicesTableLib +PmcLib +GpioLib + + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + + +[Sources] +SmmControlDriver.h +SmmControlDriver.c + + +[Protocols] +gEfiSmmControl2ProtocolGuid ## PRODUCES + + +[Guids] +gEfiEventVirtualAddressChangeGuid + + +[Depex] +TRUE diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c new file mode 100644 index 0000000000..8864d18787 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c @@ -0,0 +1,338 @@ +/** @file + This is the driver that publishes the SMM Control Protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <Library/IoLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Guid/EventGroup.h> +#include <Library/PmcLib.h> +#include <Library/GpioLib.h> +#include <IndustryStandard/Pci30.h> +#include <Register/PchRegsLpc.h> +#include <Register/SpiRegs.h> +#include <Register/PmcRegs.h> +#include "SmmControlDriver.h" + +STATIC SMM_CONTROL_PRIVATE_DATA mSmmControl; +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mABase; + +/** + Fixup internal data pointers so that the services can be called in virtual mode. + + @param[in] Event The event registered. + @param[in] Context Event context. + +**/ +VOID +EFIAPI +SmmControlVirtualAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Trigger)); + gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Clear)); +} + +/** + <b>SmmControl DXE RUNTIME Module Entry Point</b>\n + - <b>Introduction</b>\n + The SmmControl module is a DXE RUNTIME driver that provides a standard way + for other drivers to trigger software SMIs. + + - @pre + - PCH Power Management I/O space base address has already been programmed. + If SmmControl Runtime DXE driver is run before Status Code Runtime Protocol + is installed and there is the need to use Status code in the driver, it will + be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID to the dependency file. + - EFI_SMM_BASE2_PROTOCOL + - Documented in the System Management Mode Core Interface Specification. + + - @result + The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL documented in + System Management Mode Core Interface Specification. + + @param[in] ImageHandle Handle for the image of this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_STATUS Results of the installation of the SMM Control Protocol +**/ +EFI_STATUS +EFIAPI +SmmControlDriverEntryInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() Start\n")); + + // + // Get the Power Management I/O space base address. We assume that + // this base address has already been programmed if this driver is + // being run. + // + mABase = PmcGetAcpiBase (); + + Status = EFI_SUCCESS; + if (mABase != 0) { + // + // Install the instance of the protocol + // + mSmmControl.Signature = SMM_CONTROL_PRIVATE_DATA_SIGNATURE; + mSmmControl.Handle = ImageHandle; + + mSmmControl.SmmControl.Trigger = Activate; + mSmmControl.SmmControl.Clear = Deactivate; + mSmmControl.SmmControl.MinimumTriggerPeriod = 0; + + // + // Install our protocol interfaces on the device's handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mSmmControl.Handle, + &gEfiSmmControl2ProtocolGuid, + &mSmmControl.SmmControl, + NULL + ); + } else { + Status = EFI_DEVICE_ERROR; + return Status; + } + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + SmmControlVirtualAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &Event + ); + + DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() End\n")); + + return Status; +} + +/** + Trigger the software SMI + + @param[in] Command The value to be set on the software SMI command port + @param[in] Data The value to be set on the software SMI data port + + @retval EFI_SUCCESS Function completes successfully +**/ +EFI_STATUS +EFIAPI +SmmTrigger ( + IN UINT8 Command, + IN UINT8 Data + ) +{ + UINT32 OutputData; + UINT32 OutputPort; + + // + // Enable the APMC SMI + // + OutputPort = mABase + R_ACPI_IO_SMI_EN; + OutputData = IoRead32 ((UINTN) OutputPort); + OutputData |= (B_ACPI_IO_SMI_EN_APMC | B_ACPI_IO_SMI_EN_GBL_SMI); + DEBUG ( + (DEBUG_VERBOSE, + "The SMI Control Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite32 ( + (UINTN) OutputPort, + (UINT32) (OutputData) + ); + + OutputPort = R_PCH_IO_APM_STS; + OutputData = Data; + + // + // Write data to APM DATA PORT + // + IoWrite8 ( + (UINTN) OutputPort, + (UINT8) (OutputData) + ); + OutputPort = R_PCH_IO_APM_CNT; + OutputData = Command; + + // + // Generate the APMC SMI + // + IoWrite8 ( + (UINTN) OutputPort, + (UINT8) (OutputData) + ); + + return EFI_SUCCESS; +} + +/** + Clear the SMI status + + + @retval EFI_SUCCESS The function completes successfully + @retval EFI_DEVICE_ERROR Something error occurred +**/ +EFI_STATUS +EFIAPI +SmmClear ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 OutputData; + UINT32 OutputPort; + + Status = EFI_SUCCESS; + + // + // Clear the Power Button Override Status Bit, it gates EOS from being set. + // + OutputPort = mABase + R_ACPI_IO_PM1_STS; + OutputData = B_ACPI_IO_PM1_STS_PRBTNOR; + DEBUG ( + (DEBUG_VERBOSE, + "The PM1 Status Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite16 ( + (UINTN) OutputPort, + (UINT16) (OutputData) + ); + + // + // Clear the APM SMI Status Bit + // + OutputPort = mABase + R_ACPI_IO_SMI_STS; + OutputData = B_ACPI_IO_SMI_STS_APM; + DEBUG ( + (DEBUG_VERBOSE, + "The SMI Status Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite32 ( + (UINTN) OutputPort, + (UINT32) (OutputData) + ); + + // + // Set the EOS Bit + // + OutputPort = mABase + R_ACPI_IO_SMI_EN; + OutputData = IoRead32 ((UINTN) OutputPort); + OutputData |= B_ACPI_IO_SMI_EN_EOS; + DEBUG ( + (DEBUG_VERBOSE, + "The SMI Control Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite32 ( + (UINTN) OutputPort, + (UINT32) (OutputData) + ); + + // + // There is no need to read EOS back and check if it is set. + // This can lead to a reading of zero if an SMI occurs right after the SMI_EN port read + // but before the data is returned to the CPU. + // SMM Dispatcher should make sure that EOS is set after all SMI sources are processed. + // + return Status; +} + +/** + This routine generates an SMI + + @param[in] This The EFI SMM Control protocol instance + @param[in, out] CommandPort The buffer contains data to the command port + @param[in, out] DataPort The buffer contains data to the data port + @param[in] Periodic Periodic or not + @param[in] ActivationInterval Interval of periodic SMI + + @retval EFI Status Describing the result of the operation + @retval EFI_INVALID_PARAMETER Some parameter value passed is not supported +**/ +EFI_STATUS +EFIAPI +Activate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL * This, + IN OUT UINT8 *CommandPort OPTIONAL, + IN OUT UINT8 *DataPort OPTIONAL, + IN BOOLEAN Periodic OPTIONAL, + IN UINTN ActivationInterval OPTIONAL + ) +{ + EFI_STATUS Status; + UINT8 Command; + UINT8 Data; + + if (Periodic) { + DEBUG ((DEBUG_WARN, "Invalid parameter\n")); + return EFI_INVALID_PARAMETER; + } + + // + // Extract the values from CommandPort and DataPort + // + if (CommandPort == NULL) { + Command = 0xFF; + } else { + Command = *CommandPort; + } + + if (DataPort == NULL) { + Data = 0x00; + } else { + Data = *DataPort; + } + + // + // Clear any pending the APM SMI + // + Status = SmmClear (); + if (EFI_ERROR (Status)) { + return Status; + } + + return SmmTrigger (Command, Data); +} + +/** + This routine clears an SMI + + @param[in] This The EFI SMM Control protocol instance + @param[in] Periodic Periodic or not + + @retval EFI Status Describing the result of the operation + @retval EFI_INVALID_PARAMETER Some parameter value passed is not supported +**/ +EFI_STATUS +EFIAPI +Deactivate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN BOOLEAN Periodic OPTIONAL + ) +{ + if (Periodic) { + return EFI_INVALID_PARAMETER; + } + + return SmmClear (); +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h new file mode 100644 index 0000000000..a366de7d5e --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h @@ -0,0 +1,122 @@ +/** @file + Header file for SMM Control Driver. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _SMM_CONTROL_DRIVER_H_ +#define _SMM_CONTROL_DRIVER_H_ + +#include <Protocol/SmmControl2.h> + + +#define SMM_CONTROL_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', '4', 's', 'c') + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + EFI_SMM_CONTROL2_PROTOCOL SmmControl; +} SMM_CONTROL_PRIVATE_DATA; + +#define SMM_CONTROL_PRIVATE_DATA_FROM_THIS(a) CR (a, SMM_CONTROL_PRIVATE_DATA, SmmControl, SMM_CONTROL_DEV_SIGNATURE) + +// +// Prototypes +// + +/** + <b>SmmControl DXE RUNTIME Module Entry Point</b>\n + - <b>Introduction</b>\n + The SmmControl module is a DXE RUNTIME driver that provides a standard way + for other drivers to trigger software SMIs. + + - @pre + - PCH Power Management I/O space base address has already been programmed. + If SmmControl Runtime DXE driver is run before Status Code Runtime Protocol + is installed and there is the need to use Status code in the driver, it will + be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID to the dependency file. + - EFI_SMM_BASE2_PROTOCOL + - Documented in the System Management Mode Core Interface Specification. + + - @result + The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL documented in + System Management Mode Core Interface Specification. + + @param[in] ImageHandle Handle for the image of this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_STATUS Results of the installation of the SMM Control Protocol +**/ +EFI_STATUS +EFIAPI +SmmControlDriverEntryInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Trigger the software SMI + + @param[in] Command The value to be set on the software SMI command port + @param[in] Data The value to be set on the software SMI data port + + @retval EFI_SUCCESS Function completes successfully +**/ +EFI_STATUS +EFIAPI +SmmTrigger ( + IN UINT8 Command, + IN UINT8 Data + ); + +/** + Clear the SMI status + + + @retval EFI_SUCCESS The function completes successfully + @retval EFI_DEVICE_ERROR Something error occurred +**/ +EFI_STATUS +EFIAPI +SmmClear ( + VOID + ); + +/** + This routine generates an SMI + + @param[in] This The EFI SMM Control protocol instance + @param[in, out] ArgumentBuffer The buffer of argument + @param[in, out] ArgumentBufferSize The size of the argument buffer + @param[in] Periodic Periodic or not + @param[in] ActivationInterval Interval of periodic SMI + + @retval EFI Status Describing the result of the operation + @retval EFI_INVALID_PARAMETER Some parameter value passed is not supported +**/ +EFI_STATUS +EFIAPI +Activate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN OUT UINT8 *ArgumentBuffer OPTIONAL, + IN OUT UINT8 *ArgumentBufferSize OPTIONAL, + IN BOOLEAN Periodic OPTIONAL, + IN UINTN ActivationInterval OPTIONAL + ); + +/** + This routine clears an SMI + + @param[in] This The EFI SMM Control protocol instance + @param[in] Periodic Periodic or not + + @retval EFI Status Describing the result of the operation + @retval EFI_INVALID_PARAMETER Some parameter value passed is not supported +**/ +EFI_STATUS +EFIAPI +Deactivate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN BOOLEAN Periodic OPTIONAL + ); +#endif -- 2.36.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107784): https://edk2.groups.io/g/devel/message/107784 Mute This Topic: https://groups.io/mt/100551004/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [edk2-devel] [PATCH v2 6/7] AlderlakeSiliconPkg/SystemAgent: Add include headers 2023-08-04 17:37 [edk2-devel] [PATCH v2 1/7] AlderlakeSiliconPkg: Add package and library instances Saloni Kasbekar ` (3 preceding siblings ...) 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 5/7] AlderlakeSiliconPkg/Pch: Add drivers Saloni Kasbekar @ 2023-08-04 17:37 ` Saloni Kasbekar 2023-08-16 2:45 ` Chuang, Rosen 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 7/7] AlderlakeSiliconPkg/SystemAgent: Add library and driver modules Saloni Kasbekar 2023-08-16 2:42 ` [edk2-devel] [PATCH v2 1/7] AlderlakeSiliconPkg: Add package and library instances Chuang, Rosen 6 siblings, 1 reply; 14+ messages in thread From: Saloni Kasbekar @ 2023-08-04 17:37 UTC (permalink / raw) To: devel Cc: Saloni Kasbekar, Sai Chaganty, Nate DeSimone, Isaac Oram, Rosen Chuang Adds the following header files: * SystemAgent/Include Cc: Sai Chaganty <rangasai.v.chaganty@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Isaac Oram <isaac.w.oram@intel.com> Cc: Rosen Chuang <rosen.chuang@intel.com> Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com> --- .../Include/ConfigBlock/MemoryDxeConfig.h | 126 ++++++++++ .../ConfigBlock/SaMiscPeiPreMemConfig.h | 112 +++++++++ .../Include/Library/DxeSaPolicyLib.h | 58 +++++ .../Include/Library/PeiSaPolicyLib.h | 13 ++ .../SystemAgent/Include/MemInfoHob.h | 220 ++++++++++++++++++ .../SystemAgent/Include/Protocol/SaPolicy.h | 54 +++++ .../SystemAgent/Include/SaDataHob.h | 28 +++ 7 files changed, 611 insertions(+) create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/MemoryDxeConfig.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/SaMiscPeiPreMemConfig.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/DxeSaPolicyLib.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/PeiSaPolicyLib.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/MemInfoHob.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Protocol/SaPolicy.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/SaDataHob.h diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/MemoryDxeConfig.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/MemoryDxeConfig.h new file mode 100644 index 0000000000..eca0c2f1ba --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/MemoryDxeConfig.h @@ -0,0 +1,126 @@ +/** @file + Memory DXE Policy definitions + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _MEMORY_DXE_CONFIG_H_ +#define _MEMORY_DXE_CONFIG_H_ + +#pragma pack(push, 1) + +/** + Making any setup structure change after code frozen + will need to maintain backward compatibility, bump up + structure revision and update below history table\n + <b>Revision 1</b>: - Initial version. +**/ +#define MEMORY_DXE_CONFIG_REVISION 2 + +typedef struct _MEMORY_DXE_CONFIG MEMORY_DXE_CONFIG; + +/** + Retrieves the OEM custom string for the SMBIOS Type 17 Table DeviceLocator field. + Implementation of this function is optional, if this function pointer is NULL then + the reference implementation of DeviceLocator will be used. + + @param[in] This A pointer to this instance of MEMORY_DXE_CONFIG. + @param[in] Controller Desired Controller to get a DeviceLocator string for. + @param[in] Dimm Desired DIMM to get a DeviceLocator string for. + @param[in] MdSocket 0 = Memory Down, 1 = Socketed. + + @retval The DeviceLocator string + @retval NULL If the return value is NULL, the default value will be used. +**/ +typedef +CHAR8* +(EFIAPI *MEMORY_DXE_CONFIG_GET_DEVICE_LOCATOR_STRING)( + IN CONST MEMORY_DXE_CONFIG *This, + IN UINT8 Controller, + IN UINT8 Dimm, + IN UINT8 MdSocket + ); + +/** + Retrieves the OEM custom string for the SMBIOS Type 17 Table BankLocator field. + Implementation of this function is optional, if this function pointer is NULL then + the reference implementation of DeviceLocator will be used. + + @param[in] This A pointer to this instance of MEMORY_DXE_CONFIG. + @param[in] Controller Desired Controller to get a BankLocator string for. + @param[in] Dimm Desired DIMM to get a BankLocator string for. + @param[in] MdSocket 0 = Memory Down, 1 = Socketed. + + @retval The BankLocator string + @retval NULL If the return value is NULL, the default value will be used. +**/ +typedef +CHAR8* +(EFIAPI *MEMORY_DXE_CONFIG_GET_BANK_LOCATOR_STRING)( + IN CONST MEMORY_DXE_CONFIG *This, + IN UINT8 Controller, + IN UINT8 Dimm, + IN UINT8 MdSocket + ); + +/** + The Memory Configuration includes DIMM SPD address Map and DIMM Slot Mechanical present bit map. + The data elements should be initialized by a Platform Module.\n + <b>Revision 1</b>: + - Initial version. +**/ +struct _MEMORY_DXE_CONFIG { + CONFIG_BLOCK_HEADER Header; ///< Offset 0-27: Config Block Header +/** + Offset 28: + Dimm SPD address + Only Server support 2 channels * 3 slots per channel = 6 sockets totally + The Desktop and mobile only support 2 channels * 2 slots per channel = 4 sockets totally + So there is mapping rule here for Desktop and mobile that there are no more 4 DIMMS totally in a system: + Channel A/ Slot 0 --> Dimm 0 --> SpdAddressTable[0] + Channel A/ Slot 1 --> Dimm 1 --> SpdAddressTable[1] + Channel B/ Slot 0 --> Dimm 2 --> SpdAddressTable[2] + Channel B/ Slot 1 --> Dimm 3 --> SpdAddressTable[3] + Refer to SmbiosMemory.c for use + If change the mapping rule, please update the Revision number. +**/ + UINT8 *SpdAddressTable; +/** + Offset 36: + ChannelASlotMap and ChannelBSlotMap change to use SlotMap as the DIMM slot map solution. + Reserve 2-bytes in order to comply with 4-bytes alignment and keep the offset of other members. +**/ + UINT8 ChannelASlotMap; + UINT8 ChannelBSlotMap; +/** + Offset 38: + MRC execution time measurement: <b>0=Disable</b>, 1=Enable +**/ + UINT8 MrcTimeMeasure; +/** + Offset 39: + Fast boot: 0=Disable, <b>1=Enable</b> +**/ + UINT8 MrcFastBoot; +/** + Offset 40: + Retrieves the OEM custom string for the SMBIOS Type 17 Table DeviceLocator field. +**/ + MEMORY_DXE_CONFIG_GET_DEVICE_LOCATOR_STRING GetDeviceLocatorString; +/** + Offset 48: + Retrieves the OEM custom string for the SMBIOS Type 17 Table BankLocator field. +**/ + MEMORY_DXE_CONFIG_GET_BANK_LOCATOR_STRING GetBankLocatorString; +/** + Offset 56: + Each DIMM Slot Mechanical present bit map, bit 0 -> DIMM 0, bit 1 -> DIMM1, ... + if the bit is 1, the related DIMM slot is present. + E.g. if memory controller 0 channel 3 has 2 DIMMs, SlotMap[0][3] = 0x03; + E.g. if memory controller 1 channel 2 has only 1 DIMMs, SlotMap[1][2] = 0x0; +**/ + UINT8 **SlotMap; +}; +#pragma pack(pop) + +#endif // _MEMORY_DXE_CONFIG_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/SaMiscPeiPreMemConfig.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/SaMiscPeiPreMemConfig.h new file mode 100644 index 0000000000..cb75696b61 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/SaMiscPeiPreMemConfig.h @@ -0,0 +1,112 @@ +/** @file + Policy details for miscellaneous configuration in System Agent + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _SA_MISC_PEI_PREMEM_CONFIG_H_ +#define _SA_MISC_PEI_PREMEM_CONFIG_H_ + +#pragma pack(push, 1) + +#ifndef MEM_CFG_MAX_SOCKETS +#define MEM_CFG_MAX_SOCKETS 16 +#endif + +#define SA_MISC_PEI_PREMEM_CONFIG_REVISION 1 + +/** + This configuration block is to configure SA Miscellaneous variables during PEI Pre-Mem phase like programming + different System Agent BARs, TsegSize, MmioSize required etc. + <b>Revision 1</b>: + - Initial version. +**/ +typedef struct { + CONFIG_BLOCK_HEADER Header; ///< Offset 0-27 Config Block Header + /** + Offset 28 Memory DIMMs' SPD address for reading SPD data. + TGL Mapping + 0 - Controller 0 Channel 0 Dimm 0 - DDR4 - DDR5 - LPDDR4 - LPDDR5 + 1 - Controller 0 Channel 0 Dimm 1 - DDR4 + 2 - Controller 0 Channel 1 Dimm 0 -------- DDR5 - LPDDR4 - LPDDR5 + 3 - Controller 0 Channel 1 Dimm 1 -------- DDR5 2DPC + 4 - Controller 0 Channel 2 Dimm 0 --------------- LPDDR4 - LPDDR5 + 6 - Controller 0 Channel 3 Dimm 0 --------------- LPDDR4 - LPDDR5 + 8 - Controller 1 Channel 0 Dimm 0 - DDR4 - DDR5 - LPDDR4 - LPDDR5 + 9 - Controller 1 Channel 0 Dimm 1 - DDR4 + 10 - Controller 1 Channel 1 Dimm 0 -------- DDR5 - LPDDR4 - LPDDR5 + 11 - Controller 1 Channel 1 Dimm 1 -------- DDR5 2DPC + 12 - Controller 1 Channel 2 Dimm 0 --------------- LPDDR4 - LPDDR5 + 14 - Controller 1 Channel 3 Dimm 0 --------------- LPDDR4 - LPDDR5 + **/ + UINT8 SpdAddressTable[MEM_CFG_MAX_SOCKETS]; + VOID *S3DataPtr; ///< Offset 44 Memory data save pointer for S3 resume. The memory space should be allocated and filled with proper S3 resume data on a resume path + UINT32 SmbusBar; ///< Offset 48 Address of System Agent SMBUS BAR: <b>0xEFA0</b> + /** + Offset 52 Size of TSEG in bytes. (Must be power of 2) + <b>0x400000</b>: 4MB for Release build (When IED enabled, it will be 8MB) + 0x1000000 : 16MB for Debug build (Regardless IED enabled or disabled) + **/ + UINT32 TsegSize; + /** + Offset 56 + <b>(Test)</b> Size of IED region in bytes. + <b>0</b> : IED Disabled (no memory occupied) + 0x400000 : 4MB SMM memory occupied by IED (Part of TSEG) + <b>Note: Enabling IED may also enlarge TsegSize together.</b> + @deprecated + **/ + UINT32 IedSize; + UINT32 SkipExtGfxScan:1; ///< <b>(Test)</b> OFfset 60:0 :1=Skip External Gfx Device Scan; <b>0=Scan for external graphics devices</b>. Set this policy to skip External Graphics card scanning if the platform uses Internal Graphics only. + UINT32 BdatEnable:1; ///< Offset 60:1 :This field enables the generation of the BIOS DATA ACPI Tables: <b>0=FALSE</b>, 1=TRUE. + UINT32 TxtImplemented:1; ///< OFfset 60:2 :This field currently is used to tell MRC if it should run after TXT initializatoin completed: <b>0=Run without waiting for TXT</b>, 1=Run after TXT initialization by callback + /** + Offset 60:3 : + <b>(Test)</b> Scan External Discrete Graphics Devices for Legacy Only VGA OpROMs + + When enabled, if the primary graphics device is an external discrete graphics device, Si will scan the + graphics device for legacy only VGA OpROMs. + + This is intended to ease the implementation of a BIOS feature to automatically enable CSM if the Primary Gfx device + only supports Legacy VBIOS (No UEFI GOP Present). Otherwise disabling CSM won't result in no video being displayed. + This is useful for platforms that implement PCIe slots that allow the end user to install an arbitrary Gfx device. + + This setting will only take effect if SkipExtGfxScan == 0. It is ignored otherwise. + + - Disabled (0x0) : Don't Scan for Legacy Only VGA OpROMs (Default) + - <b>Enabled</b> (0x1) : Scan External Gfx for Legacy Only VGA OpROM + **/ + UINT32 ScanExtGfxForLegacyOpRom:1; + UINT32 RsvdBits0 :28; ///< Offset 60:4 :Reserved for future use + UINT8 UserBd; ///< Offset 64 <b>0=Mobile/Mobile Halo</b>, 1=Desktop/DT Halo, 2=Desktop 2DPC DDR5, 5=ULT/ULX/Mobile Halo Type3, 6=ULT/ULX/Mobile Halo Type4, 8=UP Server + UINT8 LockPTMregs; ///< <b>(Test)</b> Offset 65 Lock PCU Thermal Management registers: 0=FALSE, <b>1=TRUE</b> + UINT8 BdatTestType; ///< Offset 66 When BdatEnable is set to TRUE, this option selects the type of data which will be populated in the BIOS Data ACPI Tables: <b>0=RMT</b>, 1=RMT Per Bit, 2=Margin 2D. + UINT8 CridEnable; ///< Offset 67 For Platforms supporting Intel(R) SIPP, this policy is use control enable/disable Compatibility Revision ID (CRID) feature: <b>0=FALSE</b>, 1=TRUE + UINT32 AcpiReservedMemorySize; ///< Offset 68 The Size of a Reserved memory buffer allocated in previous boot for S3 resume used. Originally it is retrieved from AcpiVariableCompatibility variable. + UINT64 AcpiReservedMemoryBase; ///< Offset 80 The Base address of a Reserved memory buffer allocated in previous boot for S3 resume used. Originally it is retrieved from AcpiVariableCompatibility variable. + UINT64 SystemMemoryLength; ///< Offset 88 Total system memory length from previous boot, this is required for S3 resume. Originally it is retrieved from AcpiVariableCompatibility variable. + + UINT8 WrcFeatureEnable; ///< Offset 96: Enable/Disable WRC (Write Cache) feature of IOP. When enabled, supports IO devices allocating onto the ring and into LLC. + UINT8 FirstDimmBitMask; ///< Offset 97: Defines which DIMM should be populated first on a 2DPC board. + ///< 4 bit mask: Bit[0]: MC0 DIMM0, Bit[1]: MC0 DIMM1, Bit[2]: MC1 DIMM0, Bit[3]: MC1 DIMM1. + ///< For each MC, the first DIMM to be populated should be set to '1'. + ///< Note: this mask is only for non-ECC DIMM. + UINT8 FirstDimmBitMaskEcc; ///< Offset 98: Defines which ECC DIMM should be populated first on a 2DPC board. + ///< 4 bit mask: Bit[0]: MC0 DIMM0, Bit[1]: MC0 DIMM1, Bit[2]: MC1 DIMM0, Bit[3]: MC1 DIMM1. + ///< For each MC, the first DIMM to be populated should be set to '1'. + ///< For example, if one MC is T-topology, there is no special population rule, can put it as 11 for this MC and it means either D0 or D1 can be + ///< be populated firstly. + ///< Note: this mask is only for ECC DIMM, not for non-ECC DIMM. + + UINT8 DisableMrcRetrainingOnRtcPowerLoss; ///< Offset 99: Enable/Disable DisableMrcRetrainingOnRtcPowerLoss. + + + // Since the biggest element is UINT64, this structure should be aligned with 64 bits. + UINT8 Rsvd[4]; ///< Reserved for config block alignment. + UINT8 ResizableBarSupport; + + UINT8 Rsrvd1[7]; +} SA_MISC_PEI_PREMEM_CONFIG; +#pragma pack(pop) + +#endif // _SA_MISC_PEI_PREMEM_CONFIG_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/DxeSaPolicyLib.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/DxeSaPolicyLib.h new file mode 100644 index 0000000000..5f5eeeeb63 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/DxeSaPolicyLib.h @@ -0,0 +1,58 @@ +/** @file + Prototype of the DxeSaPolicyLib library. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _DXE_SA_POLICY_LIB_H_ +#define _DXE_SA_POLICY_LIB_H_ + +#include <Protocol/SaPolicy.h> + +/** + This function prints the DXE phase policy. + + @param[in] SaPolicy - SA DXE Policy protocol +**/ +VOID +SaPrintPolicyProtocol ( + IN SA_POLICY_PROTOCOL *SaPolicy + ) +; + +/** + CreateSaDxeConfigBlocks generates the config blocksg of SA DXE Policy. + It allocates and zero out buffer, and fills in the Intel default settings. + + @param[out] SaPolicy The pointer to get SA Policy Protocol instance + + @retval EFI_SUCCESS The policy default is initialized. + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create buffer +**/ +EFI_STATUS +EFIAPI +CreateSaDxeConfigBlocks( + IN OUT SA_POLICY_PROTOCOL **SaPolicy +); + +/** + SaInstallPolicyProtocol installs SA Policy. + While installed, RC assumes the Policy is ready and finalized. So please update and override + any setting before calling this function. + + @param[in] ImageHandle Image handle of this driver. + @param[in] SaPolicy The pointer to SA Policy Protocol instance + + @retval EFI_SUCCESS The policy is installed. + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create buffer + +**/ +EFI_STATUS +EFIAPI +SaInstallPolicyProtocol ( + IN EFI_HANDLE ImageHandle, + IN SA_POLICY_PROTOCOL *SaPolicy + ) +; + +#endif // _DXE_SA_POLICY_LIB_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/PeiSaPolicyLib.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/PeiSaPolicyLib.h new file mode 100644 index 0000000000..8b941b4420 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/PeiSaPolicyLib.h @@ -0,0 +1,13 @@ +/** @file + Prototype of the PeiSaPolicy library. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PEI_SA_POLICY_LIB_H_ +#define _PEI_SA_POLICY_LIB_H_ + +#include <Ppi/SiPolicy.h> +#include <Library/ConfigBlockLib.h> + +#endif // _PEI_SA_POLICY_LIBRARY_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/MemInfoHob.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/MemInfoHob.h new file mode 100644 index 0000000000..d6c670d4ce --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/MemInfoHob.h @@ -0,0 +1,220 @@ +/** @file + This file contains definitions required for creation of + Memory S3 Save data, Memory Info data and Memory Platform + data hobs. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _MEM_INFO_HOB_H_ +#define _MEM_INFO_HOB_H_ + + +#pragma pack (push, 1) + +extern EFI_GUID gSiMemoryS3DataGuid; +extern EFI_GUID gSiMemoryInfoDataGuid; +extern EFI_GUID gSiMemoryPlatformDataGuid; + +#define MAX_NODE 2 +#define MAX_CH 4 +#define MAX_DIMM 2 +#define HOB_MAX_SAGV_POINTS 4 + +/// +/// Defines taken from MRC so avoid having to include MrcInterface.h +/// + +// +// Matches MAX_SPD_SAVE define in MRC +// +#ifndef MAX_SPD_SAVE +#define MAX_SPD_SAVE 29 +#endif + +// +// MRC version description. +// +typedef struct { + UINT8 Major; ///< Major version number + UINT8 Minor; ///< Minor version number + UINT8 Rev; ///< Revision number + UINT8 Build; ///< Build number +} SiMrcVersion; + +// +// Matches MrcChannelSts enum in MRC +// +#ifndef CHANNEL_NOT_PRESENT +#define CHANNEL_NOT_PRESENT 0 // There is no channel present on the controller. +#endif +#ifndef CHANNEL_DISABLED +#define CHANNEL_DISABLED 1 // There is a channel present but it is disabled. +#endif +#ifndef CHANNEL_PRESENT +#define CHANNEL_PRESENT 2 // There is a channel present and it is enabled. +#endif + +// +// Matches MrcDimmSts enum in MRC +// +#ifndef DIMM_ENABLED +#define DIMM_ENABLED 0 // DIMM/rank Pair is enabled, presence will be detected. +#endif +#ifndef DIMM_DISABLED +#define DIMM_DISABLED 1 // DIMM/rank Pair is disabled, regardless of presence. +#endif +#ifndef DIMM_PRESENT +#define DIMM_PRESENT 2 // There is a DIMM present in the slot/rank pair and it will be used. +#endif +#ifndef DIMM_NOT_PRESENT +#define DIMM_NOT_PRESENT 3 // There is no DIMM present in the slot/rank pair. +#endif + +// +// Matches MrcDdrType enum in MRC +// +#ifndef MRC_DDR_TYPE_DDR5 +#define MRC_DDR_TYPE_DDR5 1 +#endif +#ifndef MRC_DDR_TYPE_LPDDR5 +#define MRC_DDR_TYPE_LPDDR5 2 +#endif +#ifndef MRC_DDR_TYPE_LPDDR4 +#define MRC_DDR_TYPE_LPDDR4 3 +#endif +#ifndef MRC_DDR_TYPE_UNKNOWN +#define MRC_DDR_TYPE_UNKNOWN 4 +#endif + +#define MAX_PROFILE_NUM 7 // number of memory profiles supported +#define MAX_XMP_PROFILE_NUM 5 // number of XMP profiles supported + +// +// DIMM timings +// +typedef struct { + UINT32 tCK; ///< Memory cycle time, in femtoseconds. + UINT16 NMode; ///< Number of tCK cycles for the channel DIMM's command rate mode. + UINT16 tCL; ///< Number of tCK cycles for the channel DIMM's CAS latency. + UINT16 tCWL; ///< Number of tCK cycles for the channel DIMM's minimum CAS write latency time. + UINT16 tFAW; ///< Number of tCK cycles for the channel DIMM's minimum four activate window delay time. + UINT16 tRAS; ///< Number of tCK cycles for the channel DIMM's minimum active to precharge delay time. + UINT16 tRCDtRP; ///< Number of tCK cycles for the channel DIMM's minimum RAS# to CAS# delay time and Row Precharge delay time. + UINT16 tREFI; ///< Number of tCK cycles for the channel DIMM's minimum Average Periodic Refresh Interval. + UINT16 tRFC; ///< Number of tCK cycles for the channel DIMM's minimum refresh recovery delay time. + UINT16 tRFCpb; ///< Number of tCK cycles for the channel DIMM's minimum per bank refresh recovery delay time. + UINT16 tRFC2; ///< Number of tCK cycles for the channel DIMM's minimum refresh recovery delay time. + UINT16 tRFC4; ///< Number of tCK cycles for the channel DIMM's minimum refresh recovery delay time. + UINT16 tRPab; ///< Number of tCK cycles for the channel DIMM's minimum row precharge delay time for all banks. + UINT16 tRRD; ///< Number of tCK cycles for the channel DIMM's minimum row active to row active delay time. + UINT16 tRRD_L; ///< Number of tCK cycles for the channel DIMM's minimum row active to row active delay time for same bank groups. + UINT16 tRRD_S; ///< Number of tCK cycles for the channel DIMM's minimum row active to row active delay time for different bank groups. + UINT16 tRTP; ///< Number of tCK cycles for the channel DIMM's minimum internal read to precharge command delay time. + UINT16 tWR; ///< Number of tCK cycles for the channel DIMM's minimum write recovery time. + UINT16 tWTR; ///< Number of tCK cycles for the channel DIMM's minimum internal write to read command delay time. + UINT16 tWTR_L; ///< Number of tCK cycles for the channel DIMM's minimum internal write to read command delay time for same bank groups. + UINT16 tWTR_S; ///< Number of tCK cycles for the channel DIMM's minimum internal write to read command delay time for different bank groups. + UINT16 tCCD_L; ///< Number of tCK cycles for the channel DIMM's minimum CAS-to-CAS delay for same bank group. +} MRC_CH_TIMING; + +typedef struct { + UINT16 tRDPRE; ///< Read CAS to Precharge cmd delay +} MRC_IP_TIMING; + +/// +/// Memory SMBIOS & OC Memory Data Hob +/// +typedef struct { + UINT8 Status; ///< See MrcDimmStatus for the definition of this field. + UINT8 DimmId; + UINT32 DimmCapacity; ///< DIMM size in MBytes. + UINT16 MfgId; + UINT8 ModulePartNum[20]; ///< Module part number for DDR3 is 18 bytes however for DRR4 20 bytes as per JEDEC Spec, so reserving 20 bytes + UINT8 RankInDimm; ///< The number of ranks in this DIMM. + UINT8 SpdDramDeviceType; ///< Save SPD DramDeviceType information needed for SMBIOS structure creation. + UINT8 SpdModuleType; ///< Save SPD ModuleType information needed for SMBIOS structure creation. + UINT8 SpdModuleMemoryBusWidth; ///< Save SPD ModuleMemoryBusWidth information needed for SMBIOS structure creation. + UINT8 SpdSave[MAX_SPD_SAVE]; ///< Save SPD Manufacturing information needed for SMBIOS structure creation. + UINT16 Speed; ///< The maximum capable speed of the device, in MHz + UINT8 MdSocket; ///< MdSocket: 0 = Memory Down, 1 = Socketed. Needed for SMBIOS structure creation. +} DIMM_INFO; + +typedef struct { + UINT8 Status; ///< Indicates whether this channel should be used. + UINT8 ChannelId; + UINT8 DimmCount; ///< Number of valid DIMMs that exist in the channel. + MRC_CH_TIMING Timing[MAX_PROFILE_NUM]; ///< The channel timing values. + DIMM_INFO DimmInfo[MAX_DIMM]; ///< Save the DIMM output characteristics. +} CHANNEL_INFO; + +typedef struct { + UINT8 Status; ///< Indicates whether this controller should be used. + UINT16 DeviceId; ///< The PCI device id of this memory controller. + UINT8 RevisionId; ///< The PCI revision id of this memory controller. + UINT8 ChannelCount; ///< Number of valid channels that exist on the controller. + CHANNEL_INFO ChannelInfo[MAX_CH]; ///< The following are channel level definitions. +} CONTROLLER_INFO; + +/// This data structure contains per-SaGv timing values that are considered output by the MRC. +typedef struct { + UINT32 DataRate; ///< The memory rate for the current SaGv Point in units of MT/s + MRC_CH_TIMING JedecTiming; ///< Timings used for this entry's corresponding SaGv Point - derived from JEDEC SPD spec + MRC_IP_TIMING IpTiming; ///< Timings used for this entry's corresponding SaGv Point - IP specific +} HOB_SAGV_TIMING_OUT; + +/// This data structure contains SAGV config values that are considered output by the MRC. +typedef struct { + UINT32 NumSaGvPointsEnabled; ///< Count of the total number of SAGV Points enabled. + UINT32 SaGvPointMask; ///< Bit mask where each bit indicates an enabled SAGV point. + HOB_SAGV_TIMING_OUT SaGvTiming[HOB_MAX_SAGV_POINTS]; +} HOB_SAGV_INFO; + +typedef struct { + UINT8 Revision; + UINT16 DataWidth; ///< Data width, in bits, of this memory device + /** As defined in SMBIOS 3.0 spec + Section 7.18.2 and Table 75 + **/ + UINT8 MemoryType; ///< DDR type: DDR3, DDR4, or LPDDR3 + UINT16 MaximumMemoryClockSpeed;///< The maximum capable speed of the device, in megahertz (MHz) + UINT16 ConfiguredMemoryClockSpeed; ///< The configured clock speed to the memory device, in megahertz (MHz) + /** As defined in SMBIOS 3.0 spec + Section 7.17.3 and Table 72 + **/ + UINT8 ErrorCorrectionType; + + SiMrcVersion Version; + BOOLEAN EccSupport; + UINT8 MemoryProfile; + UINT8 IsDMBRunning; ///< Deprecated. + UINT32 TotalPhysicalMemorySize; + UINT32 DefaultXmptCK[MAX_XMP_PROFILE_NUM];///< Stores the tCK value read from SPD XMP profiles if they exist. + /// + /// Set of bit flags showing XMP and User Profile capability status for the DIMMs detected in system. For each bit, 1 is supported, 0 is unsupported. + /// Bit 0: XMP Profile 1 capability status + /// Bit 1: XMP Profile 2 capability status + /// Bit 2: XMP Profile 3 capability status + /// Bit 3: User Profile 4 capability status + /// Bit 4: User Profile 5 capability status + /// + UINT8 XmpProfileEnable; + UINT8 XmpConfigWarning; ///< If XMP capable DIMMs config support only 1DPC, but 2DPC is installed + UINT8 Ratio; ///< DDR Frequency Ratio, Max Value 255 + UINT8 RefClk; + UINT32 VddVoltage[MAX_PROFILE_NUM]; + UINT32 VddqVoltage[MAX_PROFILE_NUM]; + UINT32 VppVoltage[MAX_PROFILE_NUM]; + CONTROLLER_INFO Controller[MAX_NODE]; + UINT16 Ratio_UINT16; ///< DDR Frequency Ratio, used for programs that require ratios higher then 255 + UINT32 NumPopulatedChannels; ///< Total number of memory channels populated + HOB_SAGV_INFO SagvConfigInfo; ///< This data structure contains SAGV config values that are considered output by the MRC. + UINT16 TotalMemWidth; ///< Total Memory Width in bits from all populated channels + BOOLEAN MemorySpeedReducedWrongDimmSlot; ///< Can be used by OEM BIOS to display a warning on the screen that DDR speed was reduced due to wrong DIMM population + BOOLEAN MemorySpeedReducedMixedConfig; ///< Can be used by OEM BIOS to display a warning on the screen that DDR speed was reduced due to mixed DIMM config + BOOLEAN DynamicMemoryBoostTrainingFailed; ///< TRUE if Dynamic Memory Boost failed to train and was force disabled on the last full training boot. FALSE otherwise. +} MEMORY_INFO_DATA_HOB; + +#pragma pack (pop) + +#endif // _MEM_INFO_HOB_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Protocol/SaPolicy.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Protocol/SaPolicy.h new file mode 100644 index 0000000000..cc258debe1 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Protocol/SaPolicy.h @@ -0,0 +1,54 @@ +/** @file + Interface definition details between System Agent and platform drivers during DXE phase. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _SA_POLICY_H_ +#define _SA_POLICY_H_ + +#include <ConfigBlock.h> +#include <Library/ConfigBlockLib.h> +#include <GraphicsConfig.h> +#include <ConfigBlock/MemoryDxeConfig.h> + +/// +/// Extern the GUID for protocol users. +/// +extern EFI_GUID gSaPolicyProtocolGuid; +extern EFI_GUID gGraphicsDxeConfigGuid; +extern EFI_GUID gMemoryDxeConfigGuid; + +/** + Don't change the original SA_POLICY_PROTOCOL_REVISION macro, external + modules maybe have consumed this macro in their source code. Directly + update the SA_POLICY_PROTOCOL_REVISION version number may cause those + external modules to auto mark themselves wrong version info. + Always create new version macro for new Policy protocol interface. +**/ +#define SA_POLICY_PROTOCOL_REVISION 1 + + + + +/** + SA DXE Policy + + The SA_POLICY_PROTOCOL producer drvier is recommended to + set all the SA_POLICY_PROTOCOL size buffer zero before init any member parameter, + this clear step can make sure no random value for those unknow new version parameters. + + Make sure to update the Revision if any change to the protocol, including the existing + internal structure definations.\n + Note: Here revision will be bumped up when adding/removing any config block under this structure.\n + <b>Revision 1</b>: + - Initial version. +**/ +typedef struct { + CONFIG_BLOCK_TABLE_HEADER TableHeader; ///< Offset 0-31 +/* + Individual Config Block Structures are added here in memory as part of AddConfigBlock() +*/ +} SA_POLICY_PROTOCOL; + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/SaDataHob.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/SaDataHob.h new file mode 100644 index 0000000000..bded1851f4 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/SaDataHob.h @@ -0,0 +1,28 @@ +/** @file + The GUID definition for SaDataHob + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _SA_DATA_HOB_H_ +#define _SA_DATA_HOB_H_ + +#include <Base.h> +#include <CpuPcieInfo.h> +#include <Library/PcdLib.h> + +extern EFI_GUID gSaDataHobGuid; +#pragma pack (push,1) + +/// +/// System Agent Data Hob +/// +typedef struct { + EFI_HOB_GUID_TYPE EfiHobGuidType; ///< GUID Hob type structure for gSaDataHobGuid + UINT8 PrimaryDisplay; + BOOLEAN ResizableBarSupport; ///< Resizable BAR Support + UINT8 Rsvd1[2]; ///< Reserved for future use +} SA_DATA_HOB; + +#pragma pack (pop) +#endif -- 2.36.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107573): https://edk2.groups.io/g/devel/message/107573 Mute This Topic: https://groups.io/mt/100551005/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [edk2-devel] [PATCH v2 6/7] AlderlakeSiliconPkg/SystemAgent: Add include headers 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 6/7] AlderlakeSiliconPkg/SystemAgent: Add include headers Saloni Kasbekar @ 2023-08-16 2:45 ` Chuang, Rosen 0 siblings, 0 replies; 14+ messages in thread From: Chuang, Rosen @ 2023-08-16 2:45 UTC (permalink / raw) To: Kasbekar, Saloni, devel@edk2.groups.io Cc: Chaganty, Rangasai V, Desimone, Nathaniel L, Oram, Isaac W Reviewed-by: Rosen Chuang < rosen.chuang@intel.com> -----Original Message----- From: Kasbekar, Saloni <saloni.kasbekar@intel.com> Sent: Saturday, August 5, 2023 1:38 AM To: devel@edk2.groups.io Cc: Kasbekar, Saloni <saloni.kasbekar@intel.com>; Chaganty, Rangasai V <rangasai.v.chaganty@intel.com>; Desimone, Nathaniel L <nathaniel.l.desimone@intel.com>; Oram, Isaac W <isaac.w.oram@intel.com>; Chuang, Rosen <rosen.chuang@intel.com> Subject: [PATCH v2 6/7] AlderlakeSiliconPkg/SystemAgent: Add include headers Adds the following header files: * SystemAgent/Include Cc: Sai Chaganty <rangasai.v.chaganty@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Isaac Oram <isaac.w.oram@intel.com> Cc: Rosen Chuang <rosen.chuang@intel.com> Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com> --- .../Include/ConfigBlock/MemoryDxeConfig.h | 126 ++++++++++ .../ConfigBlock/SaMiscPeiPreMemConfig.h | 112 +++++++++ .../Include/Library/DxeSaPolicyLib.h | 58 +++++ .../Include/Library/PeiSaPolicyLib.h | 13 ++ .../SystemAgent/Include/MemInfoHob.h | 220 ++++++++++++++++++ .../SystemAgent/Include/Protocol/SaPolicy.h | 54 +++++ .../SystemAgent/Include/SaDataHob.h | 28 +++ 7 files changed, 611 insertions(+) create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/MemoryDxeConfig.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/SaMiscPeiPreMemConfig.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/DxeSaPolicyLib.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/PeiSaPolicyLib.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/MemInfoHob.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Protocol/SaPolicy.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/SaDataHob.h diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/MemoryDxeConfig.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/MemoryDxeConfig.h new file mode 100644 index 0000000000..eca0c2f1ba --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/ +++ MemoryDxeConfig.h @@ -0,0 +1,126 @@ +/** @file + Memory DXE Policy definitions + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_MEMORY_DXE_CONFIG_H_ #define _MEMORY_DXE_CONFIG_H_ + +#pragma pack(push, 1) + +/** + Making any setup structure change after code frozen will need to +maintain backward compatibility, bump up structure revision and update +below history table\n + <b>Revision 1</b>: - Initial version. +**/ +#define MEMORY_DXE_CONFIG_REVISION 2 + +typedef struct _MEMORY_DXE_CONFIG MEMORY_DXE_CONFIG; + +/** + Retrieves the OEM custom string for the SMBIOS Type 17 Table DeviceLocator field. + Implementation of this function is optional, if this function pointer +is NULL then + the reference implementation of DeviceLocator will be used. + + @param[in] This A pointer to this instance of MEMORY_DXE_CONFIG. + @param[in] Controller Desired Controller to get a DeviceLocator string for. + @param[in] Dimm Desired DIMM to get a DeviceLocator string for. + @param[in] MdSocket 0 = Memory Down, 1 = Socketed. + + @retval The DeviceLocator string + @retval NULL If the return value is NULL, the default value will be used. +**/ +typedef +CHAR8* +(EFIAPI *MEMORY_DXE_CONFIG_GET_DEVICE_LOCATOR_STRING)( + IN CONST MEMORY_DXE_CONFIG *This, + IN UINT8 Controller, + IN UINT8 Dimm, + IN UINT8 MdSocket + ); + +/** + Retrieves the OEM custom string for the SMBIOS Type 17 Table BankLocator field. + Implementation of this function is optional, if this function pointer +is NULL then + the reference implementation of DeviceLocator will be used. + + @param[in] This A pointer to this instance of MEMORY_DXE_CONFIG. + @param[in] Controller Desired Controller to get a BankLocator string for. + @param[in] Dimm Desired DIMM to get a BankLocator string for. + @param[in] MdSocket 0 = Memory Down, 1 = Socketed. + + @retval The BankLocator string + @retval NULL If the return value is NULL, the default value will be used. +**/ +typedef +CHAR8* +(EFIAPI *MEMORY_DXE_CONFIG_GET_BANK_LOCATOR_STRING)( + IN CONST MEMORY_DXE_CONFIG *This, + IN UINT8 Controller, + IN UINT8 Dimm, + IN UINT8 MdSocket + ); + +/** + The Memory Configuration includes DIMM SPD address Map and DIMM Slot Mechanical present bit map. + The data elements should be initialized by a Platform Module.\n + <b>Revision 1</b>: + - Initial version. +**/ +struct _MEMORY_DXE_CONFIG { + CONFIG_BLOCK_HEADER Header; ///< Offset 0-27: Config Block Header +/** + Offset 28: + Dimm SPD address + Only Server support 2 channels * 3 slots per channel = 6 sockets +totally + The Desktop and mobile only support 2 channels * 2 slots per channel += 4 sockets totally + So there is mapping rule here for Desktop and mobile that there are no more 4 DIMMS totally in a system: + Channel A/ Slot 0 --> Dimm 0 --> SpdAddressTable[0] + Channel A/ Slot 1 --> Dimm 1 --> SpdAddressTable[1] + Channel B/ Slot 0 --> Dimm 2 --> SpdAddressTable[2] + Channel B/ Slot 1 --> Dimm 3 --> SpdAddressTable[3] + Refer to SmbiosMemory.c for use + If change the mapping rule, please update the Revision number. +**/ + UINT8 *SpdAddressTable; +/** + Offset 36: + ChannelASlotMap and ChannelBSlotMap change to use SlotMap as the DIMM slot map solution. + Reserve 2-bytes in order to comply with 4-bytes alignment and keep the offset of other members. +**/ + UINT8 ChannelASlotMap; + UINT8 ChannelBSlotMap; +/** + Offset 38: + MRC execution time measurement: <b>0=Disable</b>, 1=Enable **/ + UINT8 MrcTimeMeasure; +/** + Offset 39: + Fast boot: 0=Disable, <b>1=Enable</b> **/ + UINT8 MrcFastBoot; +/** + Offset 40: + Retrieves the OEM custom string for the SMBIOS Type 17 Table DeviceLocator field. +**/ + MEMORY_DXE_CONFIG_GET_DEVICE_LOCATOR_STRING GetDeviceLocatorString; +/** + Offset 48: + Retrieves the OEM custom string for the SMBIOS Type 17 Table BankLocator field. +**/ + MEMORY_DXE_CONFIG_GET_BANK_LOCATOR_STRING GetBankLocatorString; +/** + Offset 56: + Each DIMM Slot Mechanical present bit map, bit 0 -> DIMM 0, bit 1 -> DIMM1, ... + if the bit is 1, the related DIMM slot is present. + E.g. if memory controller 0 channel 3 has 2 DIMMs, SlotMap[0][3] = +0x03; + E.g. if memory controller 1 channel 2 has only 1 DIMMs, +SlotMap[1][2] = 0x0; **/ + UINT8 **SlotMap; +}; +#pragma pack(pop) + +#endif // _MEMORY_DXE_CONFIG_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/SaMiscPeiPreMemConfig.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/SaMiscPeiPreMemConfig.h new file mode 100644 index 0000000000..cb75696b61 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/ConfigBlock/ +++ SaMiscPeiPreMemConfig.h @@ -0,0 +1,112 @@ +/** @file + Policy details for miscellaneous configuration in System Agent + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_SA_MISC_PEI_PREMEM_CONFIG_H_ #define _SA_MISC_PEI_PREMEM_CONFIG_H_ + +#pragma pack(push, 1) + +#ifndef MEM_CFG_MAX_SOCKETS +#define MEM_CFG_MAX_SOCKETS 16 +#endif + +#define SA_MISC_PEI_PREMEM_CONFIG_REVISION 1 + +/** + This configuration block is to configure SA Miscellaneous variables +during PEI Pre-Mem phase like programming + different System Agent BARs, TsegSize, MmioSize required etc. + <b>Revision 1</b>: + - Initial version. +**/ +typedef struct { + CONFIG_BLOCK_HEADER Header; ///< Offset 0-27 Config Block Header + /** + Offset 28 Memory DIMMs' SPD address for reading SPD data. + TGL Mapping + 0 - Controller 0 Channel 0 Dimm 0 - DDR4 - DDR5 - LPDDR4 - LPDDR5 + 1 - Controller 0 Channel 0 Dimm 1 - DDR4 + 2 - Controller 0 Channel 1 Dimm 0 -------- DDR5 - LPDDR4 - LPDDR5 + 3 - Controller 0 Channel 1 Dimm 1 -------- DDR5 2DPC + 4 - Controller 0 Channel 2 Dimm 0 --------------- LPDDR4 - LPDDR5 + 6 - Controller 0 Channel 3 Dimm 0 --------------- LPDDR4 - LPDDR5 + 8 - Controller 1 Channel 0 Dimm 0 - DDR4 - DDR5 - LPDDR4 - LPDDR5 + 9 - Controller 1 Channel 0 Dimm 1 - DDR4 + 10 - Controller 1 Channel 1 Dimm 0 -------- DDR5 - LPDDR4 - LPDDR5 + 11 - Controller 1 Channel 1 Dimm 1 -------- DDR5 2DPC + 12 - Controller 1 Channel 2 Dimm 0 --------------- LPDDR4 - LPDDR5 + 14 - Controller 1 Channel 3 Dimm 0 --------------- LPDDR4 - LPDDR5 + **/ + UINT8 SpdAddressTable[MEM_CFG_MAX_SOCKETS]; + VOID *S3DataPtr; ///< Offset 44 Memory data save pointer for S3 resume. The memory space should be allocated and filled with proper S3 resume data on a resume path + UINT32 SmbusBar; ///< Offset 48 Address of System Agent SMBUS BAR: <b>0xEFA0</b> + /** + Offset 52 Size of TSEG in bytes. (Must be power of 2) + <b>0x400000</b>: 4MB for Release build (When IED enabled, it will be 8MB) + 0x1000000 : 16MB for Debug build (Regardless IED enabled or disabled) + **/ + UINT32 TsegSize; + /** + Offset 56 + <b>(Test)</b> Size of IED region in bytes. + <b>0</b> : IED Disabled (no memory occupied) + 0x400000 : 4MB SMM memory occupied by IED (Part of TSEG) + <b>Note: Enabling IED may also enlarge TsegSize together.</b> + @deprecated + **/ + UINT32 IedSize; + UINT32 SkipExtGfxScan:1; ///< <b>(Test)</b> OFfset 60:0 :1=Skip External Gfx Device Scan; <b>0=Scan for external graphics devices</b>. Set this policy to skip External Graphics card scanning if the platform uses Internal Graphics only. + UINT32 BdatEnable:1; ///< Offset 60:1 :This field enables the generation of the BIOS DATA ACPI Tables: <b>0=FALSE</b>, 1=TRUE. + UINT32 TxtImplemented:1; ///< OFfset 60:2 :This field currently is used to tell MRC if it should run after TXT initializatoin completed: <b>0=Run without waiting for TXT</b>, 1=Run after TXT initialization by callback + /** + Offset 60:3 : + <b>(Test)</b> Scan External Discrete Graphics Devices for Legacy +Only VGA OpROMs + + When enabled, if the primary graphics device is an external discrete graphics device, Si will scan the + graphics device for legacy only VGA OpROMs. + + This is intended to ease the implementation of a BIOS feature to automatically enable CSM if the Primary Gfx device + only supports Legacy VBIOS (No UEFI GOP Present). Otherwise disabling CSM won't result in no video being displayed. + This is useful for platforms that implement PCIe slots that allow the end user to install an arbitrary Gfx device. + + This setting will only take effect if SkipExtGfxScan == 0. It is ignored otherwise. + + - Disabled (0x0) : Don't Scan for Legacy Only VGA OpROMs (Default) + - <b>Enabled</b> (0x1) : Scan External Gfx for Legacy Only VGA + OpROM **/ + UINT32 ScanExtGfxForLegacyOpRom:1; + UINT32 RsvdBits0 :28; ///< Offset 60:4 :Reserved for future use + UINT8 UserBd; ///< Offset 64 <b>0=Mobile/Mobile Halo</b>, 1=Desktop/DT Halo, 2=Desktop 2DPC DDR5, 5=ULT/ULX/Mobile Halo Type3, 6=ULT/ULX/Mobile Halo Type4, 8=UP Server + UINT8 LockPTMregs; ///< <b>(Test)</b> Offset 65 Lock PCU Thermal Management registers: 0=FALSE, <b>1=TRUE</b> + UINT8 BdatTestType; ///< Offset 66 When BdatEnable is set to TRUE, this option selects the type of data which will be populated in the BIOS Data ACPI Tables: <b>0=RMT</b>, 1=RMT Per Bit, 2=Margin 2D. + UINT8 CridEnable; ///< Offset 67 For Platforms supporting Intel(R) SIPP, this policy is use control enable/disable Compatibility Revision ID (CRID) feature: <b>0=FALSE</b>, 1=TRUE + UINT32 AcpiReservedMemorySize; ///< Offset 68 The Size of a Reserved memory buffer allocated in previous boot for S3 resume used. Originally it is retrieved from AcpiVariableCompatibility variable. + UINT64 AcpiReservedMemoryBase; ///< Offset 80 The Base address of a Reserved memory buffer allocated in previous boot for S3 resume used. Originally it is retrieved from AcpiVariableCompatibility variable. + UINT64 SystemMemoryLength; ///< Offset 88 Total system memory length from previous boot, this is required for S3 resume. Originally it is retrieved from AcpiVariableCompatibility variable. + + UINT8 WrcFeatureEnable; ///< Offset 96: Enable/Disable WRC (Write Cache) feature of IOP. When enabled, supports IO devices allocating onto the ring and into LLC. + UINT8 FirstDimmBitMask; ///< Offset 97: Defines which DIMM should be populated first on a 2DPC board. + ///< 4 bit mask: Bit[0]: MC0 DIMM0, Bit[1]: MC0 DIMM1, Bit[2]: MC1 DIMM0, Bit[3]: MC1 DIMM1. + ///< For each MC, the first DIMM to be populated should be set to '1'. + ///< Note: this mask is only for non-ECC DIMM. + UINT8 FirstDimmBitMaskEcc; ///< Offset 98: Defines which ECC DIMM should be populated first on a 2DPC board. + ///< 4 bit mask: Bit[0]: MC0 DIMM0, Bit[1]: MC0 DIMM1, Bit[2]: MC1 DIMM0, Bit[3]: MC1 DIMM1. + ///< For each MC, the first DIMM to be populated should be set to '1'. + ///< For example, if one MC is T-topology, there is no special population rule, can put it as 11 for this MC and it means either D0 or D1 can be + ///< be populated firstly. + ///< Note: this mask is only for ECC DIMM, not for non-ECC DIMM. + + UINT8 DisableMrcRetrainingOnRtcPowerLoss; ///< Offset 99: Enable/Disable DisableMrcRetrainingOnRtcPowerLoss. + + + // Since the biggest element is UINT64, this structure should be aligned with 64 bits. + UINT8 Rsvd[4]; ///< Reserved for config block alignment. + UINT8 ResizableBarSupport; + + UINT8 Rsrvd1[7]; +} SA_MISC_PEI_PREMEM_CONFIG; +#pragma pack(pop) + +#endif // _SA_MISC_PEI_PREMEM_CONFIG_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/DxeSaPolicyLib.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/DxeSaPolicyLib.h new file mode 100644 index 0000000000..5f5eeeeb63 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/DxeS +++ aPolicyLib.h @@ -0,0 +1,58 @@ +/** @file + Prototype of the DxeSaPolicyLib library. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_DXE_SA_POLICY_LIB_H_ #define _DXE_SA_POLICY_LIB_H_ + +#include <Protocol/SaPolicy.h> + +/** + This function prints the DXE phase policy. + + @param[in] SaPolicy - SA DXE Policy protocol +**/ +VOID +SaPrintPolicyProtocol ( + IN SA_POLICY_PROTOCOL *SaPolicy + ) +; + +/** + CreateSaDxeConfigBlocks generates the config blocksg of SA DXE Policy. + It allocates and zero out buffer, and fills in the Intel default settings. + + @param[out] SaPolicy The pointer to get SA Policy Protocol instance + + @retval EFI_SUCCESS The policy default is initialized. + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create buffer +**/ +EFI_STATUS +EFIAPI +CreateSaDxeConfigBlocks( + IN OUT SA_POLICY_PROTOCOL **SaPolicy +); + +/** + SaInstallPolicyProtocol installs SA Policy. + While installed, RC assumes the Policy is ready and finalized. So +please update and override + any setting before calling this function. + + @param[in] ImageHandle Image handle of this driver. + @param[in] SaPolicy The pointer to SA Policy Protocol instance + + @retval EFI_SUCCESS The policy is installed. + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create buffer + +**/ +EFI_STATUS +EFIAPI +SaInstallPolicyProtocol ( + IN EFI_HANDLE ImageHandle, + IN SA_POLICY_PROTOCOL *SaPolicy + ) +; + +#endif // _DXE_SA_POLICY_LIB_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/PeiSaPolicyLib.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/PeiSaPolicyLib.h new file mode 100644 index 0000000000..8b941b4420 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Library/PeiS +++ aPolicyLib.h @@ -0,0 +1,13 @@ +/** @file + Prototype of the PeiSaPolicy library. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_PEI_SA_POLICY_LIB_H_ #define _PEI_SA_POLICY_LIB_H_ + +#include <Ppi/SiPolicy.h> +#include <Library/ConfigBlockLib.h> + +#endif // _PEI_SA_POLICY_LIBRARY_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/MemInfoHob.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/MemInfoHob.h new file mode 100644 index 0000000000..d6c670d4ce --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/MemInfoHob.h @@ -0,0 +1,220 @@ +/** @file + This file contains definitions required for creation of + Memory S3 Save data, Memory Info data and Memory Platform + data hobs. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_MEM_INFO_HOB_H_ #define _MEM_INFO_HOB_H_ + + +#pragma pack (push, 1) + +extern EFI_GUID gSiMemoryS3DataGuid; +extern EFI_GUID gSiMemoryInfoDataGuid; +extern EFI_GUID gSiMemoryPlatformDataGuid; + +#define MAX_NODE 2 +#define MAX_CH 4 +#define MAX_DIMM 2 +#define HOB_MAX_SAGV_POINTS 4 + +/// +/// Defines taken from MRC so avoid having to include MrcInterface.h +/// + +// +// Matches MAX_SPD_SAVE define in MRC +// +#ifndef MAX_SPD_SAVE +#define MAX_SPD_SAVE 29 +#endif + +// +// MRC version description. +// +typedef struct { + UINT8 Major; ///< Major version number + UINT8 Minor; ///< Minor version number + UINT8 Rev; ///< Revision number + UINT8 Build; ///< Build number +} SiMrcVersion; + +// +// Matches MrcChannelSts enum in MRC +// +#ifndef CHANNEL_NOT_PRESENT +#define CHANNEL_NOT_PRESENT 0 // There is no channel present on the controller. +#endif +#ifndef CHANNEL_DISABLED +#define CHANNEL_DISABLED 1 // There is a channel present but it is disabled. +#endif +#ifndef CHANNEL_PRESENT +#define CHANNEL_PRESENT 2 // There is a channel present and it is enabled. +#endif + +// +// Matches MrcDimmSts enum in MRC +// +#ifndef DIMM_ENABLED +#define DIMM_ENABLED 0 // DIMM/rank Pair is enabled, presence will be detected. +#endif +#ifndef DIMM_DISABLED +#define DIMM_DISABLED 1 // DIMM/rank Pair is disabled, regardless of presence. +#endif +#ifndef DIMM_PRESENT +#define DIMM_PRESENT 2 // There is a DIMM present in the slot/rank pair and it will be used. +#endif +#ifndef DIMM_NOT_PRESENT +#define DIMM_NOT_PRESENT 3 // There is no DIMM present in the slot/rank pair. +#endif + +// +// Matches MrcDdrType enum in MRC +// +#ifndef MRC_DDR_TYPE_DDR5 +#define MRC_DDR_TYPE_DDR5 1 +#endif +#ifndef MRC_DDR_TYPE_LPDDR5 +#define MRC_DDR_TYPE_LPDDR5 2 +#endif +#ifndef MRC_DDR_TYPE_LPDDR4 +#define MRC_DDR_TYPE_LPDDR4 3 +#endif +#ifndef MRC_DDR_TYPE_UNKNOWN +#define MRC_DDR_TYPE_UNKNOWN 4 +#endif + +#define MAX_PROFILE_NUM 7 // number of memory profiles supported +#define MAX_XMP_PROFILE_NUM 5 // number of XMP profiles supported + +// +// DIMM timings +// +typedef struct { + UINT32 tCK; ///< Memory cycle time, in femtoseconds. + UINT16 NMode; ///< Number of tCK cycles for the channel DIMM's command rate mode. + UINT16 tCL; ///< Number of tCK cycles for the channel DIMM's CAS latency. + UINT16 tCWL; ///< Number of tCK cycles for the channel DIMM's minimum CAS write latency time. + UINT16 tFAW; ///< Number of tCK cycles for the channel DIMM's minimum four activate window delay time. + UINT16 tRAS; ///< Number of tCK cycles for the channel DIMM's minimum active to precharge delay time. + UINT16 tRCDtRP; ///< Number of tCK cycles for the channel DIMM's minimum RAS# to CAS# delay time and Row Precharge delay time. + UINT16 tREFI; ///< Number of tCK cycles for the channel DIMM's minimum Average Periodic Refresh Interval. + UINT16 tRFC; ///< Number of tCK cycles for the channel DIMM's minimum refresh recovery delay time. + UINT16 tRFCpb; ///< Number of tCK cycles for the channel DIMM's minimum per bank refresh recovery delay time. + UINT16 tRFC2; ///< Number of tCK cycles for the channel DIMM's minimum refresh recovery delay time. + UINT16 tRFC4; ///< Number of tCK cycles for the channel DIMM's minimum refresh recovery delay time. + UINT16 tRPab; ///< Number of tCK cycles for the channel DIMM's minimum row precharge delay time for all banks. + UINT16 tRRD; ///< Number of tCK cycles for the channel DIMM's minimum row active to row active delay time. + UINT16 tRRD_L; ///< Number of tCK cycles for the channel DIMM's minimum row active to row active delay time for same bank groups. + UINT16 tRRD_S; ///< Number of tCK cycles for the channel DIMM's minimum row active to row active delay time for different bank groups. + UINT16 tRTP; ///< Number of tCK cycles for the channel DIMM's minimum internal read to precharge command delay time. + UINT16 tWR; ///< Number of tCK cycles for the channel DIMM's minimum write recovery time. + UINT16 tWTR; ///< Number of tCK cycles for the channel DIMM's minimum internal write to read command delay time. + UINT16 tWTR_L; ///< Number of tCK cycles for the channel DIMM's minimum internal write to read command delay time for same bank groups. + UINT16 tWTR_S; ///< Number of tCK cycles for the channel DIMM's minimum internal write to read command delay time for different bank groups. + UINT16 tCCD_L; ///< Number of tCK cycles for the channel DIMM's minimum CAS-to-CAS delay for same bank group. +} MRC_CH_TIMING; + +typedef struct { + UINT16 tRDPRE; ///< Read CAS to Precharge cmd delay +} MRC_IP_TIMING; + +/// +/// Memory SMBIOS & OC Memory Data Hob +/// +typedef struct { + UINT8 Status; ///< See MrcDimmStatus for the definition of this field. + UINT8 DimmId; + UINT32 DimmCapacity; ///< DIMM size in MBytes. + UINT16 MfgId; + UINT8 ModulePartNum[20]; ///< Module part number for DDR3 is 18 bytes however for DRR4 20 bytes as per JEDEC Spec, so reserving 20 bytes + UINT8 RankInDimm; ///< The number of ranks in this DIMM. + UINT8 SpdDramDeviceType; ///< Save SPD DramDeviceType information needed for SMBIOS structure creation. + UINT8 SpdModuleType; ///< Save SPD ModuleType information needed for SMBIOS structure creation. + UINT8 SpdModuleMemoryBusWidth; ///< Save SPD ModuleMemoryBusWidth information needed for SMBIOS structure creation. + UINT8 SpdSave[MAX_SPD_SAVE]; ///< Save SPD Manufacturing information needed for SMBIOS structure creation. + UINT16 Speed; ///< The maximum capable speed of the device, in MHz + UINT8 MdSocket; ///< MdSocket: 0 = Memory Down, 1 = Socketed. Needed for SMBIOS structure creation. +} DIMM_INFO; + +typedef struct { + UINT8 Status; ///< Indicates whether this channel should be used. + UINT8 ChannelId; + UINT8 DimmCount; ///< Number of valid DIMMs that exist in the channel. + MRC_CH_TIMING Timing[MAX_PROFILE_NUM]; ///< The channel timing values. + DIMM_INFO DimmInfo[MAX_DIMM]; ///< Save the DIMM output characteristics. +} CHANNEL_INFO; + +typedef struct { + UINT8 Status; ///< Indicates whether this controller should be used. + UINT16 DeviceId; ///< The PCI device id of this memory controller. + UINT8 RevisionId; ///< The PCI revision id of this memory controller. + UINT8 ChannelCount; ///< Number of valid channels that exist on the controller. + CHANNEL_INFO ChannelInfo[MAX_CH]; ///< The following are channel level definitions. +} CONTROLLER_INFO; + +/// This data structure contains per-SaGv timing values that are considered output by the MRC. +typedef struct { + UINT32 DataRate; ///< The memory rate for the current SaGv Point in units of MT/s + MRC_CH_TIMING JedecTiming; ///< Timings used for this entry's corresponding SaGv Point - derived from JEDEC SPD spec + MRC_IP_TIMING IpTiming; ///< Timings used for this entry's corresponding SaGv Point - IP specific +} HOB_SAGV_TIMING_OUT; + +/// This data structure contains SAGV config values that are considered output by the MRC. +typedef struct { + UINT32 NumSaGvPointsEnabled; ///< Count of the total number of SAGV Points enabled. + UINT32 SaGvPointMask; ///< Bit mask where each bit indicates an enabled SAGV point. + HOB_SAGV_TIMING_OUT SaGvTiming[HOB_MAX_SAGV_POINTS]; } HOB_SAGV_INFO; + +typedef struct { + UINT8 Revision; + UINT16 DataWidth; ///< Data width, in bits, of this memory device + /** As defined in SMBIOS 3.0 spec + Section 7.18.2 and Table 75 + **/ + UINT8 MemoryType; ///< DDR type: DDR3, DDR4, or LPDDR3 + UINT16 MaximumMemoryClockSpeed;///< The maximum capable speed of the device, in megahertz (MHz) + UINT16 ConfiguredMemoryClockSpeed; ///< The configured clock speed to the memory device, in megahertz (MHz) + /** As defined in SMBIOS 3.0 spec + Section 7.17.3 and Table 72 + **/ + UINT8 ErrorCorrectionType; + + SiMrcVersion Version; + BOOLEAN EccSupport; + UINT8 MemoryProfile; + UINT8 IsDMBRunning; ///< Deprecated. + UINT32 TotalPhysicalMemorySize; + UINT32 DefaultXmptCK[MAX_XMP_PROFILE_NUM];///< Stores the tCK value read from SPD XMP profiles if they exist. + /// + /// Set of bit flags showing XMP and User Profile capability status for the DIMMs detected in system. For each bit, 1 is supported, 0 is unsupported. + /// Bit 0: XMP Profile 1 capability status + /// Bit 1: XMP Profile 2 capability status + /// Bit 2: XMP Profile 3 capability status + /// Bit 3: User Profile 4 capability status + /// Bit 4: User Profile 5 capability status + /// + UINT8 XmpProfileEnable; + UINT8 XmpConfigWarning; ///< If XMP capable DIMMs config support only 1DPC, but 2DPC is installed + UINT8 Ratio; ///< DDR Frequency Ratio, Max Value 255 + UINT8 RefClk; + UINT32 VddVoltage[MAX_PROFILE_NUM]; + UINT32 VddqVoltage[MAX_PROFILE_NUM]; + UINT32 VppVoltage[MAX_PROFILE_NUM]; + CONTROLLER_INFO Controller[MAX_NODE]; + UINT16 Ratio_UINT16; ///< DDR Frequency Ratio, used for programs that require ratios higher then 255 + UINT32 NumPopulatedChannels; ///< Total number of memory channels populated + HOB_SAGV_INFO SagvConfigInfo; ///< This data structure contains SAGV config values that are considered output by the MRC. + UINT16 TotalMemWidth; ///< Total Memory Width in bits from all populated channels + BOOLEAN MemorySpeedReducedWrongDimmSlot; ///< Can be used by OEM BIOS to display a warning on the screen that DDR speed was reduced due to wrong DIMM population + BOOLEAN MemorySpeedReducedMixedConfig; ///< Can be used by OEM BIOS to display a warning on the screen that DDR speed was reduced due to mixed DIMM config + BOOLEAN DynamicMemoryBoostTrainingFailed; ///< TRUE if Dynamic Memory Boost failed to train and was force disabled on the last full training boot. FALSE otherwise. +} MEMORY_INFO_DATA_HOB; + +#pragma pack (pop) + +#endif // _MEM_INFO_HOB_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Protocol/SaPolicy.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Protocol/SaPolicy.h new file mode 100644 index 0000000000..cc258debe1 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/Protocol/SaP +++ olicy.h @@ -0,0 +1,54 @@ +/** @file + Interface definition details between System Agent and platform drivers during DXE phase. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_SA_POLICY_H_ #define _SA_POLICY_H_ + +#include <ConfigBlock.h> +#include <Library/ConfigBlockLib.h> +#include <GraphicsConfig.h> +#include <ConfigBlock/MemoryDxeConfig.h> + +/// +/// Extern the GUID for protocol users. +/// +extern EFI_GUID gSaPolicyProtocolGuid; +extern EFI_GUID gGraphicsDxeConfigGuid; extern EFI_GUID +gMemoryDxeConfigGuid; + +/** + Don't change the original SA_POLICY_PROTOCOL_REVISION macro, external + modules maybe have consumed this macro in their source code. +Directly + update the SA_POLICY_PROTOCOL_REVISION version number may cause those + external modules to auto mark themselves wrong version info. + Always create new version macro for new Policy protocol interface. +**/ +#define SA_POLICY_PROTOCOL_REVISION 1 + + + + +/** + SA DXE Policy + + The SA_POLICY_PROTOCOL producer drvier is recommended to set all the + SA_POLICY_PROTOCOL size buffer zero before init any member parameter, + this clear step can make sure no random value for those unknow new version parameters. + + Make sure to update the Revision if any change to the protocol, +including the existing internal structure definations.\n + Note: Here revision will be bumped up when adding/removing any config +block under this structure.\n + <b>Revision 1</b>: + - Initial version. +**/ +typedef struct { + CONFIG_BLOCK_TABLE_HEADER TableHeader; ///< Offset 0-31 +/* + Individual Config Block Structures are added here in memory as part +of AddConfigBlock() */ } SA_POLICY_PROTOCOL; + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/SaDataHob.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/SaDataHob.h new file mode 100644 index 0000000000..bded1851f4 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Include/SaDataHob.h @@ -0,0 +1,28 @@ +/** @file + The GUID definition for SaDataHob + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_SA_DATA_HOB_H_ #define _SA_DATA_HOB_H_ + +#include <Base.h> +#include <CpuPcieInfo.h> +#include <Library/PcdLib.h> + +extern EFI_GUID gSaDataHobGuid; +#pragma pack (push,1) + +/// +/// System Agent Data Hob +/// +typedef struct { + EFI_HOB_GUID_TYPE EfiHobGuidType; ///< GUID Hob type structure for gSaDataHobGuid + UINT8 PrimaryDisplay; + BOOLEAN ResizableBarSupport; ///< Resizable BAR Support + UINT8 Rsvd1[2]; ///< Reserved for future use +} SA_DATA_HOB; + +#pragma pack (pop) +#endif -- 2.36.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107782): https://edk2.groups.io/g/devel/message/107782 Mute This Topic: https://groups.io/mt/100551005/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [edk2-devel] [PATCH v2 7/7] AlderlakeSiliconPkg/SystemAgent: Add library and driver modules 2023-08-04 17:37 [edk2-devel] [PATCH v2 1/7] AlderlakeSiliconPkg: Add package and library instances Saloni Kasbekar ` (4 preceding siblings ...) 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 6/7] AlderlakeSiliconPkg/SystemAgent: Add include headers Saloni Kasbekar @ 2023-08-04 17:37 ` Saloni Kasbekar 2023-08-16 2:45 ` Chuang, Rosen 2023-08-16 2:42 ` [edk2-devel] [PATCH v2 1/7] AlderlakeSiliconPkg: Add package and library instances Chuang, Rosen 6 siblings, 1 reply; 14+ messages in thread From: Saloni Kasbekar @ 2023-08-04 17:37 UTC (permalink / raw) To: devel Cc: Saloni Kasbekar, Sai Chaganty, Nate DeSimone, Isaac Oram, Rosen Chuang Adds the following modules: - Library/DxeSaPolicyLib - SaInit Cc: Sai Chaganty <rangasai.v.chaganty@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Isaac Oram <isaac.w.oram@intel.com> Cc: Rosen Chuang <rosen.chuang@intel.com> Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com> --- .../Library/DxeSaPolicyLib/DxeSaPolicyLib.c | 225 ++++++++++++++++++ .../Library/DxeSaPolicyLib/DxeSaPolicyLib.inf | 46 ++++ .../DxeSaPolicyLib/DxeSaPolicyLibrary.h | 30 +++ .../SystemAgent/SaInit/Dxe/SaInit.c | 97 ++++++++ .../SystemAgent/SaInit/Dxe/SaInit.h | 42 ++++ .../SystemAgent/SaInit/Dxe/SaInitDxe.c | 87 +++++++ .../SystemAgent/SaInit/Dxe/SaInitDxe.h | 97 ++++++++ .../SystemAgent/SaInit/Dxe/SaInitDxe.inf | 90 +++++++ 8 files changed, 714 insertions(+) create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLib.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLibrary.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.inf diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLib.c b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLib.c new file mode 100644 index 0000000000..d812f300c1 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLib.c @@ -0,0 +1,225 @@ +/** @file + This file provide services for DXE phase policy default initialization + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "DxeSaPolicyLibrary.h" +#include <Library/DxeGraphicsPolicyLib.h> +#include <Register/SaRegsHostBridge.h> +#include "MemoryConfig.h" + +extern EFI_GUID gMemoryDxeConfigGuid; + +/** + This function prints the SA DXE phase policy. + + @param[in] SaPolicy - SA DXE Policy protocol +**/ +VOID +SaPrintPolicyProtocol ( + IN SA_POLICY_PROTOCOL *SaPolicy + ) +{ + UINT8 ControllerIndex; + UINT8 ChannelIndex; + EFI_STATUS Status; + MEMORY_DXE_CONFIG *MemoryDxeConfig; + + Status = GetConfigBlock ((VOID *) SaPolicy, &gMemoryDxeConfigGuid, (VOID *)&MemoryDxeConfig); + ASSERT_EFI_ERROR (Status); + + + DEBUG_CODE_BEGIN (); + INTN i; + + DEBUG ((DEBUG_INFO, "\n------------------------ SA Policy (DXE) print BEGIN -----------------\n")); + DEBUG ((DEBUG_INFO, "Revision : %x\n", SaPolicy->TableHeader.Header.Revision)); + ASSERT (SaPolicy->TableHeader.Header.Revision == SA_POLICY_PROTOCOL_REVISION); + + DEBUG ((DEBUG_INFO, "------------------------ SA_MEMORY_CONFIGURATION -----------------\n")); + + DEBUG ((DEBUG_INFO, " SpdAddressTable[%d] :", 4)); + for (i = 0; i < 4; i++) { + DEBUG ((DEBUG_INFO, " %x", MemoryDxeConfig->SpdAddressTable[i])); + } + DEBUG ((DEBUG_INFO, "\n")); + + for (ControllerIndex = 0; ControllerIndex < MEM_CFG_MAX_CONTROLLERS; ControllerIndex++) { + for (ChannelIndex = 0; ChannelIndex < MEM_CFG_MAX_CHANNELS; ChannelIndex++) { + DEBUG ((DEBUG_INFO, " SlotMap[%d][%d] : 0x%x\n", ControllerIndex, ChannelIndex, MemoryDxeConfig->SlotMap[ControllerIndex][ChannelIndex])); + } + } + DEBUG ((DEBUG_INFO, " MrcTimeMeasure : %x\n", MemoryDxeConfig->MrcTimeMeasure)); + DEBUG ((DEBUG_INFO, " MrcFastBoot : %x\n", MemoryDxeConfig->MrcFastBoot)); + + DEBUG ((DEBUG_INFO, "------------------------ CPU_PCIE_CONFIGURATION -----------------\n")); + DEBUG ((DEBUG_INFO, " PegAspm[%d] :", SA_PEG_MAX_FUN)); + DEBUG ((DEBUG_INFO, " PegRootPortHPE[%d] :", SA_PEG_MAX_FUN)); + DEBUG ((DEBUG_INFO, "\n")); + + + DEBUG ((DEBUG_INFO, "\n------------------------ SA Policy (DXE) print END -----------------\n")); + DEBUG_CODE_END (); + + return; +} + +/** + Load DXE Config block default + + @param[in] ConfigBlockPointer Pointer to config block +**/ +VOID +LoadMemoryDxeDefault ( + IN VOID *ConfigBlockPointer + ) +{ + UINT8 ControllerIndex; + UINT8 ChannelIndex; + MEMORY_DXE_CONFIG *MemoryDxeConfig; + + MemoryDxeConfig = ConfigBlockPointer; + /// + /// Initialize the Memory Configuration + /// + /// + /// DIMM SMBus addresses info + /// Refer to the SpdAddressTable[] mapping rule in DxeSaPolicyLibrary.h + /// + MemoryDxeConfig->SpdAddressTable = AllocateZeroPool (sizeof (UINT8) * 4); + ASSERT (MemoryDxeConfig->SpdAddressTable != NULL); + if (MemoryDxeConfig->SpdAddressTable != NULL) { + MemoryDxeConfig->SpdAddressTable[0] = DIMM_SMB_SPD_P0C0D0; + MemoryDxeConfig->SpdAddressTable[1] = DIMM_SMB_SPD_P0C0D1; + MemoryDxeConfig->SpdAddressTable[2] = DIMM_SMB_SPD_P0C1D0; + MemoryDxeConfig->SpdAddressTable[3] = DIMM_SMB_SPD_P0C1D1; + } + MemoryDxeConfig->SlotMap = (UINT8**)AllocateZeroPool (sizeof (UINT8*) * MEM_CFG_MAX_CONTROLLERS); + ASSERT (MemoryDxeConfig->SlotMap != NULL); + if (MemoryDxeConfig->SlotMap != NULL) { + for (ControllerIndex = 0; ControllerIndex < MEM_CFG_MAX_CONTROLLERS; ControllerIndex++) { + MemoryDxeConfig->SlotMap[ControllerIndex] = (UINT8*)AllocateZeroPool (sizeof (UINT8) * MEM_CFG_MAX_CHANNELS); + ASSERT (MemoryDxeConfig->SlotMap[ControllerIndex] != NULL); + if (MemoryDxeConfig->SlotMap[ControllerIndex] != NULL) { + for (ChannelIndex = 0; ChannelIndex < MEM_CFG_MAX_CHANNELS; ChannelIndex++) { + MemoryDxeConfig->SlotMap[ControllerIndex][ChannelIndex] = 0x01; + } + } + } + } +} + +/** + LoadSaDxeConfigBlockDefault - Initialize default settings for each SA Config block + + @param[in] ConfigBlockPointer The buffer pointer that will be initialized as specific config block + @param[in] BlockId Request to initialize defaults of specified config block by given Block ID + + @retval EFI_SUCCESS The given buffer has contained the defaults of requested config block + @retval EFI_NOT_FOUND Block ID is not defined so no default Config block will be initialized +**/ + +GLOBAL_REMOVE_IF_UNREFERENCED COMPONENT_BLOCK_ENTRY mSaDxeIpBlocks [] = { + {&gMemoryDxeConfigGuid, sizeof (MEMORY_DXE_CONFIG), MEMORY_DXE_CONFIG_REVISION, LoadMemoryDxeDefault} +}; + + +/** + CreateSaDxeConfigBlocks generates the config blocksg of SA DXE Policy. + It allocates and zero out buffer, and fills in the Intel default settings. + + @param[out] SaPolicy The pointer to get SA DXE Protocol instance + + @retval EFI_SUCCESS The policy default is initialized. + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create buffer +**/ +EFI_STATUS +EFIAPI +CreateSaDxeConfigBlocks ( + IN OUT SA_POLICY_PROTOCOL **SaPolicy + ) +{ + UINT16 TotalBlockSize; + EFI_STATUS Status; + SA_POLICY_PROTOCOL *SaInitPolicy; + UINT16 RequiredSize; + + DEBUG ((DEBUG_INFO, "SA Create Dxe Config Blocks\n")); + + SaInitPolicy = NULL; + + TotalBlockSize = GetComponentConfigBlockTotalSize (&mSaDxeIpBlocks[0], sizeof (mSaDxeIpBlocks) / sizeof (COMPONENT_BLOCK_ENTRY)); + TotalBlockSize += GraphicsGetConfigBlockTotalSizeDxe (); + DEBUG ((DEBUG_INFO, "TotalBlockSize = 0x%x\n", TotalBlockSize)); + + RequiredSize = sizeof (CONFIG_BLOCK_TABLE_HEADER) + TotalBlockSize; + + Status = CreateConfigBlockTable (RequiredSize, (VOID *) &SaInitPolicy); + ASSERT_EFI_ERROR (Status); + + // + // Initialize Policy Revision + // + SaInitPolicy->TableHeader.Header.Revision = SA_POLICY_PROTOCOL_REVISION; + // + // Add config blocks. + // + Status = AddComponentConfigBlocks ((VOID *) SaInitPolicy, &mSaDxeIpBlocks[0], sizeof (mSaDxeIpBlocks) / sizeof (COMPONENT_BLOCK_ENTRY)); + ASSERT_EFI_ERROR (Status); + + + // Gfx + Status = GraphicsAddConfigBlocksDxe ((VOID *) SaInitPolicy); + ASSERT_EFI_ERROR (Status); + + // + // Assignment for returning SaInitPolicy config block base address + // + *SaPolicy = SaInitPolicy; + return Status; +} + + +/** + SaInstallPolicyProtocol installs SA Policy. + While installed, RC assumes the Policy is ready and finalized. So please update and override + any setting before calling this function. + + @param[in] ImageHandle Image handle of this driver. + @param[in] SaPolicy The pointer to SA Policy Protocol instance + + @retval EFI_SUCCESS The policy is installed. + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create buffer + +**/ +EFI_STATUS +EFIAPI +SaInstallPolicyProtocol ( + IN EFI_HANDLE ImageHandle, + IN SA_POLICY_PROTOCOL *SaPolicy + ) +{ + EFI_STATUS Status; + + /// + /// Print SA DXE Policy + /// + SaPrintPolicyProtocol (SaPolicy); + GraphicsDxePolicyPrint (SaPolicy); + + /// + /// Install protocol to to allow access to this Policy. + /// + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gSaPolicyProtocolGuid, + SaPolicy, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLib.inf new file mode 100644 index 0000000000..b7e867de59 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLib.inf @@ -0,0 +1,46 @@ +## @file +# Component description file for the PeiSaPolicy library. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = DxeSaPolicyLib +FILE_GUID = B402A3A4-4B82-410E-B79C-5914880A05E7 +VERSION_STRING = 1.0 +MODULE_TYPE = DXE_DRIVER +LIBRARY_CLASS = DxeSaPolicyLib + + +[LibraryClasses] +BaseMemoryLib +UefiRuntimeServicesTableLib +UefiBootServicesTableLib +DebugLib +PostCodeLib +ConfigBlockLib +HobLib +DxeGraphicsPolicyLib +CpuPlatformLib + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + + +[Sources] +DxeSaPolicyLib.c +DxeSaPolicyLibrary.h + + +[Guids] +gMemoryDxeConfigGuid + + +[Protocols] +gSaPolicyProtocolGuid ## PRODUCES + +[Pcd] diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLibrary.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLibrary.h new file mode 100644 index 0000000000..14fc02512e --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLibrary.h @@ -0,0 +1,30 @@ +/** @file + Header file for the DxeSaPolicy library. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _DXE_SA_POLICY_LIBRARY_H_ +#define _DXE_SA_POLICY_LIBRARY_H_ + +#include <Uefi.h> +#include <Library/DebugLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/ConfigBlockLib.h> +#include <CpuPcieConfigGen3.h> +#include <CpuPcieConfig.h> +#include <Protocol/SaPolicy.h> + +#define WORD_FIELD_VALID_BIT BIT15 +/// +/// DIMM SMBus addresses +/// +#define DIMM_SMB_SPD_P0C0D0 0xA0 +#define DIMM_SMB_SPD_P0C0D1 0xA2 +#define DIMM_SMB_SPD_P0C1D0 0xA4 +#define DIMM_SMB_SPD_P0C1D1 0xA6 + +#endif // _DXE_SA_POLICY_LIBRARY_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.c b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.c new file mode 100644 index 0000000000..5e472b0f60 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.c @@ -0,0 +1,97 @@ +/** @file + This is the Common driver that initializes the Intel System Agent. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "SaInit.h" +#include <Library/PciSegmentLib.h> +#include <HostBridgeDataHob.h> +#include <Protocol/PciEnumerationComplete.h> +#include <Library/CpuPlatformLib.h> +#include <Register/SaRegsHostBridge.h> + +/// +/// Global Variables +/// +BOOLEAN mSkipPamLock = FALSE; + +/* + Intel(R) Core Processor Skylake BWG version 0.4.0 + + 18.6 System Agent Configuration Locking + For reliable operation and security, System BIOS must set the following bits: + 1. For all modern Intel processors, Intel strongly recommends that BIOS should set + the D_LCK bit. Set B0:D0:F0.R088h [4] = 1b to lock down SMRAM space. + BaseAddr values for mSaSecurityRegisters that uses PciExpressBaseAddress will be initialized at + Runtime inside function CpuPcieInitPolicy(). +*/ +GLOBAL_REMOVE_IF_UNREFERENCED BOOT_SCRIPT_REGISTER_SETTING mSaSecurityRegisters[] = { + {0, R_SA_SMRAMC, 0xFFFFFFFF, BIT4} +}; + +/** + SystemAgent Initialization Common Function. + + @retval EFI_SUCCESS - Always. +**/ + +VOID +SaInitEntryPoint ( + VOID + ) +{ + HOST_BRIDGE_DATA_HOB *HostBridgeDataHob; + + /// + /// Get Host Bridge Data HOB + /// + HostBridgeDataHob = NULL; + HostBridgeDataHob = (HOST_BRIDGE_DATA_HOB *) GetFirstGuidHob (&gHostBridgeDataHobGuid); + if (HostBridgeDataHob != NULL) { + mSkipPamLock = HostBridgeDataHob->SkipPamLock; + } + return; +} + +/** + This function does SA security lock +**/ +VOID +SaSecurityLock ( + VOID + ) +{ + UINT8 Index; + UINT64 BaseAddress; + UINT32 RegOffset; + UINT32 Data32And; + UINT32 Data32Or; + + /// + /// 17.2 System Agent Security Lock configuration + /// + DEBUG ((DEBUG_INFO, "DXE SaSecurityLock\n")); + for (Index = 0; Index < (sizeof (mSaSecurityRegisters) / sizeof (BOOT_SCRIPT_REGISTER_SETTING)); Index++) { + BaseAddress = mSaSecurityRegisters[Index].BaseAddr; + RegOffset = mSaSecurityRegisters[Index].Offset; + Data32And = mSaSecurityRegisters[Index].AndMask; + Data32Or = mSaSecurityRegisters[Index].OrMask; + + if (RegOffset == R_SA_SMRAMC) { + /// + /// SMRAMC LOCK must use CF8/CFC access + /// + PciCf8Or8 (PCI_CF8_LIB_ADDRESS (SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_SMRAMC), (UINT8) Data32Or); + BaseAddress = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_SMRAMC); + S3BootScriptSavePciCfgReadWrite ( + S3BootScriptWidthUint8, + (UINTN) BaseAddress, + &Data32Or, + &Data32And + ); + } + } + +} + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.h new file mode 100644 index 0000000000..14e48a3eb4 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.h @@ -0,0 +1,42 @@ +/** @file + Header file for SA Common Initialization Driver. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _SA_INITIALIZATION_DRIVER_H_ +#define _SA_INITIALIZATION_DRIVER_H_ + +#include <Uefi.h> +#include <IndustryStandard/Acpi.h> +#include <IndustryStandard/Pci.h> +#include <Library/DebugLib.h> +#include <Library/HobLib.h> +#include <Library/UefiLib.h> +#include <Library/IoLib.h> +#include <Library/PciCf8Lib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/S3BootScriptLib.h> +#include <Guid/EventGroup.h> +#include <CpuRegs.h> +#include <Library/CpuPlatformLib.h> +#include <Protocol/SaPolicy.h> + +typedef struct { + UINT64 BaseAddr; + UINT32 Offset; + UINT32 AndMask; + UINT32 OrMask; +} BOOT_SCRIPT_REGISTER_SETTING; + +/** + SystemAgent Initialization Common Function. + + @retval EFI_SUCCESS - Always. +**/ +VOID +SaInitEntryPoint ( + VOID + ); +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.c b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.c new file mode 100644 index 0000000000..b30d8667c9 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.c @@ -0,0 +1,87 @@ +/** @file + This is the driver that initializes the Intel System Agent. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "SaInitDxe.h" +#include "SaInit.h" +#include <MemInfoHob.h> +#include <Protocol/PciEnumerationComplete.h> +#include <Library/CpuPlatformLib.h> +#include <Library/CpuPcieInfoFruLib.h> + +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPcieIoTrapAddress; + +/** + SystemAgent Dxe Initialization. + + @param[in] ImageHandle Handle for the image of this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_SUCCESS The function completed successfully + @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate +**/ +EFI_STATUS +EFIAPI +SaInitEntryPointDxe ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + VOID *Registration; +#if FixedPcdGetBool(PcdFspWrapperEnable) == 0 + EFI_EVENT Event; +#endif + + DEBUG ((DEBUG_INFO, "SaInitDxe Start\n")); + + SaInitEntryPoint (); + + /// + /// Create PCI Enumeration Completed callback for CPU PCIe + /// + EfiCreateProtocolNotifyEvent ( + &gEfiPciEnumerationCompleteProtocolGuid, + TPL_CALLBACK, + CpuPciEnumCompleteCallback, + NULL, + &Registration + ); + + DEBUG ((DEBUG_INFO, "SaInitDxe End\n")); + + return EFI_SUCCESS; +} + +/** + This function gets registered as a callback to perform CPU PCIe initialization before EndOfDxe + + @param[in] Event - A pointer to the Event that triggered the callback. + @param[in] Context - A pointer to private data registered with the callback function. +**/ +VOID +EFIAPI +CpuPciEnumCompleteCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + VOID *ProtocolPointer; + + DEBUG ((DEBUG_INFO, "CpuPciEnumCompleteCallback Start\n")); + /// + /// Check if this is first time called by EfiCreateProtocolNotifyEvent() or not, + /// if it is, we will skip it until real event is triggered + /// + Status = gBS->LocateProtocol (&gEfiPciEnumerationCompleteProtocolGuid, NULL, (VOID **) &ProtocolPointer); + if (EFI_SUCCESS != Status) { + return; + } + + gBS->CloseEvent (Event); + + DEBUG ((DEBUG_INFO, "CpuPciEnumCompleteCallback End\n")); + return; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.h new file mode 100644 index 0000000000..10d98d43a7 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.h @@ -0,0 +1,97 @@ +/** @file + Header file for SA Initialization Driver. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _SA_INIT_DXE_DRIVER_H_ +#define _SA_INIT_DXE_DRIVER_H_ + +#include <Library/UefiBootServicesTableLib.h> +#include <Protocol/AcpiTable.h> +#include <Library/DxeIgdOpRegionInitLib.h> +#include <Library/CpuPlatformLib.h> +#include <Register/SaRegsHostBridge.h> + +/// +/// Driver Consumed Protocol Prototypes +/// +#include <Protocol/SaPolicy.h> + +typedef struct { + UINT64 Address; + EFI_BOOT_SCRIPT_WIDTH Width; + UINT32 Value; +} BOOT_SCRIPT_PCI_REGISTER_SAVE; + +/// +/// Function Prototype +/// +/** + This function gets registered as a callback to perform CPU PCIe initialization before ExitPmAuth + + @param[in] Event - A pointer to the Event that triggered the callback. + @param[in] Context - A pointer to private data registered with the callback function. + +**/ +VOID +EFIAPI +CpuPciEnumCompleteCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + <b>System Agent Initialization DXE Driver Entry Point</b> + - <b>Introduction</b> \n + Based on the information/data in SA_POLICY_PROTOCOL, this module performs further SA initialization in DXE phase, + e.g. internal devices enable/disable, SSVID/SID programming, graphic power-management, VT-d, IGD OpRegion initialization. + From the perspective of a PCI Express hierarchy, the Broadwell System Agent and PCH together appear as a Root Complex with root ports the number of which depends on how the 8 PCH ports and 4 System Agent PCIe ports are configured [4x1, 2x8, 1x16]. + There is an internal link (DMI or OPI) that connects the System Agent to the PCH component. This driver includes initialization of SA DMI, PCI Express, SA & PCH Root Complex Topology. + For iGFX, this module implements the initialization of the Graphics Technology Power Management from the Broadwell System Agent BIOS Specification and the initialization of the IGD OpRegion/Software SCI - BIOS Specification. + The ASL files that go along with the driver define the IGD OpRegion mailboxes in ACPI space and implement the software SCI interrupt mechanism. + The IGD OpRegion/Software SCI code serves as a communication interface between system BIOS, ASL, and Intel graphics driver including making a block of customizable data (VBT) from the Intel video BIOS available. + Reference Code for the SCI service functions "Get BIOS Data" and "System BIOS Callback" can be found in the ASL files, those functions can be platform specific, the sample provided in the reference code are implemented for Intel CRB. + This module implements the VT-d functionality described in the Broadwell System Agent BIOS Specification. + This module publishes the LegacyRegion protocol to control the read and write accesses to the Legacy BIOS ranges. + E000 and F000 segments are the legacy BIOS ranges and contain pointers to the ACPI regions, SMBIOS tables and so on. This is a private protocol used by Intel Framework. + This module registers CallBack function that performs SA security registers lockdown at end of post as required from Broadwell Bios Spec. + In addition, this module publishes the SaInfo Protocol with information such as current System Agent reference code version#. + + - @pre + - EFI_FIRMWARE_VOLUME_PROTOCOL: Documented in Firmware Volume Specification, available at the URL: http://www.intel.com/technology/framework/spec.htm + - SA_POLICY_PROTOCOL: A protocol published by a platform DXE module executed earlier; this is documented in this document as well. + - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL: Documented in the Unified Extensible Firmware Interface Specification, version 2.0, available at the URL: http://www.uefi.org/specs/ + - EFI_BOOT_SCRIPT_SAVE_PROTOCOL: A protocol published by a platform DXE module executed earlier; refer to the Sample Code section of the Framework PCH Reference Code. + - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL: Documented in the Unified Extensible Firmware Interface Specification, version 2.0, available at the URL: http://www.uefi.org/specs/ + - EFI_ACPI_TABLE_PROTOCOL : Documented in PI Specification 1.2 + - EFI_CPU_IO_PROTOCOL: Documented in CPU I/O Protocol Specification, available at the URL: http://www.intel.com/technology/framework/spec.htm + - EFI_DATA_HUB_PROTOCOL: Documented in EFI Data Hub Infrastructure Specification, available at the URL: http://www.intel.com/technology/framework/spec.htm + - EFI_HII_PROTOCOL (or EFI_HII_DATABASE_PROTOCOL for UEFI 2.1): Documented in Human Interface Infrastructure Specification, available at the URL: http://www.intel.com/technology/framework/spec.htm + (For EFI_HII_DATABASE_PROTOCOL, refer to UEFI Specification Version 2.1 available at the URL: http://www.uefi.org/) + + - @result + IGD power-management functionality is initialized; VT-d is initialized (meanwhile, the DMAR table is updated); IGD OpRegion is initialized - IGD_OPREGION_PROTOCOL installed, IGD OpRegion allocated and mailboxes initialized, chipset initialized and ready to generate Software SCI for Internal graphics events. Publishes the SA_INFO_PROTOCOL with current SA reference code version #. Publishes the EFI_LEGACY_REGION_PROTOCOL documented in the Compatibility Support Module Specification, version 0.9, available at the URL: http://www.intel.com/technology/framework/spec.htm + + - <b>References</b> \n + IGD OpRegion/Software SCI for Broadwell + Advanced Configuration and Power Interface Specification Revision 4.0a. + + - <b>Porting Recommendations</b> \n + No modification of the DXE driver should be typically necessary. + This driver should be executed after all related devices (audio, video, ME, etc.) are initialized to ensure correct data in DMAR table and DMA-remapping registers. + + @param[in] ImageHandle Handle for the image of this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_SUCCESS The function completed successfully + @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate +**/ +EFI_STATUS +EFIAPI +SaInitEntryPointDxe ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.inf b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.inf new file mode 100644 index 0000000000..4551ea389d --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.inf @@ -0,0 +1,90 @@ +## @file +# Component description file for SystemAgent Initialization driver +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = SaInitDxe +FILE_GUID = DE23ACEE-CF55-4fb6-AA77-984AB53DE811 +VERSION_STRING = 1.0 +MODULE_TYPE = DXE_DRIVER +ENTRY_POINT = SaInitEntryPointDxe +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + + + +[LibraryClasses] +UefiDriverEntryPoint +UefiLib +UefiBootServicesTableLib +DxeServicesTableLib +DebugLib +TimerLib +PciCf8Lib +PciSegmentLib +BaseMemoryLib +MemoryAllocationLib +CpuPlatformLib +IoLib +S3BootScriptLib +PmcLib +PchCycleDecodingLib +PchInfoLib +GpioLib +ConfigBlockLib +PchPcieRpLib +DxeIgdOpRegionInitLib +AslUpdateLib +CpuPcieInfoFruLib + +[Packages] +MdePkg/MdePkg.dec +UefiCpuPkg/UefiCpuPkg.dec +IntelSiliconPkg/IntelSiliconPkg.dec +AlderlakeSiliconPkg/SiPkg.dec + +[Pcd] +gSiPkgTokenSpaceGuid.PcdSiPciExpressBaseAddress +gSiPkgTokenSpaceGuid.PcdMchBaseAddress +gSiPkgTokenSpaceGuid.PcdSiIoApicBaseAddress +gSiPkgTokenSpaceGuid.PcdFspWrapperEnable +gSiPkgTokenSpaceGuid.PcdCpuPcieEnable ## CONSUMES + +[Sources] +SaInitDxe.h +SaInitDxe.c +SaInit.h +SaInit.c + +[Protocols] +gEfiAcpiTableProtocolGuid ## CONSUMES +gSaPolicyProtocolGuid ## CONSUMES +gEfiCpuArchProtocolGuid ## CONSUMES +gEfiPciEnumerationCompleteProtocolGuid ## CONSUMES +gEfiPciRootBridgeIoProtocolGuid ## CONSUMES +gIgdOpRegionProtocolGuid ## PRODUCES +gEfiFirmwareVolume2ProtocolGuid ## CONSUMES + +[Guids] +gEfiEndOfDxeEventGroupGuid +gSiConfigHobGuid ## CONSUMES +gGraphicsDxeConfigGuid +gMemoryDxeConfigGuid +gSaDataHobGuid +gHostBridgeDataHobGuid + +[Depex] +gEfiAcpiTableProtocolGuid AND +gEfiFirmwareVolume2ProtocolGuid AND +gSaPolicyProtocolGuid AND +gEfiPciRootBridgeIoProtocolGuid AND +gEfiPciHostBridgeResourceAllocationProtocolGuid AND # This is to ensure that PCI MMIO resource has been prepared and available for this driver to allocate. +gEfiHiiDatabaseProtocolGuid -- 2.36.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107574): https://edk2.groups.io/g/devel/message/107574 Mute This Topic: https://groups.io/mt/100551006/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [edk2-devel] [PATCH v2 7/7] AlderlakeSiliconPkg/SystemAgent: Add library and driver modules 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 7/7] AlderlakeSiliconPkg/SystemAgent: Add library and driver modules Saloni Kasbekar @ 2023-08-16 2:45 ` Chuang, Rosen 0 siblings, 0 replies; 14+ messages in thread From: Chuang, Rosen @ 2023-08-16 2:45 UTC (permalink / raw) To: Kasbekar, Saloni, devel@edk2.groups.io Cc: Chaganty, Rangasai V, Desimone, Nathaniel L, Oram, Isaac W Reviewed-by: Rosen Chuang < rosen.chuang@intel.com> -----Original Message----- From: Kasbekar, Saloni <saloni.kasbekar@intel.com> Sent: Saturday, August 5, 2023 1:38 AM To: devel@edk2.groups.io Cc: Kasbekar, Saloni <saloni.kasbekar@intel.com>; Chaganty, Rangasai V <rangasai.v.chaganty@intel.com>; Desimone, Nathaniel L <nathaniel.l.desimone@intel.com>; Oram, Isaac W <isaac.w.oram@intel.com>; Chuang, Rosen <rosen.chuang@intel.com> Subject: [PATCH v2 7/7] AlderlakeSiliconPkg/SystemAgent: Add library and driver modules Adds the following modules: - Library/DxeSaPolicyLib - SaInit Cc: Sai Chaganty <rangasai.v.chaganty@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Isaac Oram <isaac.w.oram@intel.com> Cc: Rosen Chuang <rosen.chuang@intel.com> Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com> --- .../Library/DxeSaPolicyLib/DxeSaPolicyLib.c | 225 ++++++++++++++++++ .../Library/DxeSaPolicyLib/DxeSaPolicyLib.inf | 46 ++++ .../DxeSaPolicyLib/DxeSaPolicyLibrary.h | 30 +++ .../SystemAgent/SaInit/Dxe/SaInit.c | 97 ++++++++ .../SystemAgent/SaInit/Dxe/SaInit.h | 42 ++++ .../SystemAgent/SaInit/Dxe/SaInitDxe.c | 87 +++++++ .../SystemAgent/SaInit/Dxe/SaInitDxe.h | 97 ++++++++ .../SystemAgent/SaInit/Dxe/SaInitDxe.inf | 90 +++++++ 8 files changed, 714 insertions(+) create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLib.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLibrary.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.inf diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLib.c b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLib.c new file mode 100644 index 0000000000..d812f300c1 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyL +++ ib/DxeSaPolicyLib.c @@ -0,0 +1,225 @@ +/** @file + This file provide services for DXE phase policy default +initialization + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ + +#include "DxeSaPolicyLibrary.h" +#include <Library/DxeGraphicsPolicyLib.h> #include +<Register/SaRegsHostBridge.h> #include "MemoryConfig.h" + +extern EFI_GUID gMemoryDxeConfigGuid; + +/** + This function prints the SA DXE phase policy. + + @param[in] SaPolicy - SA DXE Policy protocol **/ VOID +SaPrintPolicyProtocol ( + IN SA_POLICY_PROTOCOL *SaPolicy + ) +{ + UINT8 ControllerIndex; + UINT8 ChannelIndex; + EFI_STATUS Status; + MEMORY_DXE_CONFIG *MemoryDxeConfig; + + Status = GetConfigBlock ((VOID *) SaPolicy, &gMemoryDxeConfigGuid, + (VOID *)&MemoryDxeConfig); ASSERT_EFI_ERROR (Status); + + + DEBUG_CODE_BEGIN (); + INTN i; + + DEBUG ((DEBUG_INFO, "\n------------------------ SA Policy (DXE) print + BEGIN -----------------\n")); DEBUG ((DEBUG_INFO, "Revision : %x\n", + SaPolicy->TableHeader.Header.Revision)); + ASSERT (SaPolicy->TableHeader.Header.Revision == + SA_POLICY_PROTOCOL_REVISION); + + DEBUG ((DEBUG_INFO, "------------------------ SA_MEMORY_CONFIGURATION + -----------------\n")); + + DEBUG ((DEBUG_INFO, " SpdAddressTable[%d] :", 4)); for (i = 0; i < + 4; i++) { + DEBUG ((DEBUG_INFO, " %x", MemoryDxeConfig->SpdAddressTable[i])); + } + DEBUG ((DEBUG_INFO, "\n")); + + for (ControllerIndex = 0; ControllerIndex < MEM_CFG_MAX_CONTROLLERS; ControllerIndex++) { + for (ChannelIndex = 0; ChannelIndex < MEM_CFG_MAX_CHANNELS; ChannelIndex++) { + DEBUG ((DEBUG_INFO, " SlotMap[%d][%d] : 0x%x\n", ControllerIndex, ChannelIndex, MemoryDxeConfig->SlotMap[ControllerIndex][ChannelIndex])); + } + } + DEBUG ((DEBUG_INFO, " MrcTimeMeasure : %x\n", MemoryDxeConfig->MrcTimeMeasure)); + DEBUG ((DEBUG_INFO, " MrcFastBoot : %x\n", MemoryDxeConfig->MrcFastBoot)); + + DEBUG ((DEBUG_INFO, "------------------------ CPU_PCIE_CONFIGURATION + -----------------\n")); DEBUG ((DEBUG_INFO, " PegAspm[%d] :", + SA_PEG_MAX_FUN)); DEBUG ((DEBUG_INFO, " PegRootPortHPE[%d] :", + SA_PEG_MAX_FUN)); DEBUG ((DEBUG_INFO, "\n")); + + + DEBUG ((DEBUG_INFO, "\n------------------------ SA Policy (DXE) print + END -----------------\n")); DEBUG_CODE_END (); + + return; +} + +/** + Load DXE Config block default + + @param[in] ConfigBlockPointer Pointer to config block +**/ +VOID +LoadMemoryDxeDefault ( + IN VOID *ConfigBlockPointer + ) +{ + UINT8 ControllerIndex; + UINT8 ChannelIndex; + MEMORY_DXE_CONFIG *MemoryDxeConfig; + + MemoryDxeConfig = ConfigBlockPointer; + /// + /// Initialize the Memory Configuration + /// + /// + /// DIMM SMBus addresses info + /// Refer to the SpdAddressTable[] mapping rule in +DxeSaPolicyLibrary.h + /// + MemoryDxeConfig->SpdAddressTable = AllocateZeroPool (sizeof (UINT8) * +4); + ASSERT (MemoryDxeConfig->SpdAddressTable != NULL); + if (MemoryDxeConfig->SpdAddressTable != NULL) { + MemoryDxeConfig->SpdAddressTable[0] = DIMM_SMB_SPD_P0C0D0; + MemoryDxeConfig->SpdAddressTable[1] = DIMM_SMB_SPD_P0C0D1; + MemoryDxeConfig->SpdAddressTable[2] = DIMM_SMB_SPD_P0C1D0; + MemoryDxeConfig->SpdAddressTable[3] = DIMM_SMB_SPD_P0C1D1; + } + MemoryDxeConfig->SlotMap = (UINT8**)AllocateZeroPool (sizeof (UINT8*) +* MEM_CFG_MAX_CONTROLLERS); + ASSERT (MemoryDxeConfig->SlotMap != NULL); + if (MemoryDxeConfig->SlotMap != NULL) { + for (ControllerIndex = 0; ControllerIndex < MEM_CFG_MAX_CONTROLLERS; ControllerIndex++) { + MemoryDxeConfig->SlotMap[ControllerIndex] = (UINT8*)AllocateZeroPool (sizeof (UINT8) * MEM_CFG_MAX_CHANNELS); + ASSERT (MemoryDxeConfig->SlotMap[ControllerIndex] != NULL); + if (MemoryDxeConfig->SlotMap[ControllerIndex] != NULL) { + for (ChannelIndex = 0; ChannelIndex < MEM_CFG_MAX_CHANNELS; ChannelIndex++) { + MemoryDxeConfig->SlotMap[ControllerIndex][ChannelIndex] = 0x01; + } + } + } + } +} + +/** + LoadSaDxeConfigBlockDefault - Initialize default settings for each SA +Config block + + @param[in] ConfigBlockPointer The buffer pointer that will be initialized as specific config block + @param[in] BlockId Request to initialize defaults of specified config block by given Block ID + + @retval EFI_SUCCESS The given buffer has contained the defaults of requested config block + @retval EFI_NOT_FOUND Block ID is not defined so no default Config block will be initialized +**/ + +GLOBAL_REMOVE_IF_UNREFERENCED COMPONENT_BLOCK_ENTRY mSaDxeIpBlocks [] = { + {&gMemoryDxeConfigGuid, sizeof (MEMORY_DXE_CONFIG), MEMORY_DXE_CONFIG_REVISION, LoadMemoryDxeDefault} +}; + + +/** + CreateSaDxeConfigBlocks generates the config blocksg of SA DXE Policy. + It allocates and zero out buffer, and fills in the Intel default settings. + + @param[out] SaPolicy The pointer to get SA DXE Protocol instance + + @retval EFI_SUCCESS The policy default is initialized. + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create buffer +**/ +EFI_STATUS +EFIAPI +CreateSaDxeConfigBlocks ( + IN OUT SA_POLICY_PROTOCOL **SaPolicy + ) +{ + UINT16 TotalBlockSize; + EFI_STATUS Status; + SA_POLICY_PROTOCOL *SaInitPolicy; + UINT16 RequiredSize; + + DEBUG ((DEBUG_INFO, "SA Create Dxe Config Blocks\n")); + + SaInitPolicy = NULL; + + TotalBlockSize = GetComponentConfigBlockTotalSize + (&mSaDxeIpBlocks[0], sizeof (mSaDxeIpBlocks) / sizeof + (COMPONENT_BLOCK_ENTRY)); TotalBlockSize += + GraphicsGetConfigBlockTotalSizeDxe (); DEBUG ((DEBUG_INFO, + "TotalBlockSize = 0x%x\n", TotalBlockSize)); + + RequiredSize = sizeof (CONFIG_BLOCK_TABLE_HEADER) + TotalBlockSize; + + Status = CreateConfigBlockTable (RequiredSize, (VOID *) + &SaInitPolicy); ASSERT_EFI_ERROR (Status); + + // + // Initialize Policy Revision + // + SaInitPolicy->TableHeader.Header.Revision = + SA_POLICY_PROTOCOL_REVISION; // // Add config blocks. + // + Status = AddComponentConfigBlocks ((VOID *) SaInitPolicy, + &mSaDxeIpBlocks[0], sizeof (mSaDxeIpBlocks) / sizeof + (COMPONENT_BLOCK_ENTRY)); ASSERT_EFI_ERROR (Status); + + + // Gfx + Status = GraphicsAddConfigBlocksDxe ((VOID *) SaInitPolicy); + ASSERT_EFI_ERROR (Status); + + // + // Assignment for returning SaInitPolicy config block base address + // + *SaPolicy = SaInitPolicy; + return Status; +} + + +/** + SaInstallPolicyProtocol installs SA Policy. + While installed, RC assumes the Policy is ready and finalized. So +please update and override + any setting before calling this function. + + @param[in] ImageHandle Image handle of this driver. + @param[in] SaPolicy The pointer to SA Policy Protocol instance + + @retval EFI_SUCCESS The policy is installed. + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create buffer + +**/ +EFI_STATUS +EFIAPI +SaInstallPolicyProtocol ( + IN EFI_HANDLE ImageHandle, + IN SA_POLICY_PROTOCOL *SaPolicy + ) +{ + EFI_STATUS Status; + + /// + /// Print SA DXE Policy + /// + SaPrintPolicyProtocol (SaPolicy); + GraphicsDxePolicyPrint (SaPolicy); + + /// + /// Install protocol to to allow access to this Policy. + /// + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gSaPolicyProtocolGuid, + SaPolicy, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLib.inf new file mode 100644 index 0000000000..b7e867de59 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyL +++ ib/DxeSaPolicyLib.inf @@ -0,0 +1,46 @@ +## @file +# Component description file for the PeiSaPolicy library. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = DxeSaPolicyLib +FILE_GUID = B402A3A4-4B82-410E-B79C-5914880A05E7 +VERSION_STRING = 1.0 +MODULE_TYPE = DXE_DRIVER +LIBRARY_CLASS = DxeSaPolicyLib + + +[LibraryClasses] +BaseMemoryLib +UefiRuntimeServicesTableLib +UefiBootServicesTableLib +DebugLib +PostCodeLib +ConfigBlockLib +HobLib +DxeGraphicsPolicyLib +CpuPlatformLib + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + + +[Sources] +DxeSaPolicyLib.c +DxeSaPolicyLibrary.h + + +[Guids] +gMemoryDxeConfigGuid + + +[Protocols] +gSaPolicyProtocolGuid ## PRODUCES + +[Pcd] diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLibrary.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyLib/DxeSaPolicyLibrary.h new file mode 100644 index 0000000000..14fc02512e --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/Library/DxeSaPolicyL +++ ib/DxeSaPolicyLibrary.h @@ -0,0 +1,30 @@ +/** @file + Header file for the DxeSaPolicy library. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_DXE_SA_POLICY_LIBRARY_H_ #define _DXE_SA_POLICY_LIBRARY_H_ + +#include <Uefi.h> +#include <Library/DebugLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> #include +<Library/ConfigBlockLib.h> #include <CpuPcieConfigGen3.h> #include +<CpuPcieConfig.h> #include <Protocol/SaPolicy.h> + +#define WORD_FIELD_VALID_BIT BIT15 +/// +/// DIMM SMBus addresses +/// +#define DIMM_SMB_SPD_P0C0D0 0xA0 +#define DIMM_SMB_SPD_P0C0D1 0xA2 +#define DIMM_SMB_SPD_P0C1D0 0xA4 +#define DIMM_SMB_SPD_P0C1D1 0xA6 + +#endif // _DXE_SA_POLICY_LIBRARY_H_ diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.c b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.c new file mode 100644 index 0000000000..5e472b0f60 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.c @@ -0,0 +1,97 @@ +/** @file + This is the Common driver that initializes the Intel System Agent. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "SaInit.h" +#include <Library/PciSegmentLib.h> +#include <HostBridgeDataHob.h> +#include <Protocol/PciEnumerationComplete.h> +#include <Library/CpuPlatformLib.h> +#include <Register/SaRegsHostBridge.h> + +/// +/// Global Variables +/// +BOOLEAN mSkipPamLock = FALSE; + +/* + Intel(R) Core Processor Skylake BWG version 0.4.0 + + 18.6 System Agent Configuration Locking + For reliable operation and security, System BIOS must set the following bits: + 1. For all modern Intel processors, Intel strongly recommends that BIOS should set + the D_LCK bit. Set B0:D0:F0.R088h [4] = 1b to lock down SMRAM space. + BaseAddr values for mSaSecurityRegisters that uses +PciExpressBaseAddress will be initialized at + Runtime inside function CpuPcieInitPolicy(). +*/ +GLOBAL_REMOVE_IF_UNREFERENCED BOOT_SCRIPT_REGISTER_SETTING +mSaSecurityRegisters[] = { + {0, R_SA_SMRAMC, 0xFFFFFFFF, BIT4} }; + +/** + SystemAgent Initialization Common Function. + + @retval EFI_SUCCESS - Always. +**/ + +VOID +SaInitEntryPoint ( + VOID + ) +{ + HOST_BRIDGE_DATA_HOB *HostBridgeDataHob; + + /// + /// Get Host Bridge Data HOB + /// + HostBridgeDataHob = NULL; + HostBridgeDataHob = (HOST_BRIDGE_DATA_HOB *) GetFirstGuidHob +(&gHostBridgeDataHobGuid); + if (HostBridgeDataHob != NULL) { + mSkipPamLock = HostBridgeDataHob->SkipPamLock; + } + return; +} + +/** + This function does SA security lock +**/ +VOID +SaSecurityLock ( + VOID + ) +{ + UINT8 Index; + UINT64 BaseAddress; + UINT32 RegOffset; + UINT32 Data32And; + UINT32 Data32Or; + + /// + /// 17.2 System Agent Security Lock configuration /// DEBUG + ((DEBUG_INFO, "DXE SaSecurityLock\n")); for (Index = 0; Index < + (sizeof (mSaSecurityRegisters) / sizeof (BOOT_SCRIPT_REGISTER_SETTING)); Index++) { + BaseAddress = mSaSecurityRegisters[Index].BaseAddr; + RegOffset = mSaSecurityRegisters[Index].Offset; + Data32And = mSaSecurityRegisters[Index].AndMask; + Data32Or = mSaSecurityRegisters[Index].OrMask; + + if (RegOffset == R_SA_SMRAMC) { + /// + /// SMRAMC LOCK must use CF8/CFC access + /// + PciCf8Or8 (PCI_CF8_LIB_ADDRESS (SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_SMRAMC), (UINT8) Data32Or); + BaseAddress = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_SMRAMC); + S3BootScriptSavePciCfgReadWrite ( + S3BootScriptWidthUint8, + (UINTN) BaseAddress, + &Data32Or, + &Data32And + ); + } + } + +} + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.h new file mode 100644 index 0000000000..14e48a3eb4 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInit.h @@ -0,0 +1,42 @@ +/** @file + Header file for SA Common Initialization Driver. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_SA_INITIALIZATION_DRIVER_H_ #define _SA_INITIALIZATION_DRIVER_H_ + +#include <Uefi.h> +#include <IndustryStandard/Acpi.h> +#include <IndustryStandard/Pci.h> +#include <Library/DebugLib.h> +#include <Library/HobLib.h> +#include <Library/UefiLib.h> +#include <Library/IoLib.h> +#include <Library/PciCf8Lib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> #include +<Library/S3BootScriptLib.h> #include <Guid/EventGroup.h> #include +<CpuRegs.h> #include <Library/CpuPlatformLib.h> #include +<Protocol/SaPolicy.h> + +typedef struct { + UINT64 BaseAddr; + UINT32 Offset; + UINT32 AndMask; + UINT32 OrMask; +} BOOT_SCRIPT_REGISTER_SETTING; + +/** + SystemAgent Initialization Common Function. + + @retval EFI_SUCCESS - Always. +**/ +VOID +SaInitEntryPoint ( + VOID + ); +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.c b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.c new file mode 100644 index 0000000000..b30d8667c9 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe +++ .c @@ -0,0 +1,87 @@ +/** @file + This is the driver that initializes the Intel System Agent. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include +"SaInitDxe.h" +#include "SaInit.h" +#include <MemInfoHob.h> +#include <Protocol/PciEnumerationComplete.h> +#include <Library/CpuPlatformLib.h> +#include <Library/CpuPcieInfoFruLib.h> + +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPcieIoTrapAddress; + +/** + SystemAgent Dxe Initialization. + + @param[in] ImageHandle Handle for the image of this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_SUCCESS The function completed successfully + @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate +**/ +EFI_STATUS +EFIAPI +SaInitEntryPointDxe ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + VOID *Registration; +#if FixedPcdGetBool(PcdFspWrapperEnable) == 0 + EFI_EVENT Event; +#endif + + DEBUG ((DEBUG_INFO, "SaInitDxe Start\n")); + + SaInitEntryPoint (); + + /// + /// Create PCI Enumeration Completed callback for CPU PCIe /// + EfiCreateProtocolNotifyEvent ( + &gEfiPciEnumerationCompleteProtocolGuid, + TPL_CALLBACK, + CpuPciEnumCompleteCallback, + NULL, + &Registration + ); + + DEBUG ((DEBUG_INFO, "SaInitDxe End\n")); + + return EFI_SUCCESS; +} + +/** + This function gets registered as a callback to perform CPU PCIe +initialization before EndOfDxe + + @param[in] Event - A pointer to the Event that triggered the callback. + @param[in] Context - A pointer to private data registered with the callback function. +**/ +VOID +EFIAPI +CpuPciEnumCompleteCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + VOID *ProtocolPointer; + + DEBUG ((DEBUG_INFO, "CpuPciEnumCompleteCallback Start\n")); /// /// + Check if this is first time called by EfiCreateProtocolNotifyEvent() + or not, /// if it is, we will skip it until real event is triggered + /// Status = gBS->LocateProtocol + (&gEfiPciEnumerationCompleteProtocolGuid, NULL, (VOID **) + &ProtocolPointer); if (EFI_SUCCESS != Status) { + return; + } + + gBS->CloseEvent (Event); + + DEBUG ((DEBUG_INFO, "CpuPciEnumCompleteCallback End\n")); + return; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.h b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.h new file mode 100644 index 0000000000..10d98d43a7 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe +++ .h @@ -0,0 +1,97 @@ +/** @file + Header file for SA Initialization Driver. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef +_SA_INIT_DXE_DRIVER_H_ #define _SA_INIT_DXE_DRIVER_H_ + +#include <Library/UefiBootServicesTableLib.h> +#include <Protocol/AcpiTable.h> +#include <Library/DxeIgdOpRegionInitLib.h> #include +<Library/CpuPlatformLib.h> #include <Register/SaRegsHostBridge.h> + +/// +/// Driver Consumed Protocol Prototypes /// #include +<Protocol/SaPolicy.h> + +typedef struct { + UINT64 Address; + EFI_BOOT_SCRIPT_WIDTH Width; + UINT32 Value; +} BOOT_SCRIPT_PCI_REGISTER_SAVE; + +/// +/// Function Prototype +/// +/** + This function gets registered as a callback to perform CPU PCIe +initialization before ExitPmAuth + + @param[in] Event - A pointer to the Event that triggered the callback. + @param[in] Context - A pointer to private data registered with the callback function. + +**/ +VOID +EFIAPI +CpuPciEnumCompleteCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + <b>System Agent Initialization DXE Driver Entry Point</b> + - <b>Introduction</b> \n + Based on the information/data in SA_POLICY_PROTOCOL, this module performs further SA initialization in DXE phase, + e.g. internal devices enable/disable, SSVID/SID programming, graphic power-management, VT-d, IGD OpRegion initialization. + From the perspective of a PCI Express hierarchy, the Broadwell System Agent and PCH together appear as a Root Complex with root ports the number of which depends on how the 8 PCH ports and 4 System Agent PCIe ports are configured [4x1, 2x8, 1x16]. + There is an internal link (DMI or OPI) that connects the System Agent to the PCH component. This driver includes initialization of SA DMI, PCI Express, SA & PCH Root Complex Topology. + For iGFX, this module implements the initialization of the Graphics Technology Power Management from the Broadwell System Agent BIOS Specification and the initialization of the IGD OpRegion/Software SCI - BIOS Specification. + The ASL files that go along with the driver define the IGD OpRegion mailboxes in ACPI space and implement the software SCI interrupt mechanism. + The IGD OpRegion/Software SCI code serves as a communication interface between system BIOS, ASL, and Intel graphics driver including making a block of customizable data (VBT) from the Intel video BIOS available. + Reference Code for the SCI service functions "Get BIOS Data" and "System BIOS Callback" can be found in the ASL files, those functions can be platform specific, the sample provided in the reference code are implemented for Intel CRB. + This module implements the VT-d functionality described in the Broadwell System Agent BIOS Specification. + This module publishes the LegacyRegion protocol to control the read and write accesses to the Legacy BIOS ranges. + E000 and F000 segments are the legacy BIOS ranges and contain pointers to the ACPI regions, SMBIOS tables and so on. This is a private protocol used by Intel Framework. + This module registers CallBack function that performs SA security registers lockdown at end of post as required from Broadwell Bios Spec. + In addition, this module publishes the SaInfo Protocol with information such as current System Agent reference code version#. + + - @pre + - EFI_FIRMWARE_VOLUME_PROTOCOL: Documented in Firmware Volume Specification, available at the URL: http://www.intel.com/technology/framework/spec.htm + - SA_POLICY_PROTOCOL: A protocol published by a platform DXE module executed earlier; this is documented in this document as well. + - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL: Documented in the Unified Extensible Firmware Interface Specification, version 2.0, available at the URL: http://www.uefi.org/specs/ + - EFI_BOOT_SCRIPT_SAVE_PROTOCOL: A protocol published by a platform DXE module executed earlier; refer to the Sample Code section of the Framework PCH Reference Code. + - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL: Documented in the Unified Extensible Firmware Interface Specification, version 2.0, available at the URL: http://www.uefi.org/specs/ + - EFI_ACPI_TABLE_PROTOCOL : Documented in PI Specification 1.2 + - EFI_CPU_IO_PROTOCOL: Documented in CPU I/O Protocol Specification, available at the URL: http://www.intel.com/technology/framework/spec.htm + - EFI_DATA_HUB_PROTOCOL: Documented in EFI Data Hub Infrastructure Specification, available at the URL: http://www.intel.com/technology/framework/spec.htm + - EFI_HII_PROTOCOL (or EFI_HII_DATABASE_PROTOCOL for UEFI 2.1): Documented in Human Interface Infrastructure Specification, available at the URL: http://www.intel.com/technology/framework/spec.htm + (For EFI_HII_DATABASE_PROTOCOL, refer to UEFI Specification Version + 2.1 available at the URL: http://www.uefi.org/) + + - @result + IGD power-management functionality is initialized; VT-d is + initialized (meanwhile, the DMAR table is updated); IGD OpRegion is + initialized - IGD_OPREGION_PROTOCOL installed, IGD OpRegion allocated + and mailboxes initialized, chipset initialized and ready to generate + Software SCI for Internal graphics events. Publishes the + SA_INFO_PROTOCOL with current SA reference code version #. Publishes + the EFI_LEGACY_REGION_PROTOCOL documented in the Compatibility Support + Module Specification, version 0.9, available at the URL: + http://www.intel.com/technology/framework/spec.htm + + - <b>References</b> \n + IGD OpRegion/Software SCI for Broadwell + Advanced Configuration and Power Interface Specification Revision 4.0a. + + - <b>Porting Recommendations</b> \n + No modification of the DXE driver should be typically necessary. + This driver should be executed after all related devices (audio, video, ME, etc.) are initialized to ensure correct data in DMAR table and DMA-remapping registers. + + @param[in] ImageHandle Handle for the image of this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_SUCCESS The function completed successfully + @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate +**/ +EFI_STATUS +EFIAPI +SaInitEntryPointDxe ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.inf b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe.inf new file mode 100644 index 0000000000..4551ea389d --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/SystemAgent/SaInit/Dxe/SaInitDxe +++ .inf @@ -0,0 +1,90 @@ +## @file +# Component description file for SystemAgent Initialization driver # +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = SaInitDxe +FILE_GUID = DE23ACEE-CF55-4fb6-AA77-984AB53DE811 +VERSION_STRING = 1.0 +MODULE_TYPE = DXE_DRIVER +ENTRY_POINT = SaInitEntryPointDxe +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + + + +[LibraryClasses] +UefiDriverEntryPoint +UefiLib +UefiBootServicesTableLib +DxeServicesTableLib +DebugLib +TimerLib +PciCf8Lib +PciSegmentLib +BaseMemoryLib +MemoryAllocationLib +CpuPlatformLib +IoLib +S3BootScriptLib +PmcLib +PchCycleDecodingLib +PchInfoLib +GpioLib +ConfigBlockLib +PchPcieRpLib +DxeIgdOpRegionInitLib +AslUpdateLib +CpuPcieInfoFruLib + +[Packages] +MdePkg/MdePkg.dec +UefiCpuPkg/UefiCpuPkg.dec +IntelSiliconPkg/IntelSiliconPkg.dec +AlderlakeSiliconPkg/SiPkg.dec + +[Pcd] +gSiPkgTokenSpaceGuid.PcdSiPciExpressBaseAddress +gSiPkgTokenSpaceGuid.PcdMchBaseAddress +gSiPkgTokenSpaceGuid.PcdSiIoApicBaseAddress +gSiPkgTokenSpaceGuid.PcdFspWrapperEnable +gSiPkgTokenSpaceGuid.PcdCpuPcieEnable ## CONSUMES + +[Sources] +SaInitDxe.h +SaInitDxe.c +SaInit.h +SaInit.c + +[Protocols] +gEfiAcpiTableProtocolGuid ## CONSUMES +gSaPolicyProtocolGuid ## CONSUMES +gEfiCpuArchProtocolGuid ## CONSUMES +gEfiPciEnumerationCompleteProtocolGuid ## CONSUMES +gEfiPciRootBridgeIoProtocolGuid ## CONSUMES +gIgdOpRegionProtocolGuid ## PRODUCES +gEfiFirmwareVolume2ProtocolGuid ## CONSUMES + +[Guids] +gEfiEndOfDxeEventGroupGuid +gSiConfigHobGuid ## CONSUMES +gGraphicsDxeConfigGuid +gMemoryDxeConfigGuid +gSaDataHobGuid +gHostBridgeDataHobGuid + +[Depex] +gEfiAcpiTableProtocolGuid AND +gEfiFirmwareVolume2ProtocolGuid AND +gSaPolicyProtocolGuid AND +gEfiPciRootBridgeIoProtocolGuid AND +gEfiPciHostBridgeResourceAllocationProtocolGuid AND # This is to ensure that PCI MMIO resource has been prepared and available for this driver to allocate. +gEfiHiiDatabaseProtocolGuid -- 2.36.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107783): https://edk2.groups.io/g/devel/message/107783 Mute This Topic: https://groups.io/mt/100551006/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [edk2-devel] [PATCH v2 1/7] AlderlakeSiliconPkg: Add package and library instances 2023-08-04 17:37 [edk2-devel] [PATCH v2 1/7] AlderlakeSiliconPkg: Add package and library instances Saloni Kasbekar ` (5 preceding siblings ...) 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 7/7] AlderlakeSiliconPkg/SystemAgent: Add library and driver modules Saloni Kasbekar @ 2023-08-16 2:42 ` Chuang, Rosen 6 siblings, 0 replies; 14+ messages in thread From: Chuang, Rosen @ 2023-08-16 2:42 UTC (permalink / raw) To: Kasbekar, Saloni, devel@edk2.groups.io Cc: Chaganty, Rangasai V, Desimone, Nathaniel L, Oram, Isaac W Reviewed-by: Rosen Chuang < rosen.chuang@intel.com> Thanks, Rosen -----Original Message----- From: Kasbekar, Saloni <saloni.kasbekar@intel.com> Sent: Saturday, August 5, 2023 1:38 AM To: devel@edk2.groups.io Cc: Kasbekar, Saloni <saloni.kasbekar@intel.com>; Chaganty, Rangasai V <rangasai.v.chaganty@intel.com>; Desimone, Nathaniel L <nathaniel.l.desimone@intel.com>; Oram, Isaac W <isaac.w.oram@intel.com>; Chuang, Rosen <rosen.chuang@intel.com> Subject: [PATCH v2 1/7] AlderlakeSiliconPkg: Add package and library instances Create the AlderlakeSiliconPkg to provide an initial package for silicon initialization code for Alder Lake (ADL) products. Add the following libraries - - BasePciSegmentMultiSegLibPci - BaseSiConfigBlockLib - PeiPostMemSiliconPolicyInitLib - PeiPreMemSiliconPolicyInitLib Cc: Sai Chaganty <rangasai.v.chaganty@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Isaac Oram <isaac.w.oram@intel.com> Cc: Rosen Chuang <rosen.chuang@intel.com> Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com> --- .../BasePciSegmentMultiSegLibPci.inf | 37 ++ .../BasePciSegmentMultiSegLibPci.uni | 14 + .../PciSegmentLib.c | 597 ++++++++++++++++++ .../BaseSiConfigBlockLib.c | 87 +++ .../BaseSiConfigBlockLib.inf | 32 + .../PeiPostMemSiliconPolicyInitLib.c | 94 +++ .../PeiPostMemSiliconPolicyInitLib.inf | 36 ++ .../PeiPreMemSiliconPolicyInitLib.c | 98 +++ .../PeiPreMemSiliconPolicyInitLib.inf | 36 ++ 9 files changed, 1031 insertions(+) create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/BasePciSegmentMultiSegLibPci.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/BasePciSegmentMultiSegLibPci.uni create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/PciSegmentLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/BaseSiConfigBlockLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/BaseSiConfigBlockLib.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyInitLib/PeiPostMemSiliconPolicyInitLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyInitLib/PeiPostMemSiliconPolicyInitLib.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyInitLib/PeiPreMemSiliconPolicyInitLib.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyInitLib/PeiPreMemSiliconPolicyInitLib.inf diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/BasePciSegmentMultiSegLibPci.inf b/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/BasePciSegmentMultiSegLibPci.inf new file mode 100644 index 0000000000..f3764d0187 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLi +++ bPci/BasePciSegmentMultiSegLibPci.inf @@ -0,0 +1,37 @@ +## @file +# Instance of PCI Segment Library based on PCI Library. +# +# PCI Segment Library that layers on top of the PCI Library which only +# supports segment 0 and segment 1 PCI configuration access. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BasePciSegmentMultiSegLibPci + MODULE_UNI_FILE = BasePciSegmentMultiSegLibPci.uni + FILE_GUID = AC65B409-DF03-466e-8D2B-6FCE1079F0B2 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = PciSegmentLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + PciSegmentLib.c + +[Packages] + MdePkg/MdePkg.dec + AlderlakeSiliconPkg/SiPkg.dec + +[LibraryClasses] + BaseLib + PciLib + DebugLib + PcdLib diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/BasePciSegmentMultiSegLibPci.uni b/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/BasePciSegmentMultiSegLibPci.uni new file mode 100644 index 0000000000..dd8d74bee8 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLi +++ bPci/BasePciSegmentMultiSegLibPci.uni @@ -0,0 +1,14 @@ +// /** @file +// Instance of PCI Segment Library based on PCI Library. +// +// PCI Segment Library that layers on top of the PCI Library which only +// supports segment 0 and segment 1 PCI configuration access. +// +// Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +// SPDX-License-Identifier: BSD-2-Clause-Patent +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Instance of PCI Segment Library based on PCI Library." + +#string STR_MODULE_DESCRIPTION #language en-US "PCI Segment Library that layers on top of the PCI Library which only supports segment 0 and segment 1 PCI configuration access." diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/PciSegmentLib.c b/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLibPci/PciSegmentLib.c new file mode 100644 index 0000000000..9bcb388016 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/BasePciSegmentMultiSegLi +++ bPci/PciSegmentLib.c @@ -0,0 +1,597 @@ +/** @file + PCI Segment Library that layers on top of the PCI Library which only + supports segment 0 and segment 1 PCI configuration access. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ + +#include <Base.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/PciLib.h> +#include <Library/PciSegmentLib.h> + +/** + Assert the validity of a PCI Segment address. + A valid PCI Segment address should not contain 1's in bits 28..31 and +33..63 + and the segment should be 0 or 1. + + @param A The address to validate. + @param M Additional bits to assert to be zero. + +**/ +#define ASSERT_INVALID_PCI_SEGMENT_ADDRESS(A,M) \ + ASSERT (((A) & (0xfffffffef0000000ULL | (M))) == 0) + +/** + Convert the PCI Segment library address to PCI library address. + From ICL generation support the multiple segment, and the segment +number start from BIT28, + So we convert the Segment Number offset from BIT32 to BIT28 + + @param A The address to convert. +**/ +#define PCI_SEGMENT_TO_PCI_ADDRESS(A) ((UINTN) (UINT32) ((A) | +((RShiftU64 ((A) & BIT32, 4))))) + + + +/** + Reads an 8-bit PCI configuration register. + + Reads and returns the 8-bit PCI configuration register specified by Address. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + + @return The 8-bit PCI configuration register specified by Address. + +**/ +UINT8 +EFIAPI +PciSegmentRead8 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + + return PciRead8 (PCI_SEGMENT_TO_PCI_ADDRESS (Address)); } + +/** + Writes an 8-bit PCI configuration register. + + Writes the 8-bit PCI configuration register specified by Address with the value specified by Value. + Value is returned. This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param Value The value to write. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentWrite8 ( + IN UINT64 Address, + IN UINT8 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + + return PciWrite8 (PCI_SEGMENT_TO_PCI_ADDRESS (Address), Value); } + +/** + Performs a bitwise OR of an 8-bit PCI configuration register with an 8-bit value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified + by OrData, and writes the result to the 8-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentOr8 ( + IN UINT64 Address, + IN UINT8 OrData + ) +{ + return PciWrite8 (PCI_SEGMENT_TO_PCI_ADDRESS (Address), (UINT8) +(PciSegmentRead8 (Address) | OrData)); } + +/** + Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified + by AndData, and writes the result to the 8-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param AndData The value to AND with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentAnd8 ( + IN UINT64 Address, + IN UINT8 AndData + ) +{ + return PciSegmentWrite8 (Address, (UINT8) (PciSegmentRead8 (Address) +& AndData)); } + +/** + Performs a bitwise AND of an 8-bit PCI configuration register with an +8-bit value, + followed a bitwise OR with another 8-bit value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified + by AndData, performs a bitwise OR between the result of the AND + operation and the value specified by OrData, and writes the result to the 8-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentAndThenOr8 ( + IN UINT64 Address, + IN UINT8 AndData, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 (Address, (UINT8) ((PciSegmentRead8 (Address) +& AndData) | OrData)); } + +/** + Reads a 16-bit PCI configuration register. + + Reads and returns the 16-bit PCI configuration register specified by Address. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + + @return The 16-bit PCI configuration register specified by Address. + +**/ +UINT16 +EFIAPI +PciSegmentRead16 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1); + + return PciRead16 (PCI_SEGMENT_TO_PCI_ADDRESS (Address)); } + +/** + Writes a 16-bit PCI configuration register. + + Writes the 16-bit PCI configuration register specified by Address with the value specified by Value. + Value is returned. This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param Value The value to write. + + @return The parameter of Value. + +**/ +UINT16 +EFIAPI +PciSegmentWrite16 ( + IN UINT64 Address, + IN UINT16 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1); + + return PciWrite16 (PCI_SEGMENT_TO_PCI_ADDRESS (Address), Value); } + +/** + Performs a bitwise OR of a 16-bit PCI configuration register with + a 16-bit value. + + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified + by OrData, and writes the result to the 16-bit PCI configuration + register specified by Address. The value written to the PCI + configuration register is returned. This function must guarantee that + all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function and + Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentOr16 ( + IN UINT64 Address, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 (Address, (UINT16) (PciSegmentRead16 +(Address) | OrData)); } + +/** + Performs a bitwise AND of a 16-bit PCI configuration register with a +16-bit value, + followed a bitwise OR with another 16-bit value. + + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified + by AndData, performs a bitwise OR between the result of the AND + operation and the value specified by OrData, and writes the result to the 16-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentAndThenOr16 ( + IN UINT64 Address, + IN UINT16 AndData, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 (Address, (UINT16) ((PciSegmentRead16 +(Address) & AndData) | OrData)); } + +/** + Reads a 32-bit PCI configuration register. + + Reads and returns the 32-bit PCI configuration register specified by Address. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + + @return The 32-bit PCI configuration register specified by Address. + +**/ +UINT32 +EFIAPI +PciSegmentRead32 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); + + return PciRead32 (PCI_SEGMENT_TO_PCI_ADDRESS (Address)); } + +/** + Writes a 32-bit PCI configuration register. + + Writes the 32-bit PCI configuration register specified by Address with the value specified by Value. + Value is returned. This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param Value The value to write. + + @return The parameter of Value. + +**/ +UINT32 +EFIAPI +PciSegmentWrite32 ( + IN UINT64 Address, + IN UINT32 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); + + return PciWrite32 (PCI_SEGMENT_TO_PCI_ADDRESS (Address), Value); } + +/** + Performs a bitwise OR of a 32-bit PCI configuration register with a 32-bit value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified + by OrData, and writes the result to the 32-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentOr32 ( + IN UINT64 Address, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) | +OrData); } + +/** + Performs a bitwise AND of a 32-bit PCI configuration register with a +32-bit value, + followed a bitwise OR with another 32-bit value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified + by AndData, performs a bitwise OR between the result of the AND + operation and the value specified by OrData, and writes the result to the 32-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentAndThenOr32 ( + IN UINT64 Address, + IN UINT32 AndData, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 (Address, (PciSegmentRead32 (Address) & +AndData) | OrData); } +/** + Reads a range of PCI configuration registers into a caller supplied buffer. + + Reads the range of PCI configuration registers specified by + StartAddress and Size into the buffer specified by Buffer. This + function only allows the PCI configuration registers from a single + PCI function to be read. Size is returned. When possible 32-bit PCI + configuration read cycles are used to read from StartAdress to + StartAddress + Size. Due to alignment restrictions, 8-bit and 16-bit + PCI configuration read cycles may be used at the beginning and the end of the range. + + If any reserved bits in StartAddress are set, then ASSERT(). + If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). + If Size > 0 and Buffer is NULL, then ASSERT(). + + @param StartAddress The starting address that encodes the PCI Segment, Bus, Device, + Function and Register. + @param Size The size in bytes of the transfer. + @param Buffer The pointer to a buffer receiving the data read. + + @return Size + +**/ +UINTN +EFIAPI +PciSegmentReadBuffer ( + IN UINT64 StartAddress, + IN UINTN Size, + OUT VOID *Buffer + ) +{ + UINTN ReturnValue; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0); ASSERT + (((StartAddress & 0xFFF) + Size) <= 0x1000); + + if (Size == 0) { + return Size; + } + + ASSERT (Buffer != NULL); + if (Buffer == NULL) { + return 0; + } + + // + // Save Size for return + // + ReturnValue = Size; + + if ((StartAddress & BIT0) != 0) { + // + // Read a byte if StartAddress is byte aligned + // + *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress); + StartAddress += sizeof (UINT8); + Size -= sizeof (UINT8); + Buffer = (UINT8*)Buffer + 1; + } + + if (Size >= sizeof (UINT16) && (StartAddress & BIT1) != 0) { + // + // Read a word if StartAddress is word aligned + // + WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress)); + StartAddress += sizeof (UINT16); + Size -= sizeof (UINT16); + Buffer = (UINT16*)Buffer + 1; + } + + while (Size >= sizeof (UINT32)) { + // + // Read as many double words as possible + // + WriteUnaligned32 (Buffer, PciSegmentRead32 (StartAddress)); + StartAddress += sizeof (UINT32); + Size -= sizeof (UINT32); + Buffer = (UINT32*)Buffer + 1; + } + + if (Size >= sizeof (UINT16)) { + // + // Read the last remaining word if exist + // + WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress)); + StartAddress += sizeof (UINT16); + Size -= sizeof (UINT16); + Buffer = (UINT16*)Buffer + 1; + } + + if (Size >= sizeof (UINT8)) { + // + // Read the last remaining byte if exist + // + *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress); } + + return ReturnValue; +} + +/** + Copies the data in a caller supplied buffer to a specified range of +PCI + configuration space. + + Writes the range of PCI configuration registers specified by + StartAddress and Size from the buffer specified by Buffer. This + function only allows the PCI configuration registers from a single + PCI function to be written. Size is returned. When possible 32-bit + PCI configuration write cycles are used to write from StartAdress to + StartAddress + Size. Due to alignment restrictions, 8-bit and 16-bit + PCI configuration write cycles may be used at the beginning and the end of the range. + + If any reserved bits in StartAddress are set, then ASSERT(). + If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). + If Size > 0 and Buffer is NULL, then ASSERT(). + + @param StartAddress The starting address that encodes the PCI Segment, Bus, Device, + Function and Register. + @param Size The size in bytes of the transfer. + @param Buffer The pointer to a buffer containing the data to write. + + @return The parameter of Size. + +**/ +UINTN +EFIAPI +PciSegmentWriteBuffer ( + IN UINT64 StartAddress, + IN UINTN Size, + IN VOID *Buffer + ) +{ + UINTN ReturnValue; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0); ASSERT + (((StartAddress & 0xFFF) + Size) <= 0x1000); + + if (Size == 0) { + return 0; + } + + ASSERT (Buffer != NULL); + if (Buffer == NULL) { + return 0; + } + + // + // Save Size for return + // + ReturnValue = Size; + + if ((StartAddress & BIT0) != 0) { + // + // Write a byte if StartAddress is byte aligned + // + PciSegmentWrite8 (StartAddress, *(UINT8*) Buffer); + StartAddress += sizeof (UINT8); + Size -= sizeof (UINT8); + Buffer = (UINT8*) Buffer + 1; + } + + if (Size >= sizeof (UINT16) && (StartAddress & BIT1) != 0) { + // + // Write a word if StartAddress is word aligned + // + PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer)); + StartAddress += sizeof (UINT16); + Size -= sizeof (UINT16); + Buffer = (UINT16*) Buffer + 1; + } + + while (Size >= sizeof (UINT32)) { + // + // Write as many double words as possible + // + PciSegmentWrite32 (StartAddress, ReadUnaligned32 (Buffer)); + StartAddress += sizeof (UINT32); + Size -= sizeof (UINT32); + Buffer = (UINT32*) Buffer + 1; + } + + if (Size >= sizeof (UINT16)) { + // + // Write the last remaining word if exist + // + PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer)); + StartAddress += sizeof (UINT16); + Size -= sizeof (UINT16); + Buffer = (UINT16*) Buffer + 1; + } + + if (Size >= sizeof (UINT8)) { + // + // Write the last remaining byte if exist + // + PciSegmentWrite8 (StartAddress, *(UINT8*) Buffer); } + + return ReturnValue; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/BaseSiConfigBlockLib.c b/Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/BaseSiConfigBlockLib.c new file mode 100644 index 0000000000..93290d8371 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/Bas +++ eSiConfigBlockLib.c @@ -0,0 +1,87 @@ +/** @file + This file is BaseSiConfigBlockLib library is used to add config +blocks + to config block header. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include +<ConfigBlock.h> #include <Library/DebugLib.h> #include +<Library/IoLib.h> #include <Library/BaseMemoryLib.h> #include +<Library/ConfigBlockLib.h> #include <Library/SiConfigBlockLib.h> + + +/** + GetComponentConfigBlockTotalSize get config block table total size. + + @param[in] ComponentBlocks Component blocks array + @param[in] TotalBlockCount Number of blocks + + @retval Size of config block table +**/ +UINT16 +EFIAPI +GetComponentConfigBlockTotalSize ( + IN COMPONENT_BLOCK_ENTRY *ComponentBlocks, + IN UINT16 TotalBlockCount + ) +{ + UINT16 TotalBlockSize; + UINT16 BlockCount; + + TotalBlockSize = 0; + for (BlockCount = 0 ; BlockCount < TotalBlockCount; BlockCount++) { + TotalBlockSize += (UINT32) ComponentBlocks[BlockCount].Size; } + + return TotalBlockSize; +} + +/** + AddComponentConfigBlocks add all config blocks. + + @param[in] ConfigBlockTableAddress The pointer to add config blocks + @param[in] ComponentBlocks Config blocks array + @param[in] TotalBlockCount Number of blocks + + @retval EFI_SUCCESS The policy default is initialized. + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create buffer +**/ +EFI_STATUS +EFIAPI +AddComponentConfigBlocks ( + IN VOID *ConfigBlockTableAddress, + IN COMPONENT_BLOCK_ENTRY *ComponentBlocks, + IN UINT16 TotalBlockCount + ) +{ + UINT16 BlockCount; + VOID *ConfigBlockPointer; + CONFIG_BLOCK ConfigBlockBuf; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + // + // Initialize ConfigBlockPointer to NULL + // + ConfigBlockPointer = NULL; + // + // Loop to identify each config block from ComponentBlocks[] Table +and add each of them + // + for (BlockCount = 0; BlockCount < TotalBlockCount; BlockCount++) { + ZeroMem (&ConfigBlockBuf, sizeof (CONFIG_BLOCK)); + CopyMem (&(ConfigBlockBuf.Header.GuidHob.Name), ComponentBlocks[BlockCount].Guid, sizeof (EFI_GUID)); + ConfigBlockBuf.Header.GuidHob.Header.HobLength = ComponentBlocks[BlockCount].Size; + ConfigBlockBuf.Header.Revision = ComponentBlocks[BlockCount].Revision; + ConfigBlockPointer = (VOID *)&ConfigBlockBuf; + Status = AddConfigBlock ((VOID *)ConfigBlockTableAddress, (VOID *)&ConfigBlockPointer); + ASSERT_EFI_ERROR (Status); + if (ComponentBlocks[BlockCount].LoadDefault != NULL) { + ComponentBlocks[BlockCount].LoadDefault (ConfigBlockPointer); + } + } + return Status; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/BaseSiConfigBlockLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/BaseSiConfigBlockLib.inf new file mode 100644 index 0000000000..097095ef0d --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/BaseSiConfigBlockLib/Bas +++ eSiConfigBlockLib.inf @@ -0,0 +1,32 @@ +## @file +# Component description file for the BaseSiConfigBlockLib library. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = BaseSiConfigBlockLib +FILE_GUID = 6C068D0F-F48E-48CB-B369-433E507AF4A2 +VERSION_STRING = 1.0 +MODULE_TYPE = BASE +LIBRARY_CLASS = SiConfigBlockLib + + +[LibraryClasses] +DebugLib +IoLib +ConfigBlockLib + + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + + +[Sources] +BaseSiConfigBlockLib.c + + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyInitLib/PeiPostMemSiliconPolicyInitLib.c b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyInitLib/PeiPostMemSiliconPolicyInitLib.c new file mode 100644 index 0000000000..a9d6c7e265 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyI +++ nitLib/PeiPostMemSiliconPolicyInitLib.c @@ -0,0 +1,94 @@ +/** @file + This library initialize Silicon Policy for PostMemory. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include +<Ppi/SiPolicy.h> #include <Ppi/PeiSiDefaultPolicy.h> #include +<Library/PcdLib.h> #include <Library/DebugLib.h> #include +<Library/PeiServicesLib.h> #include <Library/SiPolicyLib.h> + +/** + Performs silicon post-mem policy initialization. + + The returned data must be used as input data for + SiliconPolicyDonePostMem (), and SiliconPolicyUpdateLib.SiliconPolicyUpdatePostMem (). + + @param[in, out] Policy Pointer to policy. + @return the initialized policy. +**/ +VOID * +EFIAPI +SiliconPolicyInitPostMem ( + IN OUT VOID *Policy + ) +{ + EFI_STATUS Status; + SI_POLICY_PPI *SiPolicyPpi; + PEI_SI_DEFAULT_POLICY_INIT_PPI *PeiSiDefaultPolicyInitPpi; + + DEBUG ((DEBUG_INFO, "Silicon PEI Policy Initialization Start in + Post-Memory...\n")); + + ASSERT (Policy == NULL); + SiPolicyPpi = NULL; + PeiSiDefaultPolicyInitPpi = NULL; + + // + // Locate Policy init PPI to install default silicon policy // + Status = PeiServicesLocatePpi ( + &gSiDefaultPolicyInitPpiGuid, + 0, + NULL, + (VOID **) &PeiSiDefaultPolicyInitPpi + ); + ASSERT_EFI_ERROR (Status); + if (PeiSiDefaultPolicyInitPpi != NULL) { + Status = PeiSiDefaultPolicyInitPpi->PeiPolicyInit (); + ASSERT_EFI_ERROR (Status); + if (Status == EFI_SUCCESS) { + Status = PeiServicesLocatePpi ( + &gSiPolicyPpiGuid, + 0, + NULL, + (VOID **) &SiPolicyPpi + ); + ASSERT_EFI_ERROR (Status); + } + } + + if (SiPolicyPpi == NULL) { + DEBUG ((DEBUG_ERROR, "Fail to create default policy!\n")); + return NULL; + } + + + return SiPolicyPpi; +} + +/** + The silicon post-mem policy is finalized. + Silicon code can do initialization based upon the policy data. + + The input Policy must be returned by SiliconPolicyInitPostMem(). + + @param[in] Policy Pointer to policy. + @retval RETURN_SUCCESS The policy is handled consumed by silicon code. +**/ +RETURN_STATUS +EFIAPI +SiliconPolicyDonePostMem ( + IN VOID *Policy + ) +{ + EFI_STATUS Status; + + Status = SiInstallPolicyReadyPpi (); + ASSERT_EFI_ERROR (Status); + DEBUG ((DEBUG_INFO, "Silicon PEI Policy Initialization Done in + Post-Memory\n")); + + return Status; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyInitLib/PeiPostMemSiliconPolicyInitLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyInitLib/PeiPostMemSiliconPolicyInitLib.inf new file mode 100644 index 0000000000..b13d63d337 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPostMemSiliconPolicyI +++ nitLib/PeiPostMemSiliconPolicyInitLib.inf @@ -0,0 +1,36 @@ +## @file +# Component information file for Silicon Policy Init Library # This +library implements Silicon Policy Initialization for PostMemory. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PeiPostMemSiliconPolicyInitLib + FILE_GUID = 20B51FFB-93D3-4546-9F13-2C91AEEF9212 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = SiliconPolicyInitLib + +[LibraryClasses] + BaseLib + PcdLib + PeiServicesLib + DebugLib + SiPolicyLib + +[Packages] + MdePkg/MdePkg.dec + AlderlakeSiliconPkg/SiPkg.dec + +[Sources] + PeiPostMemSiliconPolicyInitLib.c + +[Ppis] + gSiDefaultPolicyInitPpiGuid + gEfiPeiMpServicesPpiGuid + +[Depex] + gSiDefaultPolicyInitPpiGuid diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyInitLib/PeiPreMemSiliconPolicyInitLib.c b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyInitLib/PeiPreMemSiliconPolicyInitLib.c new file mode 100644 index 0000000000..74fb47a73d --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyIn +++ itLib/PeiPreMemSiliconPolicyInitLib.c @@ -0,0 +1,98 @@ +/** @file + This library initialize Silicon Policy for PreMemory. + + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include +<Ppi/SiPolicy.h> #include <Ppi/PeiPreMemSiDefaultPolicy.h> #include +<Library/DebugLib.h> #include <Library/PeiServicesLib.h> #include +<Library/SiPolicyLib.h> + + +/** + Performs silicon pre-mem policy initialization. + + The returned data must be used as input data for + SiliconPolicyDonePreMem (), and SiliconPolicyUpdateLib.SiliconPolicyUpdatePreMem (). + + @param[in, out] Policy Pointer to policy. + @return the initialized policy. +**/ +VOID * +EFIAPI +SiliconPolicyInitPreMem ( + IN OUT VOID *Policy + ) +{ + EFI_STATUS Status; + SI_PREMEM_POLICY_PPI *SiPreMemPolicyPpi; + PEI_PREMEM_SI_DEFAULT_POLICY_INIT_PPI +*PeiPreMemSiDefaultPolicyInitPpi; + + DEBUG ((DEBUG_INFO, "Silicon PEI Policy Initialization Start in + Pre-Memory...\n")); + + ASSERT (Policy == NULL); + SiPreMemPolicyPpi = NULL; + PeiPreMemSiDefaultPolicyInitPpi = NULL; + + // + // Locate Policy init PPI to install default silicon policy // + Status = PeiServicesLocatePpi ( + &gSiPreMemDefaultPolicyInitPpiGuid, + 0, + NULL, + (VOID **) &PeiPreMemSiDefaultPolicyInitPpi + ); + ASSERT_EFI_ERROR (Status); + if (PeiPreMemSiDefaultPolicyInitPpi != NULL) { + Status = PeiPreMemSiDefaultPolicyInitPpi->PeiPreMemPolicyInit (); + ASSERT_EFI_ERROR (Status); + if (Status == EFI_SUCCESS) { + Status = PeiServicesLocatePpi ( + &gSiPreMemPolicyPpiGuid, + 0, + NULL, + (VOID **) &SiPreMemPolicyPpi + ); + ASSERT_EFI_ERROR (Status); + } + } + + if (SiPreMemPolicyPpi == NULL) { + DEBUG ((DEBUG_ERROR, "Fail to create default policy!\n")); + return NULL; + } + + return SiPreMemPolicyPpi; +} + +/** + The silicon pre-mem policy is finalized. + Silicon code can do initialization based upon the policy data. + + The input Policy must be returned by SiliconPolicyInitPreMem(). + + @param[in] Policy Pointer to policy. + @retval RETURN_SUCCESS The policy is handled consumed by silicon code. +**/ +RETURN_STATUS +EFIAPI +SiliconPolicyDonePreMem ( + IN VOID *Policy + ) +{ + EFI_STATUS Status; + // + // Install PreMem Policy Ready PPI + // While installs PreMemPolicyReadyPpi, RC assumes the Policy is +ready and finalized. So please + // update and override any setting before calling this function. + // + Status = SiPreMemInstallPolicyReadyPpi (); + ASSERT_EFI_ERROR (Status); + + DEBUG ((DEBUG_INFO, "Silicon PEI Policy Initialization Done in + Pre-Memory\n")); + + return Status; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyInitLib/PeiPreMemSiliconPolicyInitLib.inf b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyInitLib/PeiPreMemSiliconPolicyInitLib.inf new file mode 100644 index 0000000000..d5ce714ce5 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Library/PeiPreMemSiliconPolicyIn +++ itLib/PeiPreMemSiliconPolicyInitLib.inf @@ -0,0 +1,36 @@ +## @file +# Component information file for Silicon Policy Init Library # This +library implements Silicon Policy Initialization for PreMemory. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PeiPreMemSiliconPolicyInitLib + FILE_GUID = 1FB4B175-0BB6-4137-A4AC-EA48FCE83862 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = SiliconPolicyInitLib + +[LibraryClasses] + BaseLib + PeiServicesLib + DebugLib + SiPolicyLib + +[Packages] + MdePkg/MdePkg.dec + AlderlakeSiliconPkg/SiPkg.dec + +[Sources] + PeiPreMemSiliconPolicyInitLib.c + +[Pcd] + +[Ppis] + gSiPreMemDefaultPolicyInitPpiGuid + +[Depex] + gSiPreMemDefaultPolicyInitPpiGuid -- 2.36.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107779): https://edk2.groups.io/g/devel/message/107779 Mute This Topic: https://groups.io/mt/100551000/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2023-08-16 2:46 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-08-04 17:37 [edk2-devel] [PATCH v2 1/7] AlderlakeSiliconPkg: Add package and library instances Saloni Kasbekar 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 2/7] AlderlakeSiliconPkg: Add Cpu modules Saloni Kasbekar 2023-08-16 2:45 ` Chuang, Rosen 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 3/7] AlderlakeSiliconPkg/Pch: Add include headers Saloni Kasbekar 2023-08-16 2:44 ` Chuang, Rosen 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 4/7] AlderlakeSiliconPkg/Pch: Add libraries Saloni Kasbekar 2023-08-16 2:42 ` Chuang, Rosen 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 5/7] AlderlakeSiliconPkg/Pch: Add drivers Saloni Kasbekar 2023-08-16 2:46 ` Chuang, Rosen 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 6/7] AlderlakeSiliconPkg/SystemAgent: Add include headers Saloni Kasbekar 2023-08-16 2:45 ` Chuang, Rosen 2023-08-04 17:37 ` [edk2-devel] [PATCH v2 7/7] AlderlakeSiliconPkg/SystemAgent: Add library and driver modules Saloni Kasbekar 2023-08-16 2:45 ` Chuang, Rosen 2023-08-16 2:42 ` [edk2-devel] [PATCH v2 1/7] AlderlakeSiliconPkg: Add package and library instances Chuang, Rosen
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox