4 Copyright (c) 2021, ARM Limited. All rights reserved.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
8 - ACPI 6.4 Specification, January 2021
11 - Cm or CM - Configuration Manager
15 #include <Library/AcpiLib.h>
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/MemoryAllocationLib.h>
19 #include <Protocol/AcpiTable.h>
21 // Module specific include files.
22 #include <AcpiTableGenerator.h>
23 #include <ConfigurationManagerObject.h>
24 #include <ConfigurationManagerHelper.h>
25 #include <Library/TableHelperLib.h>
26 #include <Protocol/ConfigurationManagerProtocol.h>
28 #include "PpttGenerator.h"
31 ARM standard PPTT Generator
34 The following Configuration Manager Object(s) are used by this Generator:
35 - EArmObjProcHierarchyInfo (REQUIRED)
38 - EArmObjGicCInfo (REQUIRED)
42 This macro expands to a function that retrieves the Processor Hierarchy
43 information from the Configuration Manager.
47 EArmObjProcHierarchyInfo
,
48 CM_ARM_PROC_HIERARCHY_INFO
52 This macro expands to a function that retrieves the cache information
53 from the Configuration Manager.
62 This macro expands to a function that retrieves the cross-CM-object-
63 reference information from the Configuration Manager.
72 This macro expands to a function that retrieves the GIC CPU interface
73 information from the Configuration Manager.
82 Returns the size of the PPTT Processor Hierarchy Node (Type 0) given a
83 Processor Hierarchy Info CM object.
85 @param [in] Node Pointer to Processor Hierarchy Info CM object which
86 represents the Processor Hierarchy Node to be generated.
88 @retval Size of the Processor Hierarchy Node in bytes.
92 GetProcHierarchyNodeSize (
93 IN CONST CM_ARM_PROC_HIERARCHY_INFO
*Node
96 ASSERT (Node
!= NULL
);
98 // <size of Processor Hierarchy Node> + <size of Private Resources array>
99 return sizeof (EFI_ACPI_6_4_PPTT_STRUCTURE_PROCESSOR
) +
100 (Node
->NoOfPrivateResources
* sizeof (UINT32
));
104 This macro expands to a function that retrieves the amount of memory required
105 to store the Processor Hierarchy Nodes (Type 0) and updates the Node Indexer.
107 GET_SIZE_OF_PPTT_STRUCTS (
109 GetProcHierarchyNodeSize (NodesToIndex
),
110 CM_ARM_PROC_HIERARCHY_INFO
114 This macro expands to a function that retrieves the amount of memory required
115 to store the Cache Type Structures (Type 1) and updates the Node Indexer.
117 GET_SIZE_OF_PPTT_STRUCTS (
119 sizeof (EFI_ACPI_6_4_PPTT_STRUCTURE_CACHE
),
124 Search the Node Indexer and return the indexed PPTT node with the given
127 @param [in] NodeIndexer Pointer to the Node Indexer array.
128 @param [in] NodeCount Number of elements in Node Indexer.
129 @param [in] SearchToken Token used for Node Indexer lookup.
130 @param [out] IndexedNodeFound Pointer to the Node Indexer array element
131 with the given Token.
133 @retval EFI_SUCCESS Success.
134 @retval EFI_NOT_FOUND No element with a matching token was
135 found in the Node Indexer array.
139 GetPpttNodeReferencedByToken (
140 IN PPTT_NODE_INDEXER
*NodeIndexer
,
142 IN CONST CM_OBJECT_TOKEN SearchToken
,
143 OUT PPTT_NODE_INDEXER
**IndexedNodeFound
148 ASSERT (NodeIndexer
!= NULL
);
152 "PPTT: Node Indexer: SearchToken = %p\n",
156 while (NodeCount
-- != 0) {
159 "PPTT: Node Indexer: NodeIndexer->Token = %p. Offset = %d\n",
164 if (NodeIndexer
->Token
== SearchToken
) {
165 *IndexedNodeFound
= NodeIndexer
;
166 Status
= EFI_SUCCESS
;
169 "PPTT: Node Indexer: Token = %p. Found, Status = %r\n",
179 Status
= EFI_NOT_FOUND
;
182 "PPTT: Node Indexer: SearchToken = %p. Status = %r\n",
191 Detect cycles in the processor and cache topology graph represented in
194 @param [in] Generator Pointer to the PPTT Generator.
196 @retval EFI_SUCCESS There are no cyclic references in the graph.
197 @retval EFI_INVALID_PARAMETER Processor or cache references form a cycle.
201 DetectCyclesInTopology (
202 IN CONST ACPI_PPTT_GENERATOR
*CONST Generator
206 PPTT_NODE_INDEXER
*Iterator
;
207 PPTT_NODE_INDEXER
*CycleDetector
;
208 UINT32 NodesRemaining
;
210 ASSERT (Generator
!= NULL
);
212 Iterator
= Generator
->NodeIndexer
;
213 NodesRemaining
= Generator
->ProcTopologyStructCount
;
215 while (NodesRemaining
!= 0) {
218 "INFO: PPTT: Cycle detection for element with index %d\n",
219 Generator
->ProcTopologyStructCount
- NodesRemaining
222 CycleDetector
= Iterator
;
224 // Walk the topology tree
225 while (CycleDetector
->TopologyParent
!= NULL
) {
228 "INFO: PPTT: %p -> %p\n",
229 CycleDetector
->Token
,
230 CycleDetector
->TopologyParent
->Token
233 // Check if we have already visited this node
234 if (CycleDetector
->CycleDetectionStamp
== NodesRemaining
) {
235 Status
= EFI_INVALID_PARAMETER
;
238 "ERROR: PPTT: Cycle in processor and cache topology detected for " \
239 "a chain of references originating from a node with: Token = %p " \
247 // Stamp the visited node
248 CycleDetector
->CycleDetectionStamp
= NodesRemaining
;
249 CycleDetector
= CycleDetector
->TopologyParent
;
250 } // Continue topology tree walk
254 } // Next Node Indexer
260 Update the array of private resources for a given Processor Hierarchy Node.
262 @param [in] Generator Pointer to the PPTT Generator.
263 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
265 @param [in] PrivResArray Pointer to the array of private resources.
266 @param [in] PrivResCount Number of private resources.
267 @param [in] PrivResArrayToken Reference Token for the CM_ARM_OBJ_REF
268 array describing node's private resources.
270 @retval EFI_SUCCESS Array updated successfully.
271 @retval EFI_INVALID_PARAMETER A parameter is invalid.
272 @retval EFI_NOT_FOUND A private resource was not found.
276 AddPrivateResources (
277 IN CONST ACPI_PPTT_GENERATOR
*CONST Generator
,
278 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
279 IN UINT32
*PrivResArray
,
280 IN UINT32 PrivResCount
,
281 IN CONST CM_OBJECT_TOKEN PrivResArrayToken
285 CM_ARM_OBJ_REF
*CmObjRefs
;
286 UINT32 CmObjRefCount
;
287 PPTT_NODE_INDEXER
*PpttNodeFound
;
290 (Generator
!= NULL
) &&
291 (CfgMgrProtocol
!= NULL
) &&
292 (PrivResArray
!= NULL
) &&
296 // Validate input arguments
297 if (PrivResArrayToken
== CM_NULL_TOKEN
) {
298 Status
= EFI_INVALID_PARAMETER
;
301 "ERROR: PPTT: The number of private resources is %d while " \
302 "PrivResToken = CM_NULL_TOKEN. Status = %r\n",
310 // Get the CM Object References
311 Status
= GetEArmObjCmRef (
317 if (EFI_ERROR (Status
)) {
320 "ERROR: PPTT: Failed to get CM Object References. " \
321 "PrivResToken = %p. Status = %r\n",
328 if (CmObjRefCount
!= PrivResCount
) {
329 Status
= EFI_INVALID_PARAMETER
;
332 "ERROR: PPTT: The number of CM Object References retrieved and the " \
333 "number of private resources don't match. CmObjRefCount = %d. " \
334 "PrivResourceCount = %d. PrivResToken = %p. Status = %r\n",
343 while (PrivResCount
-- != 0) {
344 if (CmObjRefs
->ReferenceToken
== CM_NULL_TOKEN
) {
345 Status
= EFI_INVALID_PARAMETER
;
348 "ERROR: PPTT: CM_NULL_TOKEN provided as reference token for a " \
349 "private resource. Status = %r\n",
355 // The Node indexer has the Processor hierarchy nodes at the begining
356 // followed by the cache structs. Therefore we can skip the Processor
357 // hierarchy nodes in the node indexer search.
358 Status
= GetPpttNodeReferencedByToken (
359 Generator
->CacheStructIndexedList
,
360 (Generator
->ProcTopologyStructCount
-
361 Generator
->ProcHierarchyNodeCount
),
362 CmObjRefs
->ReferenceToken
,
365 if (EFI_ERROR (Status
)) {
368 "ERROR: PPTT: Failed to get a private resource with Token = %p from " \
369 "Node Indexer. Status = %r\n",
370 CmObjRefs
->ReferenceToken
,
376 // Update the offset of the private resources in the Processor
377 // Hierarchy Node structure
378 *(PrivResArray
++) = PpttNodeFound
->Offset
;
386 Function to test if two indexed Processor Hierarchy Info objects map to the
387 same GIC CPU Interface Info object.
389 This is a callback function that can be invoked by FindDuplicateValue ().
391 @param [in] Object1 Pointer to the first indexed Processor Hierarchy
393 @param [in] Object2 Pointer to the second indexed Processor Hierarchy
395 @param [in] Index1 Index of Object1 to be displayed for debugging
397 @param [in] Index2 Index of Object2 to be displayed for debugging
400 @retval TRUE Object1 and Object2 have the same GicCToken.
401 @retval FALSE Object1 and Object2 have different GicCTokens.
406 IN CONST VOID
*Object1
,
407 IN CONST VOID
*Object2
,
412 PPTT_NODE_INDEXER
*IndexedObject1
;
413 PPTT_NODE_INDEXER
*IndexedObject2
;
414 CM_ARM_PROC_HIERARCHY_INFO
*ProcNode1
;
415 CM_ARM_PROC_HIERARCHY_INFO
*ProcNode2
;
422 IndexedObject1
= (PPTT_NODE_INDEXER
*)Object1
;
423 IndexedObject2
= (PPTT_NODE_INDEXER
*)Object2
;
424 ProcNode1
= (CM_ARM_PROC_HIERARCHY_INFO
*)IndexedObject1
->Object
;
425 ProcNode2
= (CM_ARM_PROC_HIERARCHY_INFO
*)IndexedObject2
->Object
;
427 if (IS_ACPI_PROC_ID_VALID (ProcNode1
) &&
428 IS_ACPI_PROC_ID_VALID (ProcNode2
) &&
429 (ProcNode1
->GicCToken
!= CM_NULL_TOKEN
) &&
430 (ProcNode2
->GicCToken
!= CM_NULL_TOKEN
) &&
431 (ProcNode1
->GicCToken
== ProcNode2
->GicCToken
))
435 "ERROR: PPTT: Two Processor Hierarchy Info objects (%d and %d) map to " \
436 "the same GICC Info object. ACPI Processor IDs are not unique. " \
439 IndexedObject1
->Token
,
450 Update the Processor Hierarchy Node (Type 0) information.
452 This function populates the Processor Hierarchy Nodes with information from
453 the Configuration Manager and adds this information to the PPTT table.
455 @param [in] Generator Pointer to the PPTT Generator.
456 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
458 @param [in] Pptt Pointer to PPTT table structure.
459 @param [in] NodesStartOffset Offset from the start of PPTT table to the
460 start of Processor Hierarchy Nodes.
462 @retval EFI_SUCCESS Node updated successfully.
463 @retval EFI_INVALID_PARAMETER A parameter is invalid.
464 @retval EFI_NOT_FOUND The required object was not found.
468 AddProcHierarchyNodes (
469 IN CONST ACPI_PPTT_GENERATOR
*CONST Generator
,
470 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
471 IN CONST EFI_ACPI_6_4_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
*Pptt
,
472 IN CONST UINT32 NodesStartOffset
476 EFI_ACPI_6_4_PPTT_STRUCTURE_PROCESSOR
*ProcStruct
;
477 UINT32
*PrivateResources
;
478 BOOLEAN IsGicCTokenDuplicated
;
480 CM_ARM_GICC_INFO
*GicCInfoList
;
481 UINT32 GicCInfoCount
;
482 UINT32 UniqueGicCRefCount
;
484 PPTT_NODE_INDEXER
*PpttNodeFound
;
485 CM_ARM_PROC_HIERARCHY_INFO
*ProcInfoNode
;
487 PPTT_NODE_INDEXER
*ProcNodeIterator
;
492 (Generator
!= NULL
) &&
493 (CfgMgrProtocol
!= NULL
) &&
497 ProcStruct
= (EFI_ACPI_6_4_PPTT_STRUCTURE_PROCESSOR
*)((UINT8
*)Pptt
+
500 ProcNodeIterator
= Generator
->ProcHierarchyNodeIndexedList
;
501 NodeCount
= Generator
->ProcHierarchyNodeCount
;
503 // Check if every GICC Object is referenced by onlu one Proc Node
504 IsGicCTokenDuplicated
= FindDuplicateValue (
507 sizeof (PPTT_NODE_INDEXER
),
510 // Duplicate GIC CPU Interface Token was found so two PPTT Processor Hierarchy
511 // Nodes map to the same MADT GICC structure
512 if (IsGicCTokenDuplicated
) {
513 return EFI_INVALID_PARAMETER
;
516 UniqueGicCRefCount
= 0;
518 while (NodeCount
-- != 0) {
519 ProcInfoNode
= (CM_ARM_PROC_HIERARCHY_INFO
*)ProcNodeIterator
->Object
;
521 // Check if the private resource count is within the size limit
522 // imposed on the Processor Hierarchy node by the specification.
523 // Note: The length field is 8 bit wide while the number of private
524 // resource field is 32 bit wide.
525 Length
= GetProcHierarchyNodeSize (ProcInfoNode
);
526 if (Length
> MAX_UINT8
) {
527 Status
= EFI_INVALID_PARAMETER
;
530 "ERROR: PPTT: Too many private resources. Count = %d. " \
531 "Maximum supported Processor Node size exceeded. " \
532 "Token = %p. Status = %r\n",
533 ProcInfoNode
->NoOfPrivateResources
,
534 ProcInfoNode
->ParentToken
,
540 // Populate the node header
541 ProcStruct
->Type
= EFI_ACPI_6_4_PPTT_TYPE_PROCESSOR
;
542 ProcStruct
->Length
= (UINT8
)Length
;
543 ProcStruct
->Reserved
[0] = EFI_ACPI_RESERVED_BYTE
;
544 ProcStruct
->Reserved
[1] = EFI_ACPI_RESERVED_BYTE
;
546 // Populate the flags
547 ProcStruct
->Flags
.PhysicalPackage
= ProcInfoNode
->Flags
& BIT0
;
548 ProcStruct
->Flags
.AcpiProcessorIdValid
= (ProcInfoNode
->Flags
& BIT1
) >> 1;
549 ProcStruct
->Flags
.ProcessorIsAThread
= (ProcInfoNode
->Flags
& BIT2
) >> 2;
550 ProcStruct
->Flags
.NodeIsALeaf
= (ProcInfoNode
->Flags
& BIT3
) >> 3;
551 ProcStruct
->Flags
.IdenticalImplementation
=
552 (ProcInfoNode
->Flags
& BIT4
) >> 4;
553 ProcStruct
->Flags
.Reserved
= 0;
555 // Populate the parent reference
556 if (ProcInfoNode
->ParentToken
== CM_NULL_TOKEN
) {
557 ProcStruct
->Parent
= 0;
559 Status
= GetPpttNodeReferencedByToken (
560 Generator
->ProcHierarchyNodeIndexedList
,
561 Generator
->ProcHierarchyNodeCount
,
562 ProcInfoNode
->ParentToken
,
565 if (EFI_ERROR (Status
)) {
568 "ERROR: PPTT: Failed to get parent processor hierarchy node " \
569 "reference. Token = %p, Status = %r\n",
570 ProcInfoNode
->ParentToken
,
577 // Test if the reference is to a 'leaf' node
578 if (IS_PROC_NODE_LEAF (
579 ((CM_ARM_PROC_HIERARCHY_INFO
*)PpttNodeFound
->Object
)
582 Status
= EFI_INVALID_PARAMETER
;
585 "ERROR: PPTT: Reference to a leaf Processor Hierarchy Node. " \
586 "ParentToken = %p. ChildToken = %p. Status = %r\n",
587 ProcInfoNode
->ParentToken
,
594 // Update Proc Structure with the offset of the parent node
595 ProcStruct
->Parent
= PpttNodeFound
->Offset
;
597 // Store the reference for the parent node in the Node Indexer
598 // so that this can be used later for cycle detection
599 ProcNodeIterator
->TopologyParent
= PpttNodeFound
;
602 // Populate ACPI Processor ID
603 if (!IS_ACPI_PROC_ID_VALID (ProcInfoNode
)) {
604 // Default invalid ACPI Processor ID to 0
605 ProcStruct
->AcpiProcessorId
= 0;
606 } else if (ProcInfoNode
->GicCToken
== CM_NULL_TOKEN
) {
607 Status
= EFI_INVALID_PARAMETER
;
610 "ERROR: PPTT: The 'ACPI Processor ID valid' flag is set but no GICC " \
611 "structure token was provided. GicCToken = %p. RequestorToken = %p. " \
613 ProcInfoNode
->GicCToken
,
619 Status
= GetEArmObjGicCInfo (
621 ProcInfoNode
->GicCToken
,
625 if (EFI_ERROR (Status
)) {
628 "ERROR: PPTT: Failed to get GICC structure. ACPI Processor ID " \
629 "can't be populated. GicCToken = %p. RequestorToken = %p. " \
631 ProcInfoNode
->GicCToken
,
638 if (GicCInfoCount
!= 1) {
639 Status
= EFI_INVALID_PARAMETER
;
642 "ERROR: PPTT: Failed to find a unique GICC structure. " \
643 "ACPI Processor ID can't be populated. " \
644 "GICC Structure Count = %d. GicCToken = %p. RequestorToken = %p " \
647 ProcInfoNode
->GicCToken
,
654 // Update the ACPI Processor Id
655 ProcStruct
->AcpiProcessorId
= GicCInfoList
->AcpiProcessorUid
;
657 // Increment the reference count for the number of
658 // Unique GICC objects that were retrieved.
659 UniqueGicCRefCount
++;
662 ProcStruct
->NumberOfPrivateResources
= ProcInfoNode
->NoOfPrivateResources
;
663 PrivateResources
= (UINT32
*)((UINT8
*)ProcStruct
+
664 sizeof (EFI_ACPI_6_4_PPTT_STRUCTURE_PROCESSOR
));
666 if (ProcStruct
->NumberOfPrivateResources
!= 0) {
667 // Populate the private resources array
668 Status
= AddPrivateResources (
672 ProcStruct
->NumberOfPrivateResources
,
673 ProcInfoNode
->PrivateResourcesArrayToken
675 if (EFI_ERROR (Status
)) {
678 "ERROR: PPTT: Failed to populate the private resources array. " \
686 // Next Processor Hierarchy Node
687 ProcStruct
= (EFI_ACPI_6_4_PPTT_STRUCTURE_PROCESSOR
*)((UINT8
*)ProcStruct
+
690 } // Processor Hierarchy Node
692 // Knowing the total number of GICC references made and that all GICC Token
693 // references are unique, we can test if no GICC instances have been left out.
694 Status
= GetEArmObjGicCInfo (
700 if (EFI_ERROR (Status
)) {
703 "ERROR: PPTT: Failed to get GICC Info. Status = %r\n",
709 // MADT - PPTT cross validation
710 // This checks that one and only one GICC structure is referenced by a
711 // Processor Hierarchy Node in the PPTT.
712 // Since we have already checked that the GICC objects referenced by the
713 // Proc Nodes are unique, the UniqueGicCRefCount cannot be greater than
714 // the total number of GICC objects in the platform.
715 if (GicCInfoCount
> UniqueGicCRefCount
) {
716 Status
= EFI_INVALID_PARAMETER
;
719 "ERROR: PPTT: %d GICC structure(s) exposed by MADT don't have " \
720 "a corresponding Processor Hierarchy Node. Status = %r\n",
721 GicCInfoCount
- UniqueGicCRefCount
,
730 Test whether CacheId is unique among the CacheIdList.
732 @param [in] CacheId Cache ID to check.
733 @param [in] CacheIdList List of already existing cache IDs.
734 @param [in] CacheIdListSize Size of CacheIdList.
736 @retval TRUE CacheId does not exist in CacheIdList.
737 @retval FALSE CacheId already exists in CacheIdList.
742 IN CONST UINT32 CacheId
,
743 IN CONST UINT32
*CacheIdList
,
744 IN CONST UINT32 CacheIdListSize
749 for (Index
= 0; Index
< CacheIdListSize
; Index
++) {
750 if (CacheIdList
[Index
] == CacheId
) {
759 Update the Cache Type Structure (Type 1) information.
761 This function populates the Cache Type Structures with information from
762 the Configuration Manager and adds this information to the PPTT table.
764 @param [in] Generator Pointer to the PPTT Generator.
765 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
767 @param [in] Pptt Pointer to PPTT table structure.
768 @param [in] NodesStartOffset Offset from the start of PPTT table to the
769 start of Cache Type Structures.
770 @param [in] Revision Revision of the PPTT table being requested.
772 @retval EFI_SUCCESS Structures updated successfully.
773 @retval EFI_INVALID_PARAMETER A parameter is invalid.
774 @retval EFI_NOT_FOUND A required object was not found.
775 @retval EFI_OUT_OF_RESOURCES Out of resources.
779 AddCacheTypeStructures (
780 IN CONST ACPI_PPTT_GENERATOR
*CONST Generator
,
781 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
782 IN CONST EFI_ACPI_6_4_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
*Pptt
,
783 IN CONST UINT32 NodesStartOffset
,
784 IN CONST UINT32 Revision
788 EFI_ACPI_6_4_PPTT_STRUCTURE_CACHE
*CacheStruct
;
789 PPTT_NODE_INDEXER
*PpttNodeFound
;
790 CM_ARM_CACHE_INFO
*CacheInfoNode
;
791 PPTT_NODE_INDEXER
*CacheNodeIterator
;
793 BOOLEAN CacheIdUnique
;
795 UINT32
*FoundCacheIds
;
798 (Generator
!= NULL
) &&
799 (CfgMgrProtocol
!= NULL
) &&
803 CacheStruct
= (EFI_ACPI_6_4_PPTT_STRUCTURE_CACHE
*)((UINT8
*)Pptt
+
806 CacheNodeIterator
= Generator
->CacheStructIndexedList
;
807 NodeCount
= Generator
->CacheStructCount
;
809 FoundCacheIds
= AllocateZeroPool (NodeCount
* sizeof (*FoundCacheIds
));
810 if (FoundCacheIds
== NULL
) {
811 DEBUG ((DEBUG_ERROR
, "ERROR: PPTT: Failed to allocate resources.\n"));
812 return EFI_OUT_OF_RESOURCES
;
815 for (NodeIndex
= 0; NodeIndex
< NodeCount
; NodeIndex
++) {
816 CacheInfoNode
= (CM_ARM_CACHE_INFO
*)CacheNodeIterator
->Object
;
818 // Populate the node header
819 CacheStruct
->Type
= EFI_ACPI_6_4_PPTT_TYPE_CACHE
;
820 CacheStruct
->Length
= sizeof (EFI_ACPI_6_4_PPTT_STRUCTURE_CACHE
);
821 CacheStruct
->Reserved
[0] = EFI_ACPI_RESERVED_BYTE
;
822 CacheStruct
->Reserved
[1] = EFI_ACPI_RESERVED_BYTE
;
824 // "On Arm-based systems, all cache properties must be provided in the
825 // table." (ACPI 6.4, Section 5.2.29.2)
826 CacheStruct
->Flags
.SizePropertyValid
= 1;
827 CacheStruct
->Flags
.NumberOfSetsValid
= 1;
828 CacheStruct
->Flags
.AssociativityValid
= 1;
829 CacheStruct
->Flags
.AllocationTypeValid
= 1;
830 CacheStruct
->Flags
.CacheTypeValid
= 1;
831 CacheStruct
->Flags
.WritePolicyValid
= 1;
832 CacheStruct
->Flags
.LineSizeValid
= 1;
833 CacheStruct
->Flags
.CacheIdValid
= 1;
834 CacheStruct
->Flags
.Reserved
= 0;
836 // Populate the reference to the next level of cache
837 if (CacheInfoNode
->NextLevelOfCacheToken
== CM_NULL_TOKEN
) {
838 CacheStruct
->NextLevelOfCache
= 0;
840 Status
= GetPpttNodeReferencedByToken (
841 Generator
->CacheStructIndexedList
,
842 Generator
->CacheStructCount
,
843 CacheInfoNode
->NextLevelOfCacheToken
,
846 if (EFI_ERROR (Status
)) {
849 "ERROR: PPTT: Failed to get the reference to the Next Level of " \
850 "Cache. NextLevelOfCacheToken = %p. RequestorToken = %p. " \
852 CacheInfoNode
->NextLevelOfCacheToken
,
853 CacheInfoNode
->Token
,
859 // Update Cache Structure with the offset for the next level of cache
860 CacheStruct
->NextLevelOfCache
= PpttNodeFound
->Offset
;
862 // Store the next level of cache information in the Node Indexer
863 // so that this can be used later for cycle detection
864 CacheNodeIterator
->TopologyParent
= PpttNodeFound
;
867 CacheStruct
->Size
= CacheInfoNode
->Size
;
869 // Validate and populate the 'Number of sets' field
870 if (CacheInfoNode
->NumberOfSets
> PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX
) {
871 Status
= EFI_INVALID_PARAMETER
;
874 "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum number " \
875 "of sets can be %d. NumberOfSets = %d. Status = %r\n",
876 PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX
,
877 CacheInfoNode
->NumberOfSets
,
883 if (CacheInfoNode
->NumberOfSets
> PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX
) {
886 "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \
887 "number of sets can be %d. NumberOfSets = %d\n",
888 PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX
,
889 CacheInfoNode
->NumberOfSets
893 CacheStruct
->NumberOfSets
= CacheInfoNode
->NumberOfSets
;
895 // Validate Associativity field based on maximum associativity
896 // supported by ACPI Cache type structure.
897 if (CacheInfoNode
->Associativity
> MAX_UINT8
) {
898 Status
= EFI_INVALID_PARAMETER
;
901 "ERROR: PPTT: The maximum associativity supported by ACPI " \
902 "Cache type structure is %d. Associativity = %d, Status = %r\n",
904 CacheInfoNode
->Associativity
,
910 // Validate the Associativity field based on the architecture specification
911 // The architecture supports much larger associativity values than the
912 // current ACPI specification.
913 // These checks will be needed in the future when the ACPI specification
914 // is extended. Disabling this code for now.
916 if (CacheInfoNode
->Associativity
> PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX
) {
917 Status
= EFI_INVALID_PARAMETER
;
920 "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum cache " \
921 "associativity can be %d. Associativity = %d. Status = %r\n",
922 PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX
,
923 CacheInfoNode
->Associativity
,
929 if (CacheInfoNode
->Associativity
> PPTT_ARM_CACHE_ASSOCIATIVITY_MAX
) {
932 "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \
933 "cache associativity can be %d. Associativity = %d\n",
934 PPTT_ARM_CACHE_ASSOCIATIVITY_MAX
,
935 CacheInfoNode
->Associativity
941 // Note a typecast is needed as the maximum associativity
942 // supported by ACPI Cache type structure is MAX_UINT8.
943 CacheStruct
->Associativity
= (UINT8
)CacheInfoNode
->Associativity
;
945 // Populate cache attributes
946 CacheStruct
->Attributes
.AllocationType
=
947 CacheInfoNode
->Attributes
& (BIT0
| BIT1
);
948 CacheStruct
->Attributes
.CacheType
=
949 (CacheInfoNode
->Attributes
& (BIT2
| BIT3
)) >> 2;
950 CacheStruct
->Attributes
.WritePolicy
=
951 (CacheInfoNode
->Attributes
& BIT4
) >> 4;
952 CacheStruct
->Attributes
.Reserved
= 0;
954 // Validate and populate cache line size
955 if ((CacheInfoNode
->LineSize
< PPTT_ARM_CACHE_LINE_SIZE_MIN
) ||
956 (CacheInfoNode
->LineSize
> PPTT_ARM_CACHE_LINE_SIZE_MAX
))
958 Status
= EFI_INVALID_PARAMETER
;
961 "ERROR: PPTT: The cache line size must be between %d and %d bytes " \
962 "on ARM Platforms. LineSize = %d. Status = %r\n",
963 PPTT_ARM_CACHE_LINE_SIZE_MIN
,
964 PPTT_ARM_CACHE_LINE_SIZE_MAX
,
965 CacheInfoNode
->LineSize
,
971 if ((CacheInfoNode
->LineSize
& (CacheInfoNode
->LineSize
- 1)) != 0) {
972 Status
= EFI_INVALID_PARAMETER
;
975 "ERROR: PPTT: The cache line size is not a power of 2. " \
976 "LineSize = %d. Status = %r\n",
977 CacheInfoNode
->LineSize
,
983 CacheStruct
->LineSize
= CacheInfoNode
->LineSize
;
986 // Validate and populate cache id
987 if (CacheInfoNode
->CacheId
== 0) {
988 Status
= EFI_INVALID_PARAMETER
;
991 "ERROR: PPTT: The cache id cannot be zero. Status = %r\n",
997 CacheIdUnique
= IsCacheIdUnique (
998 CacheInfoNode
->CacheId
,
1002 if (!CacheIdUnique
) {
1003 Status
= EFI_INVALID_PARAMETER
;
1006 "ERROR: PPTT: The cache id is not unique. " \
1007 "CacheId = %d. Status = %r\n",
1008 CacheInfoNode
->CacheId
,
1014 // Store the cache id so we can check future cache ids for uniqueness
1015 FoundCacheIds
[NodeIndex
] = CacheInfoNode
->CacheId
;
1017 CacheStruct
->CacheId
= CacheInfoNode
->CacheId
;
1020 // Next Cache Type Structure
1021 CacheStruct
= (EFI_ACPI_6_4_PPTT_STRUCTURE_CACHE
*)((UINT8
*)CacheStruct
+
1022 CacheStruct
->Length
);
1023 CacheNodeIterator
++;
1024 } // for Cache Type Structure
1026 Status
= EFI_SUCCESS
;
1029 FreePool (FoundCacheIds
);
1035 Construct the PPTT ACPI table.
1037 This function invokes the Configuration Manager protocol interface
1038 to get the required hardware information for generating the ACPI
1041 If this function allocates any resources then they must be freed
1042 in the FreeXXXXTableResources function.
1044 @param [in] This Pointer to the table generator.
1045 @param [in] AcpiTableInfo Pointer to the ACPI table generator to be used.
1046 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1048 @param [out] Table Pointer to the constructed ACPI Table.
1050 @retval EFI_SUCCESS Table generated successfully.
1051 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1052 @retval EFI_NOT_FOUND The required object was not found.
1053 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
1054 Manager is less than the Object size for
1055 the requested object.
1061 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
1062 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
1063 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1064 OUT EFI_ACPI_DESCRIPTION_HEADER
**CONST Table
1069 UINT32 ProcTopologyStructCount
;
1070 UINT32 ProcHierarchyNodeCount
;
1071 UINT32 CacheStructCount
;
1073 UINT32 ProcHierarchyNodeOffset
;
1074 UINT32 CacheStructOffset
;
1076 CM_ARM_PROC_HIERARCHY_INFO
*ProcHierarchyNodeList
;
1077 CM_ARM_CACHE_INFO
*CacheStructList
;
1079 ACPI_PPTT_GENERATOR
*Generator
;
1081 // Pointer to the Node Indexer array
1082 PPTT_NODE_INDEXER
*NodeIndexer
;
1084 EFI_ACPI_6_4_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
*Pptt
;
1088 (AcpiTableInfo
!= NULL
) &&
1089 (CfgMgrProtocol
!= NULL
) &&
1091 (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
) &&
1092 (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
)
1095 if ((AcpiTableInfo
->AcpiTableRevision
< This
->MinAcpiTableRevision
) ||
1096 (AcpiTableInfo
->AcpiTableRevision
> This
->AcpiTableRevision
))
1100 "ERROR: PPTT: Requested table revision = %d is not supported. "
1101 "Supported table revisions: Minimum = %d. Maximum = %d\n",
1102 AcpiTableInfo
->AcpiTableRevision
,
1103 This
->MinAcpiTableRevision
,
1104 This
->AcpiTableRevision
1106 return EFI_INVALID_PARAMETER
;
1109 Generator
= (ACPI_PPTT_GENERATOR
*)This
;
1112 // Get the processor hierarchy info and update the processor topology
1113 // structure count with Processor Hierarchy Nodes (Type 0)
1114 Status
= GetEArmObjProcHierarchyInfo (
1117 &ProcHierarchyNodeList
,
1118 &ProcHierarchyNodeCount
1120 if (EFI_ERROR (Status
)) {
1123 "ERROR: PPTT: Failed to get processor hierarchy info. Status = %r\n",
1129 ProcTopologyStructCount
= ProcHierarchyNodeCount
;
1130 Generator
->ProcHierarchyNodeCount
= ProcHierarchyNodeCount
;
1132 // Get the cache info and update the processor topology structure count with
1133 // Cache Type Structures (Type 1)
1134 Status
= GetEArmObjCacheInfo (
1140 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1143 "ERROR: PPTT: Failed to get cache info. Status = %r\n",
1149 ProcTopologyStructCount
+= CacheStructCount
;
1150 Generator
->CacheStructCount
= CacheStructCount
;
1152 // Allocate Node Indexer array
1153 NodeIndexer
= (PPTT_NODE_INDEXER
*)AllocateZeroPool (
1154 sizeof (PPTT_NODE_INDEXER
) *
1155 ProcTopologyStructCount
1157 if (NodeIndexer
== NULL
) {
1158 Status
= EFI_OUT_OF_RESOURCES
;
1161 "ERROR: PPTT: Failed to allocate memory for Node Indexer. Status = %r\n ",
1167 DEBUG ((DEBUG_INFO
, "INFO: NodeIndexer = %p\n", NodeIndexer
));
1168 Generator
->ProcTopologyStructCount
= ProcTopologyStructCount
;
1169 Generator
->NodeIndexer
= NodeIndexer
;
1171 // Calculate the size of the PPTT table
1172 TableSize
= sizeof (EFI_ACPI_6_4_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
);
1174 // Include the size of Processor Hierarchy Nodes and index them
1175 if (Generator
->ProcHierarchyNodeCount
!= 0) {
1176 ProcHierarchyNodeOffset
= TableSize
;
1177 Generator
->ProcHierarchyNodeIndexedList
= NodeIndexer
;
1178 TableSize
+= GetSizeofProcHierarchyNodes (
1179 ProcHierarchyNodeOffset
,
1180 ProcHierarchyNodeList
,
1181 Generator
->ProcHierarchyNodeCount
,
1187 " ProcHierarchyNodeCount = %d\n" \
1188 " ProcHierarchyNodeOffset = 0x%x\n" \
1189 " ProcHierarchyNodeIndexedList = 0x%p\n",
1190 Generator
->ProcHierarchyNodeCount
,
1191 ProcHierarchyNodeOffset
,
1192 Generator
->ProcHierarchyNodeIndexedList
1196 // Include the size of Cache Type Structures and index them
1197 if (Generator
->CacheStructCount
!= 0) {
1198 CacheStructOffset
= TableSize
;
1199 Generator
->CacheStructIndexedList
= NodeIndexer
;
1200 TableSize
+= GetSizeofCacheTypeStructs (
1203 Generator
->CacheStructCount
,
1208 " CacheStructCount = %d\n" \
1209 " CacheStructOffset = 0x%x\n" \
1210 " CacheStructIndexedList = 0x%p\n",
1211 Generator
->CacheStructCount
,
1213 Generator
->CacheStructIndexedList
1220 " ProcTopologyStructCount = %d\n" \
1221 " TableSize = %d\n",
1222 ProcTopologyStructCount
,
1226 // Allocate the Buffer for the PPTT table
1227 *Table
= (EFI_ACPI_DESCRIPTION_HEADER
*)AllocateZeroPool (TableSize
);
1228 if (*Table
== NULL
) {
1229 Status
= EFI_OUT_OF_RESOURCES
;
1232 "ERROR: PPTT: Failed to allocate memory for PPTT Table. " \
1233 "Size = %d. Status = %r\n",
1240 Pptt
= (EFI_ACPI_6_4_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
*)*Table
;
1244 "PPTT: Pptt = 0x%p. TableSize = 0x%x\n",
1250 Status
= AddAcpiHeader (
1257 if (EFI_ERROR (Status
)) {
1260 "ERROR: PPTT: Failed to add ACPI header. Status = %r\n",
1266 // Add Processor Hierarchy Nodes (Type 0) to the generated table
1267 if (Generator
->ProcHierarchyNodeCount
!= 0) {
1268 Status
= AddProcHierarchyNodes (
1272 ProcHierarchyNodeOffset
1274 if (EFI_ERROR (Status
)) {
1277 "ERROR: PPTT: Failed to add Processor Hierarchy Nodes. Status = %r\n",
1284 // Add Cache Type Structures (Type 1) to the generated table
1285 if (Generator
->CacheStructCount
!= 0) {
1286 Status
= AddCacheTypeStructures (
1291 AcpiTableInfo
->AcpiTableRevision
1293 if (EFI_ERROR (Status
)) {
1296 "ERROR: PPTT: Failed to add Cache Type Structures. Status = %r\n",
1303 // Validate CM object cross-references in PPTT
1304 Status
= DetectCyclesInTopology (Generator
);
1305 if (EFI_ERROR (Status
)) {
1308 "ERROR: PPTT: Invalid processor and cache topology. Status = %r\n",
1317 if (Generator
->NodeIndexer
!= NULL
) {
1318 FreePool (Generator
->NodeIndexer
);
1319 Generator
->NodeIndexer
= NULL
;
1322 if (*Table
!= NULL
) {
1331 Free any resources allocated for constructing the PPTT
1333 @param [in] This Pointer to the table generator.
1334 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1335 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1337 @param [in, out] Table Pointer to the ACPI Table.
1339 @retval EFI_SUCCESS The resources were freed successfully.
1340 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
1344 FreePpttTableResources (
1345 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
1346 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
1347 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1348 IN OUT EFI_ACPI_DESCRIPTION_HEADER
**CONST Table
1351 ACPI_PPTT_GENERATOR
*Generator
;
1355 (AcpiTableInfo
!= NULL
) &&
1356 (CfgMgrProtocol
!= NULL
) &&
1357 (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
) &&
1358 (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
)
1361 Generator
= (ACPI_PPTT_GENERATOR
*)This
;
1363 // Free any memory allocated by the generator
1364 if (Generator
->NodeIndexer
!= NULL
) {
1365 FreePool (Generator
->NodeIndexer
);
1366 Generator
->NodeIndexer
= NULL
;
1369 if ((Table
== NULL
) || (*Table
== NULL
)) {
1370 DEBUG ((DEBUG_ERROR
, "ERROR: PPTT: Invalid Table Pointer\n"));
1375 return EFI_INVALID_PARAMETER
;
1383 /** The PPTT Table Generator revision.
1385 #define PPTT_GENERATOR_REVISION CREATE_REVISION (1, 0)
1387 /** The interface for the PPTT Table Generator.
1390 ACPI_PPTT_GENERATOR PpttGenerator
= {
1391 // ACPI table generator header
1394 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdPptt
),
1395 // Generator Description
1396 L
"ACPI.STD.PPTT.GENERATOR",
1397 // ACPI Table Signature
1398 EFI_ACPI_6_4_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE
,
1399 // ACPI Table Revision supported by this Generator
1400 EFI_ACPI_6_4_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION
,
1401 // Minimum supported ACPI Table Revision
1402 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION
,
1404 TABLE_GENERATOR_CREATOR_ID_ARM
,
1406 PPTT_GENERATOR_REVISION
,
1407 // Build Table function
1409 // Free Resource function
1410 FreePpttTableResources
,
1411 // Extended build function not needed
1413 // Extended build function not implemented by the generator.
1414 // Hence extended free resource function is not required.
1418 // PPTT Generator private data
1420 // Processor topology node count
1422 // Count of Processor Hierarchy Nodes
1424 // Count of Cache Structures
1426 // Pointer to PPTT Node Indexer
1431 Register the Generator with the ACPI Table Factory.
1433 @param [in] ImageHandle The handle to the image.
1434 @param [in] SystemTable Pointer to the System Table.
1436 @retval EFI_SUCCESS The Generator is registered.
1437 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1438 @retval EFI_ALREADY_STARTED The Generator for the Table ID
1439 is already registered.
1443 AcpiPpttLibConstructor (
1444 IN EFI_HANDLE ImageHandle
,
1445 IN EFI_SYSTEM_TABLE
*SystemTable
1450 Status
= RegisterAcpiTableGenerator (&PpttGenerator
.Header
);
1451 DEBUG ((DEBUG_INFO
, "PPTT: Register Generator. Status = %r\n", Status
));
1452 ASSERT_EFI_ERROR (Status
);
1457 Deregister the Generator from the ACPI Table Factory.
1459 @param [in] ImageHandle The handle to the image.
1460 @param [in] SystemTable Pointer to the System Table.
1462 @retval EFI_SUCCESS The Generator is deregistered.
1463 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1464 @retval EFI_NOT_FOUND The Generator is not registered.
1468 AcpiPpttLibDestructor (
1469 IN EFI_HANDLE ImageHandle
,
1470 IN EFI_SYSTEM_TABLE
*SystemTable
1475 Status
= DeregisterAcpiTableGenerator (&PpttGenerator
.Header
);
1476 DEBUG ((DEBUG_INFO
, "PPTT: Deregister Generator. Status = %r\n", Status
));
1477 ASSERT_EFI_ERROR (Status
);