summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DynamicTablesPkg/DynamicTables.dsc.inc3
-rw-r--r--DynamicTablesPkg/Include/AcpiTableGenerator.h3
-rw-r--r--DynamicTablesPkg/Include/ArmNameSpaceObjects.h95
-rw-r--r--DynamicTablesPkg/Include/ConfigurationManagerObject.h22
-rw-r--r--DynamicTablesPkg/Include/TableGenerator.h3
-rw-r--r--DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/AcpiPpttLibArm.inf29
-rw-r--r--DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.c1528
-rw-r--r--DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.h190
8 files changed, 1867 insertions, 6 deletions
diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc
index 8ea5b0a7d9..142832b9fa 100644
--- a/DynamicTablesPkg/DynamicTables.dsc.inc
+++ b/DynamicTablesPkg/DynamicTables.dsc.inc
@@ -1,7 +1,7 @@
## @file
# Dsc include file for Dynamic Tables Framework.
#
-# Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.<BR>
+# Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -27,6 +27,7 @@
NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/AcpiIortLibArm.inf
NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/AcpiMadtLibArm.inf
NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/AcpiMcfgLibArm.inf
+ NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/AcpiPpttLibArm.inf
NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/AcpiRawLibArm.inf
NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/AcpiSpcrLibArm.inf
}
diff --git a/DynamicTablesPkg/Include/AcpiTableGenerator.h b/DynamicTablesPkg/Include/AcpiTableGenerator.h
index c4ef05965f..7d6d344227 100644
--- a/DynamicTablesPkg/Include/AcpiTableGenerator.h
+++ b/DynamicTablesPkg/Include/AcpiTableGenerator.h
@@ -51,6 +51,8 @@ The Dynamic Tables Framework implements the following ACPI table generators:
from the Configuration Manager and builds the MCFG table.
- IORT : The IORT generator collates the IO Topology information from the
Configuration Manager and builds the IORT table.
+ - PPTT : The PPTT generator collates the processor topology information from
+ the Configuration Manager and builds the PPTT table.
*/
/** The ACPI_TABLE_GENERATOR_ID type describes ACPI table generator ID.
@@ -72,6 +74,7 @@ typedef enum StdAcpiTableId {
EStdAcpiTableIdSpcr, ///< SPCR Generator
EStdAcpiTableIdMcfg, ///< MCFG Generator
EStdAcpiTableIdIort, ///< IORT Generator
+ EStdAcpiTableIdPptt, ///< PPTT Generator
EStdAcpiTableIdMax
} ESTD_ACPI_TABLE_ID;
diff --git a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
index d9dcca12db..19c47ef655 100644
--- a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
+++ b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
@@ -48,6 +48,10 @@ typedef enum ArmObjectID {
EArmObjGicItsIdentifierArray, ///< 24 - GIC ITS Identifier Array
EArmObjIdMappingArray, ///< 25 - ID Mapping Array
EArmObjSmmuInterruptArray, ///< 26 - SMMU Interrupt Array
+ EArmObjProcHierarchyInfo, ///< 27 - Processor Hierarchy Info
+ EArmObjCacheInfo, ///< 28 - Cache Info
+ EArmObjProcNodeIdInfo, ///< 29 - Processor Hierarchy Node ID Info
+ EArmObjCmRef, ///< 30 - CM Object Reference
EArmObjMax
} EARM_OBJECT_ID;
@@ -628,6 +632,97 @@ typedef struct CmArmSmmuInterrupt {
UINT32 Flags;
} CM_ARM_SMMU_INTERRUPT;
+/** A structure that describes the Processor Hierarchy Node (Type 0) in PPTT
+
+ ID: EArmObjProcHierarchyInfo
+*/
+typedef struct CmArmProcHierarchyInfo {
+ /// A unique token used to identify this object
+ CM_OBJECT_TOKEN Token;
+ /// Processor structure flags (ACPI 6.3 - January 2019, PPTT, Table 5-155)
+ UINT32 Flags;
+ /// Token for the parent CM_ARM_PROC_HIERARCHY_INFO object in the processor
+ /// topology. A value of CM_NULL_TOKEN means this node has no parent.
+ CM_OBJECT_TOKEN ParentToken;
+ /// Token of the associated CM_ARM_GICC_INFO object which has the
+ /// corresponding ACPI Processor ID. A value of CM_NULL_TOKEN means this
+ /// node represents a group of associated processors and it does not have an
+ /// associated GIC CPU interface.
+ CM_OBJECT_TOKEN GicCToken;
+ /// Number of resources private to this Node
+ UINT32 NoOfPrivateResources;
+ /// Token of the array which contains references to the resources private to
+ /// this CM_ARM_PROC_HIERARCHY_INFO instance. This field is ignored if
+ /// the NoOfPrivateResources is 0, in which case it is recomended to set
+ /// this field to CM_NULL_TOKEN.
+ CM_OBJECT_TOKEN PrivateResourcesArrayToken;
+} CM_ARM_PROC_HIERARCHY_INFO;
+
+/** A structure that describes the Cache Type Structure (Type 1) in PPTT
+
+ ID: EArmObjCacheInfo
+*/
+typedef struct CmArmCacheInfo {
+ /// A unique token used to identify this object
+ CM_OBJECT_TOKEN Token;
+ /// Reference token for the next level of cache that is private to the same
+ /// CM_ARM_PROC_HIERARCHY_INFO instance. A value of CM_NULL_TOKEN means this
+ /// entry represents the last cache level appropriate to the processor
+ /// hierarchy node structures using this entry.
+ CM_OBJECT_TOKEN NextLevelOfCacheToken;
+ /// Size of the cache in bytes
+ UINT32 Size;
+ /// Number of sets in the cache
+ UINT32 NumberOfSets;
+ /// Integer number of ways. The maximum associativity supported by
+ /// ACPI Cache type structure is limited to MAX_UINT8. However,
+ /// the maximum number of ways supported by the architecture is
+ /// PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX. Therfore this field
+ /// is 32-bit wide.
+ UINT32 Associativity;
+ /// Cache attributes (ACPI 6.3 - January 2019, PPTT, Table 5-156)
+ UINT8 Attributes;
+ /// Line size in bytes
+ UINT16 LineSize;
+} CM_ARM_CACHE_INFO;
+
+/** A structure that describes the ID Structure (Type 2) in PPTT
+
+ ID: EArmObjProcNodeIdInfo
+*/
+typedef struct CmArmProcNodeIdInfo {
+ /// A unique token used to identify this object
+ CM_OBJECT_TOKEN Token;
+ // Vendor ID (as described in ACPI ID registry)
+ UINT32 VendorId;
+ /// First level unique node ID
+ UINT64 Level1Id;
+ /// Second level unique node ID
+ UINT64 Level2Id;
+ /// Major revision of the node
+ UINT16 MajorRev;
+ /// Minor revision of the node
+ UINT16 MinorRev;
+ /// Spin revision of the node
+ UINT16 SpinRev;
+} CM_ARM_PROC_NODE_ID_INFO;
+
+/** A structure that describes a reference to another Configuration Manager
+ object.
+
+ This is useful for creating an array of reference tokens. The framework
+ can then query the configuration manager for these arrays using the
+ object ID EArmObjCmRef.
+
+ This can be used is to represent one-to-many relationships between objects.
+
+ ID: EArmObjCmRef
+*/
+typedef struct CmArmObjRef {
+ /// Token of the CM object being referenced
+ CM_OBJECT_TOKEN ReferenceToken;
+} CM_ARM_OBJ_REF;
+
#pragma pack()
#endif // ARM_NAMESPACE_OBJECTS_H_
diff --git a/DynamicTablesPkg/Include/ConfigurationManagerObject.h b/DynamicTablesPkg/Include/ConfigurationManagerObject.h
index 3bd4273d25..b0d3e709ec 100644
--- a/DynamicTablesPkg/Include/ConfigurationManagerObject.h
+++ b/DynamicTablesPkg/Include/ConfigurationManagerObject.h
@@ -63,10 +63,24 @@ Object ID's in the ARM Namespace:
10 - Serial Debug Port Info
11 - Generic Timer Info
12 - Platform GT Block Info
- 13 - Platform Generic Watchdog
- 14 - PCI Configuration Space Info
- 15 - Hypervisor Vendor Id
- 16 - Fixed feature flags for FADT
+ 13 - Generic Timer Block Frame Info
+ 14 - Platform Generic Watchdog
+ 15 - PCI Configuration Space Info
+ 16 - Hypervisor Vendor Id
+ 17 - Fixed feature flags for FADT
+ 18 - ITS Group
+ 19 - Named Component
+ 20 - Root Complex
+ 21 - SMMUv1 or SMMUv2
+ 22 - SMMUv3
+ 23 - PMCG
+ 24 - GIC ITS Identifier Array
+ 25 - ID Mapping Array
+ 26 - SMMU Interrupt Array
+ 27 - Processor Hierarchy Info
+ 28 - Cache Info
+ 29 - Processor Hierarchy Node ID Info
+ 30 - CM Object Reference
*/
typedef UINT32 CM_OBJECT_ID;
diff --git a/DynamicTablesPkg/Include/TableGenerator.h b/DynamicTablesPkg/Include/TableGenerator.h
index d39868a41c..da6434a48b 100644
--- a/DynamicTablesPkg/Include/TableGenerator.h
+++ b/DynamicTablesPkg/Include/TableGenerator.h
@@ -1,6 +1,6 @@
/** @file
- Copyright (c) 2017, ARM Limited. All rights reserved.
+ Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -55,6 +55,7 @@ _______________________________________________________________________________
7 - DBG2
8 - SPCR
9 - MCFG
+ 10 - PPTT
Standard SMBIOS Table IDs:
0 - Reserved
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/AcpiPpttLibArm.inf b/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/AcpiPpttLibArm.inf
new file mode 100644
index 0000000000..3cb13d7d8f
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/AcpiPpttLibArm.inf
@@ -0,0 +1,29 @@
+## @file
+# PPTT Table Generator
+#
+# Copyright (c) 2019, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = AcpiPpttLibArm
+ FILE_GUID = FA102D52-5A92-4F95-A097-1D53F9CF5959
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_DRIVER
+ LIBRARY_CLASS = NULL|DXE_DRIVER
+ CONSTRUCTOR = AcpiPpttLibConstructor
+ DESTRUCTOR = AcpiPpttLibDestructor
+
+[Sources]
+ PpttGenerator.c
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ DynamicTablesPkg/DynamicTablesPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.c b/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.c
new file mode 100644
index 0000000000..c8713dec62
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.c
@@ -0,0 +1,1528 @@
+/** @file
+ PPTT Table Generator
+
+ Copyright (c) 2019, ARM Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - ACPI 6.3 Specification, January 2019
+
+ @par Glossary:
+ - Cm or CM - Configuration Manager
+ - Obj or OBJ - Object
+**/
+
+#include <Library/AcpiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/AcpiTable.h>
+
+// Module specific include files.
+#include <AcpiTableGenerator.h>
+#include <ConfigurationManagerObject.h>
+#include <ConfigurationManagerHelper.h>
+#include <Library/TableHelperLib.h>
+#include <Protocol/ConfigurationManagerProtocol.h>
+
+#include "PpttGenerator.h"
+
+/**
+ ARM standard PPTT Generator
+
+ Requirements:
+ The following Configuration Manager Object(s) are used by this Generator:
+ - EArmObjProcHierarchyInfo (REQUIRED)
+ - EArmObjCacheInfo
+ - EArmObjProcNodeIdInfo
+ - EArmObjCmRef
+ - EArmObjGicCInfo (REQUIRED)
+*/
+
+/**
+ This macro expands to a function that retrieves the Processor Hierarchy
+ information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjProcHierarchyInfo,
+ CM_ARM_PROC_HIERARCHY_INFO
+ );
+
+/**
+ This macro expands to a function that retrieves the cache information
+ from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjCacheInfo,
+ CM_ARM_CACHE_INFO
+ );
+
+/**
+ This macro expands to a function that retrieves the ID information for
+ Processor Hierarchy Nodes from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjProcNodeIdInfo,
+ CM_ARM_PROC_NODE_ID_INFO
+ );
+
+/**
+ This macro expands to a function that retrieves the cross-CM-object-
+ reference information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjCmRef,
+ CM_ARM_OBJ_REF
+ );
+
+/**
+ This macro expands to a function that retrieves the GIC CPU interface
+ information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjGicCInfo,
+ CM_ARM_GICC_INFO
+ );
+
+/**
+ Returns the size of the PPTT Processor Hierarchy Node (Type 0) given a
+ Processor Hierarchy Info CM object.
+
+ @param [in] Node Pointer to Processor Hierarchy Info CM object which
+ represents the Processor Hierarchy Node to be generated.
+
+ @retval Size of the Processor Hierarchy Node in bytes.
+**/
+STATIC
+UINT32
+GetProcHierarchyNodeSize (
+ IN CONST CM_ARM_PROC_HIERARCHY_INFO * Node
+ )
+{
+ ASSERT (Node != NULL);
+
+ // <size of Processor Hierarchy Node> + <size of Private Resources array>
+ return sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR) +
+ (Node->NoOfPrivateResources * sizeof (UINT32));
+}
+
+/**
+ This macro expands to a function that retrieves the amount of memory required
+ to store the Processor Hierarchy Nodes (Type 0) and updates the Node Indexer.
+*/
+GET_SIZE_OF_PPTT_STRUCTS (
+ ProcHierarchyNodes,
+ GetProcHierarchyNodeSize (NodesToIndex),
+ CM_ARM_PROC_HIERARCHY_INFO
+ );
+
+/**
+ This macro expands to a function that retrieves the amount of memory required
+ to store the Cache Type Structures (Type 1) and updates the Node Indexer.
+*/
+GET_SIZE_OF_PPTT_STRUCTS (
+ CacheTypeStructs,
+ sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE),
+ CM_ARM_CACHE_INFO
+ );
+
+/** This macro expands to a function that retrieves the amount of memory
+ required to store the ID Structures (Type 2) and updates the Node Indexer.
+*/
+GET_SIZE_OF_PPTT_STRUCTS (
+ IdStructs,
+ sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_ID),
+ CM_ARM_PROC_NODE_ID_INFO
+ );
+
+/**
+ Search the Node Indexer and return the indexed PPTT node with the given
+ Token.
+
+ @param [in] NodeIndexer Pointer to the Node Indexer array.
+ @param [in] NodeCount Number of elements in Node Indexer.
+ @param [in] SearchToken Token used for Node Indexer lookup.
+ @param [out] IndexedNodeFound Pointer to the Node Indexer array element
+ with the given Token.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_NOT_FOUND No element with a matching token was
+ found in the Node Indexer array.
+**/
+STATIC
+EFI_STATUS
+GetPpttNodeReferencedByToken (
+ IN PPTT_NODE_INDEXER * NodeIndexer,
+ IN UINT32 NodeCount,
+ IN CONST CM_OBJECT_TOKEN SearchToken,
+ OUT PPTT_NODE_INDEXER ** IndexedNodeFound
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (NodeIndexer != NULL);
+
+ DEBUG ((
+ DEBUG_INFO,
+ "PPTT: Node Indexer: SearchToken = %p\n",
+ SearchToken
+ ));
+
+ while (NodeCount-- != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "PPTT: Node Indexer: NodeIndexer->Token = %p. Offset = %d\n",
+ NodeIndexer->Token,
+ NodeIndexer->Offset
+ ));
+
+ if (NodeIndexer->Token == SearchToken) {
+ *IndexedNodeFound = NodeIndexer;
+ Status = EFI_SUCCESS;
+ DEBUG ((
+ DEBUG_INFO,
+ "PPTT: Node Indexer: Token = %p. Found, Status = %r\n",
+ SearchToken,
+ Status
+ ));
+ return Status;
+ }
+ NodeIndexer++;
+ }
+
+ Status = EFI_NOT_FOUND;
+ DEBUG ((
+ DEBUG_ERROR,
+ "PPTT: Node Indexer: SearchToken = %p. Status = %r\n",
+ SearchToken,
+ Status
+ ));
+
+ return Status;
+}
+
+/**
+ Detect cycles in the processor and cache topology graph represented in
+ the PPTT table.
+
+ @param [in] Generator Pointer to the PPTT Generator.
+
+ @retval EFI_SUCCESS There are no cyclic references in the graph.
+ @retval EFI_INVALID_PARAMETER Processor or cache references form a cycle.
+**/
+STATIC
+EFI_STATUS
+DetectCyclesInTopology (
+ IN CONST ACPI_PPTT_GENERATOR * CONST Generator
+ )
+{
+ EFI_STATUS Status;
+ PPTT_NODE_INDEXER * Iterator;
+ PPTT_NODE_INDEXER * CycleDetector;
+ UINT32 NodesRemaining;
+
+ ASSERT (Generator != NULL);
+
+ Iterator = Generator->NodeIndexer;
+ NodesRemaining = Generator->ProcTopologyStructCount;
+
+ while (NodesRemaining != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "INFO: PPTT: Cycle detection for element with index %d\n",
+ Generator->ProcTopologyStructCount - NodesRemaining
+ ));
+
+ CycleDetector = Iterator;
+
+ // Walk the topology tree
+ while (CycleDetector->TopologyParent != NULL) {
+ DEBUG ((
+ DEBUG_INFO,
+ "INFO: PPTT: %p -> %p\n",
+ CycleDetector->Token,
+ CycleDetector->TopologyParent->Token
+ ));
+
+ // Check if we have already visited this node
+ if (CycleDetector->CycleDetectionStamp == NodesRemaining) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Cycle in processor and cache topology detected for " \
+ "a chain of references originating from a node with: Token = %p " \
+ "Status = %r\n",
+ Iterator->Token,
+ Status
+ ));
+ return Status;
+ }
+
+ // Stamp the visited node
+ CycleDetector->CycleDetectionStamp = NodesRemaining;
+ CycleDetector = CycleDetector->TopologyParent;
+ } // Continue topology tree walk
+
+ Iterator++;
+ NodesRemaining--;
+ } // Next Node Indexer
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update the array of private resources for a given Processor Hierarchy Node.
+
+ @param [in] Generator Pointer to the PPTT Generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] PrivResArray Pointer to the array of private resources.
+ @param [in] PrivResCount Number of private resources.
+ @param [in] PrivResArrayToken Reference Token for the CM_ARM_OBJ_REF
+ array describing node's private resources.
+
+ @retval EFI_SUCCESS Array updated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND A private resource was not found.
+**/
+STATIC
+EFI_STATUS
+AddPrivateResources (
+ IN CONST ACPI_PPTT_GENERATOR * CONST Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN UINT32 * PrivResArray,
+ IN UINT32 PrivResCount,
+ IN CONST CM_OBJECT_TOKEN PrivResArrayToken
+ )
+{
+ EFI_STATUS Status;
+ CM_ARM_OBJ_REF * CmObjRefs;
+ UINT32 CmObjRefCount;
+ PPTT_NODE_INDEXER * PpttNodeFound;
+
+ ASSERT (
+ (Generator != NULL) &&
+ (CfgMgrProtocol != NULL) &&
+ (PrivResArray != NULL) &&
+ (PrivResCount != 0)
+ );
+
+ // Validate input arguments
+ if (PrivResArrayToken == CM_NULL_TOKEN) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: The number of private resources is %d while " \
+ "PrivResToken = CM_NULL_TOKEN. Status = %r\n",
+ PrivResCount,
+ Status
+ ));
+ return Status;
+ }
+
+ CmObjRefCount = 0;
+ // Get the CM Object References
+ Status = GetEArmObjCmRef (
+ CfgMgrProtocol,
+ PrivResArrayToken,
+ &CmObjRefs,
+ &CmObjRefCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get CM Object References. " \
+ "PrivResToken = %p. Status = %r\n",
+ PrivResArrayToken,
+ Status
+ ));
+ return Status;
+ }
+
+ if (CmObjRefCount != PrivResCount) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: The number of CM Object References retrieved and the " \
+ "number of private resources don't match. CmObjRefCount = %d. " \
+ "PrivResourceCount = %d. PrivResToken = %p. Status = %r\n",
+ CmObjRefCount,
+ PrivResCount,
+ PrivResArrayToken,
+ Status
+ ));
+ return Status;
+ }
+
+ while (PrivResCount-- != 0) {
+ if (CmObjRefs->ReferenceToken == CM_NULL_TOKEN) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: CM_NULL_TOKEN provided as reference token for a " \
+ "private resource. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // The Node indexer has the Processor hierarchy nodes at the begining
+ // followed by the cache structs and Id structs. Therefore we can
+ // skip the Processor hierarchy nodes in the node indexer search.
+ Status = GetPpttNodeReferencedByToken (
+ Generator->CacheStructIndexedList,
+ (Generator->ProcTopologyStructCount -
+ Generator->ProcHierarchyNodeCount),
+ CmObjRefs->ReferenceToken,
+ &PpttNodeFound
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get a private resource with Token = %p from " \
+ "Node Indexer. Status = %r\n",
+ CmObjRefs->ReferenceToken,
+ Status
+ ));
+ return Status;
+ }
+
+ // Update the offset of the private resources in the Processor
+ // Hierarchy Node structure
+ *(PrivResArray++) = PpttNodeFound->Offset;
+ CmObjRefs++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Function to test if two indexed Processor Hierarchy Info objects map to the
+ same GIC CPU Interface Info object.
+
+ This is a callback function that can be invoked by FindDuplicateValue ().
+
+ @param [in] Object1 Pointer to the first indexed Processor Hierarchy
+ Info object.
+ @param [in] Object2 Pointer to the second indexed Processor Hierarchy
+ Info object.
+ @param [in] Index1 Index of Object1 to be displayed for debugging
+ purposes.
+ @param [in] Index2 Index of Object2 to be displayed for debugging
+ purposes.
+
+ @retval TRUE Object1 and Object2 have the same GicCToken.
+ @retval FALSE Object1 and Object2 have different GicCTokens.
+**/
+BOOLEAN
+EFIAPI
+IsGicCTokenEqual (
+ IN CONST VOID * Object1,
+ IN CONST VOID * Object2,
+ IN UINTN Index1,
+ IN UINTN Index2
+ )
+{
+ PPTT_NODE_INDEXER * IndexedObject1;
+ PPTT_NODE_INDEXER * IndexedObject2;
+ CM_ARM_PROC_HIERARCHY_INFO * ProcNode1;
+ CM_ARM_PROC_HIERARCHY_INFO * ProcNode2;
+
+ ASSERT (
+ (Object1 != NULL) &&
+ (Object2 != NULL)
+ );
+
+ IndexedObject1 = (PPTT_NODE_INDEXER*)Object1;
+ IndexedObject2 = (PPTT_NODE_INDEXER*)Object2;
+ ProcNode1 = (CM_ARM_PROC_HIERARCHY_INFO*)IndexedObject1->Object;
+ ProcNode2 = (CM_ARM_PROC_HIERARCHY_INFO*)IndexedObject2->Object;
+
+ if (IS_ACPI_PROC_ID_VALID (ProcNode1) &&
+ IS_ACPI_PROC_ID_VALID (ProcNode2) &&
+ (ProcNode1->GicCToken != CM_NULL_TOKEN) &&
+ (ProcNode2->GicCToken != CM_NULL_TOKEN) &&
+ (ProcNode1->GicCToken == ProcNode2->GicCToken)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Two Processor Hierarchy Info objects (%d and %d) map to " \
+ "the same GICC Info object. ACPI Processor IDs are not unique. " \
+ "GicCToken = %p.\n",
+ Index1,
+ IndexedObject1->Token,
+ Index2,
+ ProcNode1->GicCToken
+ ));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Update the Processor Hierarchy Node (Type 0) information.
+
+ This function populates the Processor Hierarchy Nodes with information from
+ the Configuration Manager and adds this information to the PPTT table.
+
+ @param [in] Generator Pointer to the PPTT Generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Pptt Pointer to PPTT table structure.
+ @param [in] NodesStartOffset Offset from the start of PPTT table to the
+ start of Processor Hierarchy Nodes.
+
+ @retval EFI_SUCCESS Node updated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object was not found.
+**/
+STATIC
+EFI_STATUS
+AddProcHierarchyNodes (
+ IN CONST ACPI_PPTT_GENERATOR * CONST Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER * Pptt,
+ IN CONST UINT32 NodesStartOffset
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR * ProcStruct;
+ UINT32 * PrivateResources;
+ BOOLEAN IsGicCTokenDuplicated;
+
+ CM_ARM_GICC_INFO * GicCInfoList;
+ UINT32 GicCInfoCount;
+ UINT32 UniqueGicCRefCount;
+
+ PPTT_NODE_INDEXER * PpttNodeFound;
+ CM_ARM_PROC_HIERARCHY_INFO * ProcInfoNode;
+
+ PPTT_NODE_INDEXER * ProcNodeIterator;
+ UINT32 NodeCount;
+
+ ASSERT (
+ (Generator != NULL) &&
+ (CfgMgrProtocol != NULL) &&
+ (Pptt != NULL)
+ );
+
+ ProcStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR*)((UINT8*)Pptt +
+ NodesStartOffset);
+
+ ProcNodeIterator = Generator->ProcHierarchyNodeIndexedList;
+ NodeCount = Generator->ProcHierarchyNodeCount;
+
+ // Check if every GICC Object is referenced by onlu one Proc Node
+ IsGicCTokenDuplicated = FindDuplicateValue (
+ ProcNodeIterator,
+ NodeCount,
+ sizeof (PPTT_NODE_INDEXER),
+ IsGicCTokenEqual
+ );
+ // Duplicate GIC CPU Interface Token was found so two PPTT Processor Hierarchy
+ // Nodes map to the same MADT GICC structure
+ if (IsGicCTokenDuplicated) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UniqueGicCRefCount = 0;
+
+ while (NodeCount-- != 0) {
+ ProcInfoNode = (CM_ARM_PROC_HIERARCHY_INFO*)ProcNodeIterator->Object;
+
+ // Check if the private resource count is within the size limit
+ // imposed on the Processor Hierarchy node by the specification.
+ // Note: The length field is 8 bit wide while the number of private
+ // resource field is 32 bit wide.
+ if ((sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR) +
+ (ProcInfoNode->NoOfPrivateResources * sizeof (UINT32))) > MAX_UINT8) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Too many private resources. Count = %d. " \
+ "Maximum supported Processor Node size exceeded. " \
+ "Token = %p. Status = %r\n",
+ ProcInfoNode->NoOfPrivateResources,
+ ProcInfoNode->ParentToken,
+ Status
+ ));
+ return Status;
+ }
+
+ // Populate the node header
+ ProcStruct->Type = EFI_ACPI_6_3_PPTT_TYPE_PROCESSOR;
+ ProcStruct->Length = GetProcHierarchyNodeSize (ProcInfoNode);
+ ProcStruct->Reserved[0] = EFI_ACPI_RESERVED_BYTE;
+ ProcStruct->Reserved[1] = EFI_ACPI_RESERVED_BYTE;
+
+ // Populate the flags
+ ProcStruct->Flags.PhysicalPackage = ProcInfoNode->Flags & BIT0;
+ ProcStruct->Flags.AcpiProcessorIdValid = (ProcInfoNode->Flags & BIT1) >> 1;
+ ProcStruct->Flags.ProcessorIsAThread = (ProcInfoNode->Flags & BIT2) >> 2;
+ ProcStruct->Flags.NodeIsALeaf = (ProcInfoNode->Flags & BIT3) >> 3;
+ ProcStruct->Flags.IdenticalImplementation =
+ (ProcInfoNode->Flags & BIT4) >> 4;
+ ProcStruct->Flags.Reserved = 0;
+
+ // Populate the parent reference
+ if (ProcInfoNode->ParentToken == CM_NULL_TOKEN) {
+ ProcStruct->Parent = 0;
+ } else {
+ Status = GetPpttNodeReferencedByToken (
+ Generator->ProcHierarchyNodeIndexedList,
+ Generator->ProcHierarchyNodeCount,
+ ProcInfoNode->ParentToken,
+ &PpttNodeFound
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get parent processor hierarchy node " \
+ "reference. Token = %p, Status = %r\n",
+ ProcInfoNode->ParentToken,
+ ProcInfoNode->Token,
+ Status
+ ));
+ return Status;
+ }
+
+ // Test if the reference is to a 'leaf' node
+ if (IS_PROC_NODE_LEAF (
+ ((CM_ARM_PROC_HIERARCHY_INFO*)PpttNodeFound->Object))) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Reference to a leaf Processor Hierarchy Node. " \
+ "ParentToken = %p. ChildToken = %p. Status = %r\n",
+ ProcInfoNode->ParentToken,
+ ProcInfoNode->Token,
+ Status
+ ));
+ return Status;
+ }
+
+ // Update Proc Structure with the offset of the parent node
+ ProcStruct->Parent = PpttNodeFound->Offset;
+
+ // Store the reference for the parent node in the Node Indexer
+ // so that this can be used later for cycle detection
+ ProcNodeIterator->TopologyParent = PpttNodeFound;
+ }
+
+ // Populate ACPI Processor ID
+ if (!IS_ACPI_PROC_ID_VALID (ProcInfoNode)) {
+ // Default invalid ACPI Processor ID to 0
+ ProcStruct->AcpiProcessorId = 0;
+ } else if (ProcInfoNode->GicCToken == CM_NULL_TOKEN) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: The 'ACPI Processor ID valid' flag is set but no GICC " \
+ "structure token was provided. GicCToken = %p. RequestorToken = %p. " \
+ "Status = %r\n",
+ ProcInfoNode->GicCToken,
+ ProcInfoNode->Token,
+ Status
+ ));
+ return Status;
+ } else {
+ Status = GetEArmObjGicCInfo (
+ CfgMgrProtocol,
+ ProcInfoNode->GicCToken,
+ &GicCInfoList,
+ &GicCInfoCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get GICC structure. ACPI Processor ID " \
+ "can't be populated. GicCToken = %p. RequestorToken = %p. " \
+ "Status = %r\n",
+ ProcInfoNode->GicCToken,
+ ProcInfoNode->Token,
+ Status
+ ));
+ return Status;
+ }
+
+ if (GicCInfoCount != 1) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to find a unique GICC structure. " \
+ "ACPI Processor ID can't be populated. " \
+ "GICC Structure Count = %d. GicCToken = %p. RequestorToken = %p " \
+ "Status = %r\n",
+ GicCInfoCount,
+ ProcInfoNode->GicCToken,
+ ProcInfoNode->Token,
+ Status
+ ));
+ return Status;
+ }
+
+ // Update the ACPI Processor Id
+ ProcStruct->AcpiProcessorId = GicCInfoList->AcpiProcessorUid;
+
+ // Increment the reference count for the number of
+ // Unique GICC objects that were retrieved.
+ UniqueGicCRefCount++;
+ }
+
+ ProcStruct->NumberOfPrivateResources = ProcInfoNode->NoOfPrivateResources;
+ PrivateResources = (UINT32*)((UINT8*)ProcStruct +
+ sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR));
+
+ if (ProcStruct->NumberOfPrivateResources != 0) {
+ // Populate the private resources array
+ Status = AddPrivateResources (
+ Generator,
+ CfgMgrProtocol,
+ PrivateResources,
+ ProcStruct->NumberOfPrivateResources,
+ ProcInfoNode->PrivateResourcesArrayToken
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to populate the private resources array. " \
+ "Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ // Next Processor Hierarchy Node
+ ProcStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR*)((UINT8*)ProcStruct +
+ ProcStruct->Length);
+ ProcNodeIterator++;
+ } // Processor Hierarchy Node
+
+ // Knowing the total number of GICC references made and that all GICC Token
+ // references are unique, we can test if no GICC instances have been left out.
+ Status = GetEArmObjGicCInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &GicCInfoList,
+ &GicCInfoCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get GICC Info. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // MADT - PPTT cross validation
+ // This checks that one and only one GICC structure is referenced by a
+ // Processor Hierarchy Node in the PPTT.
+ // Since we have already checked that the GICC objects referenced by the
+ // Proc Nodes are unique, the UniqueGicCRefCount cannot be greater than
+ // the total number of GICC objects in the platform.
+ if (GicCInfoCount > UniqueGicCRefCount) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: %d GICC structure(s) exposed by MADT don't have " \
+ "a corresponding Processor Hierarchy Node. Status = %r\n",
+ GicCInfoCount - UniqueGicCRefCount,
+ Status
+ ));
+ }
+
+ return Status;
+}
+
+/**
+ Update the Cache Type Structure (Type 1) information.
+
+ This function populates the Cache Type Structures with information from
+ the Configuration Manager and adds this information to the PPTT table.
+
+ @param [in] Generator Pointer to the PPTT Generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Pptt Pointer to PPTT table structure.
+ @param [in] NodesStartOffset Offset from the start of PPTT table to the
+ start of Cache Type Structures.
+
+ @retval EFI_SUCCESS Structures updated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND A required object was not found.
+**/
+STATIC
+EFI_STATUS
+AddCacheTypeStructures (
+ IN CONST ACPI_PPTT_GENERATOR * CONST Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER * Pptt,
+ IN CONST UINT32 NodesStartOffset
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE * CacheStruct;
+ PPTT_NODE_INDEXER * PpttNodeFound;
+ CM_ARM_CACHE_INFO * CacheInfoNode;
+ PPTT_NODE_INDEXER * CacheNodeIterator;
+ UINT32 NodeCount;
+
+ ASSERT (
+ (Generator != NULL) &&
+ (CfgMgrProtocol != NULL) &&
+ (Pptt != NULL)
+ );
+
+ CacheStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE*)((UINT8*)Pptt +
+ NodesStartOffset);
+
+ CacheNodeIterator = Generator->CacheStructIndexedList;
+ NodeCount = Generator->CacheStructCount;
+
+ while (NodeCount-- != 0) {
+ CacheInfoNode = (CM_ARM_CACHE_INFO*)CacheNodeIterator->Object;
+
+ // Populate the node header
+ CacheStruct->Type = EFI_ACPI_6_3_PPTT_TYPE_CACHE;
+ CacheStruct->Length = sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE);
+ CacheStruct->Reserved[0] = EFI_ACPI_RESERVED_BYTE;
+ CacheStruct->Reserved[1] = EFI_ACPI_RESERVED_BYTE;
+
+ // "On Arm-based systems, all cache properties must be provided in the
+ // table." (ACPI 6.3, Section 5.2.29.2)
+ CacheStruct->Flags.SizePropertyValid = 1;
+ CacheStruct->Flags.NumberOfSetsValid = 1;
+ CacheStruct->Flags.AssociativityValid = 1;
+ CacheStruct->Flags.AllocationTypeValid = 1;
+ CacheStruct->Flags.CacheTypeValid = 1;
+ CacheStruct->Flags.WritePolicyValid = 1;
+ CacheStruct->Flags.LineSizeValid = 1;
+ CacheStruct->Flags.Reserved = 0;
+
+ // Populate the reference to the next level of cache
+ if (CacheInfoNode->NextLevelOfCacheToken == CM_NULL_TOKEN) {
+ CacheStruct->NextLevelOfCache = 0;
+ } else {
+ Status = GetPpttNodeReferencedByToken (
+ Generator->CacheStructIndexedList,
+ Generator->CacheStructCount,
+ CacheInfoNode->NextLevelOfCacheToken,
+ &PpttNodeFound
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get the reference to the Next Level of " \
+ "Cache. NextLevelOfCacheToken = %p. RequestorToken = %p. " \
+ "Status = %r\n",
+ CacheInfoNode->NextLevelOfCacheToken,
+ CacheInfoNode->Token,
+ Status
+ ));
+ return Status;
+ }
+
+ // Update Cache Structure with the offset for the next level of cache
+ CacheStruct->NextLevelOfCache = PpttNodeFound->Offset;
+
+ // Store the next level of cache information in the Node Indexer
+ // so that this can be used later for cycle detection
+ CacheNodeIterator->TopologyParent = PpttNodeFound;
+ }
+
+ CacheStruct->Size = CacheInfoNode->Size;
+
+ // Validate and populate the 'Number of sets' field
+ if (CacheInfoNode->NumberOfSets > PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum number " \
+ "of sets can be %d. NumberOfSets = %d. Status = %r\n",
+ PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX,
+ CacheInfoNode->NumberOfSets,
+ Status
+ ));
+ return Status;
+ }
+
+ if (CacheInfoNode->NumberOfSets > PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX) {
+ DEBUG ((
+ DEBUG_INFO,
+ "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \
+ "number of sets can be %d. NumberOfSets = %d\n",
+ PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX,
+ CacheInfoNode->NumberOfSets
+ ));
+ }
+
+ CacheStruct->NumberOfSets = CacheInfoNode->NumberOfSets;
+
+ // Validate Associativity field based on maximum associativity
+ // supported by ACPI Cache type structure.
+ if (CacheInfoNode->Associativity > MAX_UINT8) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: The maximum associativity supported by ACPI " \
+ "Cache type structure is %d. Associativity = %d, Status = %r\n",
+ MAX_UINT8,
+ CacheInfoNode->Associativity,
+ Status
+ ));
+ return Status;
+ }
+
+ // Validate the Associativity field based on the architecture specification
+ // The architecture supports much larger associativity values than the
+ // current ACPI specification.
+ // These checks will be needed in the future when the ACPI specification
+ // is extended. Disabling this code for now.
+#if 0
+ if (CacheInfoNode->Associativity > PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum cache " \
+ "associativity can be %d. Associativity = %d. Status = %r\n",
+ PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX,
+ CacheInfoNode->Associativity,
+ Status
+ ));
+ return Status;
+ }
+
+ if (CacheInfoNode->Associativity > PPTT_ARM_CACHE_ASSOCIATIVITY_MAX) {
+ DEBUG ((
+ DEBUG_INFO,
+ "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \
+ "cache associativity can be %d. Associativity = %d\n",
+ PPTT_ARM_CACHE_ASSOCIATIVITY_MAX,
+ CacheInfoNode->Associativity
+ ));
+ }
+#endif
+
+ // Note a typecast is needed as the maximum associativity
+ // supported by ACPI Cache type structure is MAX_UINT8.
+ CacheStruct->Associativity = (UINT8)CacheInfoNode->Associativity;
+
+ // Populate cache attributes
+ CacheStruct->Attributes.AllocationType =
+ CacheInfoNode->Attributes & (BIT0 | BIT1);
+ CacheStruct->Attributes.CacheType =
+ (CacheInfoNode->Attributes & (BIT2 | BIT3)) >> 2;
+ CacheStruct->Attributes.WritePolicy =
+ (CacheInfoNode->Attributes & BIT4) >> 4;
+ CacheStruct->Attributes.Reserved = 0;
+
+ // Validate and populate cache line size
+ if ((CacheInfoNode->LineSize < PPTT_ARM_CACHE_LINE_SIZE_MIN) ||
+ (CacheInfoNode->LineSize > PPTT_ARM_CACHE_LINE_SIZE_MAX)) {
+
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: The cache line size must be between %d and %d bytes " \
+ "on ARM Platforms. LineSize = %d. Status = %r\n" ,
+ PPTT_ARM_CACHE_LINE_SIZE_MIN,
+ PPTT_ARM_CACHE_LINE_SIZE_MAX,
+ CacheInfoNode->LineSize,
+ Status
+ ));
+ return Status;
+ }
+
+ if ((CacheInfoNode->LineSize & (CacheInfoNode->LineSize - 1)) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: The cache line size is not a power of 2. " \
+ "LineSize = %d. Status = %r\n" ,
+ CacheInfoNode->LineSize,
+ Status
+ ));
+ return Status;
+ }
+
+ CacheStruct->LineSize = CacheInfoNode->LineSize;
+
+ // Next Cache Type Structure
+ CacheStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE*)((UINT8*)CacheStruct +
+ CacheStruct->Length);
+ CacheNodeIterator++;
+ } // Cache Type Structure
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update the ID Type Structure (Type 2) information.
+
+ This function populates the ID Type Structures with information from
+ the Configuration Manager and and adds this information to the PPTT table.
+
+ @param [in] Generator Pointer to the PPTT Generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Pptt Pointer to PPTT table structure.
+ @param [in] NodesStartOffset Offset from the start of PPTT table to the
+ start of ID Type Structures.
+
+ @retval EFI_SUCCESS Structures updated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND A required object was not found.
+**/
+STATIC
+EFI_STATUS
+AddIdTypeStructures (
+ IN CONST ACPI_PPTT_GENERATOR * CONST Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER * Pptt,
+ IN CONST UINT32 NodesStartOffset
+ )
+{
+ EFI_ACPI_6_3_PPTT_STRUCTURE_ID * IdStruct;
+ CM_ARM_PROC_NODE_ID_INFO * ProcIdInfoNode;
+ PPTT_NODE_INDEXER * IdStructIterator;
+ UINT32 NodeCount;
+
+
+ ASSERT (
+ (Generator != NULL) &&
+ (CfgMgrProtocol != NULL) &&
+ (Pptt != NULL)
+ );
+
+ IdStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_ID*)((UINT8*)Pptt + NodesStartOffset);
+
+ IdStructIterator = Generator->IdStructIndexedList;
+ NodeCount = Generator->IdStructCount;
+ while (NodeCount-- != 0) {
+ ProcIdInfoNode = (CM_ARM_PROC_NODE_ID_INFO*)IdStructIterator->Object;
+
+ // Populate the node
+ IdStruct->Type = EFI_ACPI_6_3_PPTT_TYPE_ID;
+ IdStruct->Length = sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_ID);
+ IdStruct->Reserved[0] = EFI_ACPI_RESERVED_BYTE;
+ IdStruct->Reserved[1] = EFI_ACPI_RESERVED_BYTE;
+ IdStruct->VendorId = ProcIdInfoNode->VendorId;
+ IdStruct->Level1Id = ProcIdInfoNode->Level1Id;
+ IdStruct->Level2Id = ProcIdInfoNode->Level2Id;
+ IdStruct->MajorRev = ProcIdInfoNode->MajorRev;
+ IdStruct->MinorRev = ProcIdInfoNode->MinorRev;
+ IdStruct->SpinRev = ProcIdInfoNode->SpinRev;
+
+ // Next ID Type Structure
+ IdStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_ID*)((UINT8*)IdStruct +
+ IdStruct->Length);
+ IdStructIterator++;
+ } // ID Type Structure
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Construct the PPTT ACPI table.
+
+ This function invokes the Configuration Manager protocol interface
+ to get the required hardware information for generating the ACPI
+ table.
+
+ If this function allocates any resources then they must be freed
+ in the FreeXXXXTableResources function.
+
+ @param [in] This Pointer to the table generator.
+ @param [in] AcpiTableInfo Pointer to the ACPI table generator to be used.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [out] Table Pointer to the constructed ACPI Table.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object was not found.
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
+ Manager is less than the Object size for
+ the requested object.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BuildPpttTable (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TableSize;
+ UINT32 ProcTopologyStructCount;
+
+ UINT32 ProcHierarchyNodeOffset;
+ UINT32 CacheStructOffset;
+ UINT32 IdStructOffset;
+
+ CM_ARM_PROC_HIERARCHY_INFO * ProcHierarchyNodeList;
+ CM_ARM_CACHE_INFO * CacheStructList;
+ CM_ARM_PROC_NODE_ID_INFO * IdStructList;
+
+ ACPI_PPTT_GENERATOR * Generator;
+
+ // Pointer to the Node Indexer array
+ PPTT_NODE_INDEXER * NodeIndexer;
+
+ EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER * Pptt;
+
+ ASSERT (
+ (This != NULL) &&
+ (AcpiTableInfo != NULL) &&
+ (CfgMgrProtocol != NULL) &&
+ (Table != NULL) &&
+ (AcpiTableInfo->TableGeneratorId == This->GeneratorID) &&
+ (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature)
+ );
+
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Requested table revision = %d is not supported. "
+ "Supported table revisions: Minimum = %d. Maximum = %d\n",
+ AcpiTableInfo->AcpiTableRevision,
+ This->MinAcpiTableRevision,
+ This->AcpiTableRevision
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Generator = (ACPI_PPTT_GENERATOR*)This;
+ *Table = NULL;
+
+ // Get the processor hierarchy info and update the processor topology
+ // structure count with Processor Hierarchy Nodes (Type 0)
+ Status = GetEArmObjProcHierarchyInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &ProcHierarchyNodeList,
+ &Generator->ProcHierarchyNodeCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get processor hierarchy info. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ ProcTopologyStructCount = Generator->ProcHierarchyNodeCount;
+
+ // Get the cache info and update the processor topology structure count with
+ // Cache Type Structures (Type 1)
+ Status = GetEArmObjCacheInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &CacheStructList,
+ &Generator->CacheStructCount
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get cache info. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ ProcTopologyStructCount += Generator->CacheStructCount;
+
+ // Get the processor hierarchy node ID info and update the processor topology
+ // structure count with ID Structures (Type 2)
+ Status = GetEArmObjProcNodeIdInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &IdStructList,
+ &Generator->IdStructCount
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get processor hierarchy node ID info. " \
+ "Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ ProcTopologyStructCount += Generator->IdStructCount;
+
+ // Allocate Node Indexer array
+ NodeIndexer = (PPTT_NODE_INDEXER*)AllocateZeroPool (
+ sizeof (PPTT_NODE_INDEXER) *
+ ProcTopologyStructCount
+ );
+ if (NodeIndexer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to allocate memory for Node Indexer. Status = %r\n ",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ DEBUG ((DEBUG_INFO, "INFO: NodeIndexer = %p\n", NodeIndexer));
+ Generator->ProcTopologyStructCount = ProcTopologyStructCount;
+ Generator->NodeIndexer = NodeIndexer;
+
+ // Calculate the size of the PPTT table
+ TableSize = sizeof (EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER);
+
+ // Include the size of Processor Hierarchy Nodes and index them
+ if (Generator->ProcHierarchyNodeCount != 0) {
+ ProcHierarchyNodeOffset = TableSize;
+ Generator->ProcHierarchyNodeIndexedList = NodeIndexer;
+ TableSize += GetSizeofProcHierarchyNodes (
+ ProcHierarchyNodeOffset,
+ ProcHierarchyNodeList,
+ Generator->ProcHierarchyNodeCount,
+ &NodeIndexer
+ );
+ }
+
+ // Include the size of Cache Type Structures and index them
+ if (Generator->CacheStructCount != 0) {
+ CacheStructOffset = TableSize;
+ Generator->CacheStructIndexedList = NodeIndexer;
+ TableSize += GetSizeofCacheTypeStructs (
+ CacheStructOffset,
+ CacheStructList,
+ Generator->CacheStructCount,
+ &NodeIndexer
+ );
+ }
+
+ // Include the size of ID Type Structures and index them
+ if (Generator->IdStructCount != 0) {
+ IdStructOffset = TableSize;
+ Generator->IdStructIndexedList = NodeIndexer;
+ TableSize += GetSizeofIdStructs (
+ IdStructOffset,
+ IdStructList,
+ Generator->IdStructCount,
+ &NodeIndexer
+ );
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "INFO: PPTT:\n" \
+ " ProcTopologyStructCount = %d\n" \
+ " TableSize = %d\n",
+ ProcTopologyStructCount,
+ TableSize
+ ));
+
+ DEBUG ((
+ DEBUG_INFO,
+ " ProcHierarchyNodeCount = %d\n" \
+ " ProcHierarchyNodeOffset = 0x%x\n" \
+ " ProcHierarchyNodeIndexedList = 0x%p\n",
+ Generator->ProcHierarchyNodeCount,
+ ProcHierarchyNodeOffset,
+ Generator->ProcHierarchyNodeIndexedList
+ ));
+
+ DEBUG ((
+ DEBUG_INFO,
+ " CacheStructCount = %d\n" \
+ " CacheStructOffset = 0x%x\n" \
+ " CacheStructIndexedList = 0x%p\n",
+ Generator->CacheStructCount,
+ CacheStructOffset,
+ Generator->CacheStructIndexedList
+ ));
+
+ DEBUG ((
+ DEBUG_INFO,
+ " IdStructCount = %d\n" \
+ " IdStructOffset = 0x%x\n" \
+ " IdStructIndexedList = 0x%p\n",
+ Generator->IdStructCount,
+ IdStructOffset,
+ Generator->IdStructIndexedList
+ ));
+
+ // Allocate the Buffer for the PPTT table
+ *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);
+ if (*Table == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to allocate memory for PPTT Table. " \
+ "Size = %d. Status = %r\n",
+ TableSize,
+ Status
+ ));
+ goto error_handler;
+ }
+
+ Pptt = (EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER*)*Table;
+
+ DEBUG ((
+ DEBUG_INFO,
+ "PPTT: Pptt = 0x%p. TableSize = 0x%x\n",
+ Pptt,
+ TableSize
+ ));
+
+ // Add ACPI header
+ Status = AddAcpiHeader (
+ CfgMgrProtocol,
+ This,
+ &Pptt->Header,
+ AcpiTableInfo,
+ TableSize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to add ACPI header. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ // Add Processor Hierarchy Nodes (Type 0) to the generated table
+ if (Generator->ProcHierarchyNodeCount != 0) {
+ Status = AddProcHierarchyNodes (
+ Generator,
+ CfgMgrProtocol,
+ Pptt,
+ ProcHierarchyNodeOffset
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to add Processor Hierarchy Nodes. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ // Add Cache Type Structures (Type 1) to the generated table
+ if (Generator->CacheStructCount != 0) {
+ Status = AddCacheTypeStructures (
+ Generator,
+ CfgMgrProtocol,
+ Pptt,
+ CacheStructOffset
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to add Cache Type Structures. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ // Add ID Type Structures (Type 2) to the generated table
+ if (Generator->IdStructCount != 0) {
+ Status = AddIdTypeStructures (
+ Generator,
+ CfgMgrProtocol,
+ Pptt,
+ IdStructOffset
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to add ID Type Structures. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ // Validate CM object cross-references in PPTT
+ Status = DetectCyclesInTopology (Generator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Invalid processor and cache topology. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ return Status;
+
+error_handler:
+ if (Generator->NodeIndexer != NULL) {
+ FreePool (Generator->NodeIndexer);
+ Generator->NodeIndexer = NULL;
+ }
+
+ if (*Table != NULL) {
+ FreePool (*Table);
+ *Table = NULL;
+ }
+
+ return Status;
+}
+
+/**
+ Free any resources allocated for constructing the PPTT
+
+ @param [in] This Pointer to the table generator.
+ @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in, out] Table Pointer to the ACPI Table.
+
+ @retval EFI_SUCCESS The resources were freed successfully.
+ @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
+**/
+STATIC
+EFI_STATUS
+FreePpttTableResources (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table
+ )
+{
+ ACPI_PPTT_GENERATOR * Generator;
+
+ ASSERT (
+ (This != NULL) &&
+ (AcpiTableInfo != NULL) &&
+ (CfgMgrProtocol != NULL) &&
+ (AcpiTableInfo->TableGeneratorId == This->GeneratorID) &&
+ (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature)
+ );
+
+ Generator = (ACPI_PPTT_GENERATOR*)This;
+
+ // Free any memory allocated by the generator
+ if (Generator->NodeIndexer != NULL) {
+ FreePool (Generator->NodeIndexer);
+ Generator->NodeIndexer = NULL;
+ }
+
+ if ((Table == NULL) || (*Table == NULL)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: PPTT: Invalid Table Pointer\n"));
+ ASSERT (
+ (Table != NULL) &&
+ (*Table != NULL)
+ );
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FreePool (*Table);
+ *Table = NULL;
+ return EFI_SUCCESS;
+}
+
+/** The PPTT Table Generator revision.
+*/
+#define PPTT_GENERATOR_REVISION CREATE_REVISION (1, 0)
+
+/** The interface for the PPTT Table Generator.
+*/
+STATIC
+ACPI_PPTT_GENERATOR PpttGenerator = {
+ // ACPI table generator header
+ {
+ // Generator ID
+ CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdPptt),
+ // Generator Description
+ L"ACPI.STD.PPTT.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE,
+ // ACPI Table Revision supported by this Generator
+ EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION,
+ // Minimum supported ACPI Table Revision
+ EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION,
+ // Creator ID
+ TABLE_GENERATOR_CREATOR_ID_ARM,
+ // Creator Revision
+ PPTT_GENERATOR_REVISION,
+ // Build Table function
+ BuildPpttTable,
+ // Free Resource function
+ FreePpttTableResources,
+ // Extended build function not needed
+ NULL,
+ // Extended build function not implemented by the generator.
+ // Hence extended free resource function is not required.
+ NULL
+ },
+
+ // PPTT Generator private data
+
+ // Processor topology node count
+ 0,
+ // Pointer to PPTT Node Indexer
+ NULL
+};
+
+/**
+ Register the Generator with the ACPI Table Factory.
+
+ @param [in] ImageHandle The handle to the image.
+ @param [in] SystemTable Pointer to the System Table.
+
+ @retval EFI_SUCCESS The Generator is registered.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_ALREADY_STARTED The Generator for the Table ID
+ is already registered.
+**/
+EFI_STATUS
+EFIAPI
+AcpiPpttLibConstructor (
+ IN CONST EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * CONST SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = RegisterAcpiTableGenerator (&PpttGenerator.Header);
+ DEBUG ((DEBUG_INFO, "PPTT: Register Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ Deregister the Generator from the ACPI Table Factory.
+
+ @param [in] ImageHandle The handle to the image.
+ @param [in] SystemTable Pointer to the System Table.
+
+ @retval EFI_SUCCESS The Generator is deregistered.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The Generator is not registered.
+**/
+EFI_STATUS
+EFIAPI
+AcpiPpttLibDestructor (
+ IN CONST EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * CONST SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&PpttGenerator.Header);
+ DEBUG ((DEBUG_INFO, "PPTT: Deregister Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.h b/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.h
new file mode 100644
index 0000000000..6a0fdd08e1
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.h
@@ -0,0 +1,190 @@
+/** @file
+ Header file for the dynamic PPTT generator
+
+ Copyright (c) 2019, ARM Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - ACPI 6.3 Specification, January 2019
+ - ARM Architecture Reference Manual ARMv8 (D.a)
+
+ @par Glossary:
+ - Cm or CM - Configuration Manager
+ - Obj or OBJ - Object
+**/
+
+#ifndef PPTT_GENERATOR_H_
+#define PPTT_GENERATOR_H_
+
+#pragma pack(1)
+
+/// Cache parameters allowed by the architecture with
+/// ARMv8.3-CCIDX (Cache extended number of sets)
+/// Derived from CCSIDR_EL1 when ID_AA64MMFR2_EL1.CCIDX==0001
+#define PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX (1 << 24)
+#define PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX (1 << 21)
+
+/// Cache parameters allowed by the architecture without
+/// ARMv8.3-CCIDX (Cache extended number of sets)
+/// Derived from CCSIDR_EL1 when ID_AA64MMFR2_EL1.CCIDX==0000
+#define PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX (1 << 15)
+#define PPTT_ARM_CACHE_ASSOCIATIVITY_MAX (1 << 10)
+
+/// Common cache parameters
+/// Derived from CCSIDR_EL1
+/// The LineSize is represented by bits 2:0
+/// (Log2(Number of bytes in cache line)) - 4 is used to represent
+/// the LineSize bits.
+#define PPTT_ARM_CACHE_LINE_SIZE_MAX (1 << 11)
+#define PPTT_ARM_CACHE_LINE_SIZE_MIN (1 << 4)
+
+/// Test if the given Processor Hierarchy Info object has the 'Node is a Leaf'
+/// flag set
+#define IS_PROC_NODE_LEAF(Node) ((Node->Flags & BIT3) != 0)
+
+/// Test if the given Processor Hierarchy Info object has the 'ACPI Processor
+/// ID valid' flag set
+#define IS_ACPI_PROC_ID_VALID(Node) ((Node->Flags & BIT1) != 0)
+
+/**
+ The GET_SIZE_OF_PPTT_STRUCTS macro expands to a function that is used to
+ calculate the total memory requirement for the PPTT structures represented
+ by the given list of Configuration Manager Objects of the same type. This
+ function also indexes the input CM objects so that various other CM objects
+ (possibly of different type) can reference them.
+
+ The size of memory needed for the specified type of PPTT structures is based
+ on the number and type of CM objects provided. The macro assumes that the
+ ACPI object PpttObjName has fixed size.
+
+ The macro expands to a function which has the following prototype:
+
+ STATIC
+ UINT32
+ EFIAPI
+ GetSizeof<PpttObjName> (
+ IN CONST UINT32 StartOffset,
+ IN CONST CmObjectType * Nodes,
+ IN UINT32 NodeCount,
+ IN OUT PPTT_NODE_INDEXER ** CONST NodeIndexer
+ )
+
+ Generated function parameters:
+ @param [in] StartOffset Offset from the start of PPTT to where
+ the PPTT structures will be placed.
+ @param [in] NodesToIndex Pointer to the list of CM objects to be
+ indexed and size-estimated.
+ @param [out] NodeCount Number of CM objects in NodesToIndex.
+ @param [in, out] NodeIndexer Pointer to the list of Node Indexer
+ elements to populate.
+ @retval Size Total memory requirement for the PPTT
+ structures described in NodesToIndex.
+
+ Macro Parameters:
+ @param [in] PpttObjName Name for the type of PPTT structures which
+ size is estimated.
+ @param [in] PpttObjSize Expression to use to calculate the size of
+ of a single instance of the PPTT structure
+ which corresponds to the CM object being
+ indexed.
+ @param [in] CmObjectType Data type of the CM nodes in NodesToIndex.
+**/
+#define GET_SIZE_OF_PPTT_STRUCTS( \
+ PpttObjName, \
+ PpttObjSize, \
+ CmObjectType \
+) \
+STATIC \
+UINT32 \
+GetSizeof##PpttObjName ( \
+ IN CONST UINT32 StartOffset, \
+ IN CONST CmObjectType * NodesToIndex, \
+ IN UINT32 NodeCount, \
+ IN OUT PPTT_NODE_INDEXER ** CONST NodeIndexer \
+ ) \
+{ \
+ UINT32 Size; \
+ \
+ ASSERT ( \
+ (NodesToIndex != NULL) && \
+ (NodeIndexer != NULL) \
+ ); \
+ \
+ Size = 0; \
+ while (NodeCount-- != 0) { \
+ (*NodeIndexer)->Token = NodesToIndex->Token; \
+ (*NodeIndexer)->Object = (VOID*)NodesToIndex; \
+ (*NodeIndexer)->Offset = Size + StartOffset; \
+ (*NodeIndexer)->CycleDetectionStamp = 0; \
+ (*NodeIndexer)->TopologyParent = NULL; \
+ DEBUG (( \
+ DEBUG_INFO, \
+ "PPTT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n", \
+ *NodeIndexer, \
+ (*NodeIndexer)->Token, \
+ (*NodeIndexer)->Object, \
+ (*NodeIndexer)->Offset \
+ )); \
+ \
+ Size += PpttObjSize; \
+ (*NodeIndexer)++; \
+ NodesToIndex++; \
+ } \
+ return Size; \
+}
+
+/**
+ A structure for indexing CM objects (nodes) used in PPTT generation.
+
+ PPTT_NODE_INDEXER is a wrapper around CM objects which augments these objects
+ with additional information that enables generating PPTT structures with
+ correct cross-references.
+
+ PPTT_NODE_INDEXER keeps track of each structure's offset from the base
+ address of the generated table. It also caches certain information and makes
+ PPTT cyclic reference detection possible.
+*/
+typedef struct PpttNodeIndexer {
+ /// Unique identifier for the node
+ CM_OBJECT_TOKEN Token;
+ /// Pointer to the CM object being indexed
+ VOID * Object;
+ /// Offset from the start of the PPTT table to the PPTT structure which is
+ /// represented by Object
+ UINT32 Offset;
+ /// Field used to mark nodes as 'visited' when detecting cycles in processor
+ /// and cache topology
+ UINT32 CycleDetectionStamp;
+ /// Reference to a Node Indexer element which is the parent of this Node
+ /// Indexer element in the processor and cache topology
+ /// e.g For a hardware thread the TopologyParent would point to a CPU node
+ /// For a L1 cache the TopologyParent would point to a L2 cache
+ struct PpttNodeIndexer * TopologyParent;
+} PPTT_NODE_INDEXER;
+
+typedef struct AcpiPpttGenerator {
+ /// ACPI Table generator header
+ ACPI_TABLE_GENERATOR Header;
+ /// PPTT structure count
+ UINT32 ProcTopologyStructCount;
+ /// List of indexed CM objects for PPTT generation
+ PPTT_NODE_INDEXER * NodeIndexer;
+ /// Pointer to the start of Processor Hierarchy nodes in
+ /// the Node Indexer array
+ PPTT_NODE_INDEXER * ProcHierarchyNodeIndexedList;
+ /// Pointer to the start of Cache Structures in the Node Indexer array
+ PPTT_NODE_INDEXER * CacheStructIndexedList;
+ /// Pointer to the start of Id Structures in the Node Indexer array
+ PPTT_NODE_INDEXER * IdStructIndexedList;
+ /// Count of Processor Hierarchy Nodes
+ UINT32 ProcHierarchyNodeCount;
+ /// Count of Cache Structures
+ UINT32 CacheStructCount;
+ /// Count of Id Structures
+ UINT32 IdStructCount;
+
+} ACPI_PPTT_GENERATOR;
+
+#pragma pack()
+
+#endif // PPTT_GENERATOR_H_