4 Copyright (c) 2019, ARM Limited. All rights reserved.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
8 - ACPI 6.3 Specification, January 2019
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)
37 - EArmObjProcNodeIdInfo
39 - EArmObjGicCInfo (REQUIRED)
43 This macro expands to a function that retrieves the Processor Hierarchy
44 information from the Configuration Manager.
48 EArmObjProcHierarchyInfo
,
49 CM_ARM_PROC_HIERARCHY_INFO
53 This macro expands to a function that retrieves the cache information
54 from the Configuration Manager.
63 This macro expands to a function that retrieves the ID information for
64 Processor Hierarchy Nodes from the Configuration Manager.
68 EArmObjProcNodeIdInfo
,
69 CM_ARM_PROC_NODE_ID_INFO
73 This macro expands to a function that retrieves the cross-CM-object-
74 reference information from the Configuration Manager.
83 This macro expands to a function that retrieves the GIC CPU interface
84 information from the Configuration Manager.
93 Returns the size of the PPTT Processor Hierarchy Node (Type 0) given a
94 Processor Hierarchy Info CM object.
96 @param [in] Node Pointer to Processor Hierarchy Info CM object which
97 represents the Processor Hierarchy Node to be generated.
99 @retval Size of the Processor Hierarchy Node in bytes.
103 GetProcHierarchyNodeSize (
104 IN CONST CM_ARM_PROC_HIERARCHY_INFO
*Node
107 ASSERT (Node
!= NULL
);
109 // <size of Processor Hierarchy Node> + <size of Private Resources array>
110 return sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR
) +
111 (Node
->NoOfPrivateResources
* sizeof (UINT32
));
115 This macro expands to a function that retrieves the amount of memory required
116 to store the Processor Hierarchy Nodes (Type 0) and updates the Node Indexer.
118 GET_SIZE_OF_PPTT_STRUCTS (
120 GetProcHierarchyNodeSize (NodesToIndex
),
121 CM_ARM_PROC_HIERARCHY_INFO
125 This macro expands to a function that retrieves the amount of memory required
126 to store the Cache Type Structures (Type 1) and updates the Node Indexer.
128 GET_SIZE_OF_PPTT_STRUCTS (
130 sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE
),
134 /** This macro expands to a function that retrieves the amount of memory
135 required to store the ID Structures (Type 2) and updates the Node Indexer.
137 GET_SIZE_OF_PPTT_STRUCTS (
139 sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_ID
),
140 CM_ARM_PROC_NODE_ID_INFO
144 Search the Node Indexer and return the indexed PPTT node with the given
147 @param [in] NodeIndexer Pointer to the Node Indexer array.
148 @param [in] NodeCount Number of elements in Node Indexer.
149 @param [in] SearchToken Token used for Node Indexer lookup.
150 @param [out] IndexedNodeFound Pointer to the Node Indexer array element
151 with the given Token.
153 @retval EFI_SUCCESS Success.
154 @retval EFI_NOT_FOUND No element with a matching token was
155 found in the Node Indexer array.
159 GetPpttNodeReferencedByToken (
160 IN PPTT_NODE_INDEXER
*NodeIndexer
,
162 IN CONST CM_OBJECT_TOKEN SearchToken
,
163 OUT PPTT_NODE_INDEXER
**IndexedNodeFound
168 ASSERT (NodeIndexer
!= NULL
);
172 "PPTT: Node Indexer: SearchToken = %p\n",
176 while (NodeCount
-- != 0) {
179 "PPTT: Node Indexer: NodeIndexer->Token = %p. Offset = %d\n",
184 if (NodeIndexer
->Token
== SearchToken
) {
185 *IndexedNodeFound
= NodeIndexer
;
186 Status
= EFI_SUCCESS
;
189 "PPTT: Node Indexer: Token = %p. Found, Status = %r\n",
199 Status
= EFI_NOT_FOUND
;
202 "PPTT: Node Indexer: SearchToken = %p. Status = %r\n",
211 Detect cycles in the processor and cache topology graph represented in
214 @param [in] Generator Pointer to the PPTT Generator.
216 @retval EFI_SUCCESS There are no cyclic references in the graph.
217 @retval EFI_INVALID_PARAMETER Processor or cache references form a cycle.
221 DetectCyclesInTopology (
222 IN CONST ACPI_PPTT_GENERATOR
*CONST Generator
226 PPTT_NODE_INDEXER
*Iterator
;
227 PPTT_NODE_INDEXER
*CycleDetector
;
228 UINT32 NodesRemaining
;
230 ASSERT (Generator
!= NULL
);
232 Iterator
= Generator
->NodeIndexer
;
233 NodesRemaining
= Generator
->ProcTopologyStructCount
;
235 while (NodesRemaining
!= 0) {
238 "INFO: PPTT: Cycle detection for element with index %d\n",
239 Generator
->ProcTopologyStructCount
- NodesRemaining
242 CycleDetector
= Iterator
;
244 // Walk the topology tree
245 while (CycleDetector
->TopologyParent
!= NULL
) {
248 "INFO: PPTT: %p -> %p\n",
249 CycleDetector
->Token
,
250 CycleDetector
->TopologyParent
->Token
253 // Check if we have already visited this node
254 if (CycleDetector
->CycleDetectionStamp
== NodesRemaining
) {
255 Status
= EFI_INVALID_PARAMETER
;
258 "ERROR: PPTT: Cycle in processor and cache topology detected for " \
259 "a chain of references originating from a node with: Token = %p " \
267 // Stamp the visited node
268 CycleDetector
->CycleDetectionStamp
= NodesRemaining
;
269 CycleDetector
= CycleDetector
->TopologyParent
;
270 } // Continue topology tree walk
274 } // Next Node Indexer
280 Update the array of private resources for a given Processor Hierarchy Node.
282 @param [in] Generator Pointer to the PPTT Generator.
283 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
285 @param [in] PrivResArray Pointer to the array of private resources.
286 @param [in] PrivResCount Number of private resources.
287 @param [in] PrivResArrayToken Reference Token for the CM_ARM_OBJ_REF
288 array describing node's private resources.
290 @retval EFI_SUCCESS Array updated successfully.
291 @retval EFI_INVALID_PARAMETER A parameter is invalid.
292 @retval EFI_NOT_FOUND A private resource was not found.
296 AddPrivateResources (
297 IN CONST ACPI_PPTT_GENERATOR
*CONST Generator
,
298 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
299 IN UINT32
*PrivResArray
,
300 IN UINT32 PrivResCount
,
301 IN CONST CM_OBJECT_TOKEN PrivResArrayToken
305 CM_ARM_OBJ_REF
*CmObjRefs
;
306 UINT32 CmObjRefCount
;
307 PPTT_NODE_INDEXER
*PpttNodeFound
;
310 (Generator
!= NULL
) &&
311 (CfgMgrProtocol
!= NULL
) &&
312 (PrivResArray
!= NULL
) &&
316 // Validate input arguments
317 if (PrivResArrayToken
== CM_NULL_TOKEN
) {
318 Status
= EFI_INVALID_PARAMETER
;
321 "ERROR: PPTT: The number of private resources is %d while " \
322 "PrivResToken = CM_NULL_TOKEN. Status = %r\n",
330 // Get the CM Object References
331 Status
= GetEArmObjCmRef (
337 if (EFI_ERROR (Status
)) {
340 "ERROR: PPTT: Failed to get CM Object References. " \
341 "PrivResToken = %p. Status = %r\n",
348 if (CmObjRefCount
!= PrivResCount
) {
349 Status
= EFI_INVALID_PARAMETER
;
352 "ERROR: PPTT: The number of CM Object References retrieved and the " \
353 "number of private resources don't match. CmObjRefCount = %d. " \
354 "PrivResourceCount = %d. PrivResToken = %p. Status = %r\n",
363 while (PrivResCount
-- != 0) {
364 if (CmObjRefs
->ReferenceToken
== CM_NULL_TOKEN
) {
365 Status
= EFI_INVALID_PARAMETER
;
368 "ERROR: PPTT: CM_NULL_TOKEN provided as reference token for a " \
369 "private resource. Status = %r\n",
375 // The Node indexer has the Processor hierarchy nodes at the begining
376 // followed by the cache structs and Id structs. Therefore we can
377 // skip the Processor hierarchy nodes in the node indexer search.
378 Status
= GetPpttNodeReferencedByToken (
379 Generator
->CacheStructIndexedList
,
380 (Generator
->ProcTopologyStructCount
-
381 Generator
->ProcHierarchyNodeCount
),
382 CmObjRefs
->ReferenceToken
,
385 if (EFI_ERROR (Status
)) {
388 "ERROR: PPTT: Failed to get a private resource with Token = %p from " \
389 "Node Indexer. Status = %r\n",
390 CmObjRefs
->ReferenceToken
,
396 // Update the offset of the private resources in the Processor
397 // Hierarchy Node structure
398 *(PrivResArray
++) = PpttNodeFound
->Offset
;
406 Function to test if two indexed Processor Hierarchy Info objects map to the
407 same GIC CPU Interface Info object.
409 This is a callback function that can be invoked by FindDuplicateValue ().
411 @param [in] Object1 Pointer to the first indexed Processor Hierarchy
413 @param [in] Object2 Pointer to the second indexed Processor Hierarchy
415 @param [in] Index1 Index of Object1 to be displayed for debugging
417 @param [in] Index2 Index of Object2 to be displayed for debugging
420 @retval TRUE Object1 and Object2 have the same GicCToken.
421 @retval FALSE Object1 and Object2 have different GicCTokens.
426 IN CONST VOID
*Object1
,
427 IN CONST VOID
*Object2
,
432 PPTT_NODE_INDEXER
*IndexedObject1
;
433 PPTT_NODE_INDEXER
*IndexedObject2
;
434 CM_ARM_PROC_HIERARCHY_INFO
*ProcNode1
;
435 CM_ARM_PROC_HIERARCHY_INFO
*ProcNode2
;
442 IndexedObject1
= (PPTT_NODE_INDEXER
*)Object1
;
443 IndexedObject2
= (PPTT_NODE_INDEXER
*)Object2
;
444 ProcNode1
= (CM_ARM_PROC_HIERARCHY_INFO
*)IndexedObject1
->Object
;
445 ProcNode2
= (CM_ARM_PROC_HIERARCHY_INFO
*)IndexedObject2
->Object
;
447 if (IS_ACPI_PROC_ID_VALID (ProcNode1
) &&
448 IS_ACPI_PROC_ID_VALID (ProcNode2
) &&
449 (ProcNode1
->GicCToken
!= CM_NULL_TOKEN
) &&
450 (ProcNode2
->GicCToken
!= CM_NULL_TOKEN
) &&
451 (ProcNode1
->GicCToken
== ProcNode2
->GicCToken
))
455 "ERROR: PPTT: Two Processor Hierarchy Info objects (%d and %d) map to " \
456 "the same GICC Info object. ACPI Processor IDs are not unique. " \
459 IndexedObject1
->Token
,
470 Update the Processor Hierarchy Node (Type 0) information.
472 This function populates the Processor Hierarchy Nodes with information from
473 the Configuration Manager and adds this information to the PPTT table.
475 @param [in] Generator Pointer to the PPTT Generator.
476 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
478 @param [in] Pptt Pointer to PPTT table structure.
479 @param [in] NodesStartOffset Offset from the start of PPTT table to the
480 start of Processor Hierarchy Nodes.
482 @retval EFI_SUCCESS Node updated successfully.
483 @retval EFI_INVALID_PARAMETER A parameter is invalid.
484 @retval EFI_NOT_FOUND The required object was not found.
488 AddProcHierarchyNodes (
489 IN CONST ACPI_PPTT_GENERATOR
*CONST Generator
,
490 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
491 IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
*Pptt
,
492 IN CONST UINT32 NodesStartOffset
496 EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR
*ProcStruct
;
497 UINT32
*PrivateResources
;
498 BOOLEAN IsGicCTokenDuplicated
;
500 CM_ARM_GICC_INFO
*GicCInfoList
;
501 UINT32 GicCInfoCount
;
502 UINT32 UniqueGicCRefCount
;
504 PPTT_NODE_INDEXER
*PpttNodeFound
;
505 CM_ARM_PROC_HIERARCHY_INFO
*ProcInfoNode
;
507 PPTT_NODE_INDEXER
*ProcNodeIterator
;
512 (Generator
!= NULL
) &&
513 (CfgMgrProtocol
!= NULL
) &&
517 ProcStruct
= (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR
*)((UINT8
*)Pptt
+
520 ProcNodeIterator
= Generator
->ProcHierarchyNodeIndexedList
;
521 NodeCount
= Generator
->ProcHierarchyNodeCount
;
523 // Check if every GICC Object is referenced by onlu one Proc Node
524 IsGicCTokenDuplicated
= FindDuplicateValue (
527 sizeof (PPTT_NODE_INDEXER
),
530 // Duplicate GIC CPU Interface Token was found so two PPTT Processor Hierarchy
531 // Nodes map to the same MADT GICC structure
532 if (IsGicCTokenDuplicated
) {
533 return EFI_INVALID_PARAMETER
;
536 UniqueGicCRefCount
= 0;
538 while (NodeCount
-- != 0) {
539 ProcInfoNode
= (CM_ARM_PROC_HIERARCHY_INFO
*)ProcNodeIterator
->Object
;
541 // Check if the private resource count is within the size limit
542 // imposed on the Processor Hierarchy node by the specification.
543 // Note: The length field is 8 bit wide while the number of private
544 // resource field is 32 bit wide.
545 Length
= GetProcHierarchyNodeSize (ProcInfoNode
);
546 if (Length
> MAX_UINT8
) {
547 Status
= EFI_INVALID_PARAMETER
;
550 "ERROR: PPTT: Too many private resources. Count = %d. " \
551 "Maximum supported Processor Node size exceeded. " \
552 "Token = %p. Status = %r\n",
553 ProcInfoNode
->NoOfPrivateResources
,
554 ProcInfoNode
->ParentToken
,
560 // Populate the node header
561 ProcStruct
->Type
= EFI_ACPI_6_3_PPTT_TYPE_PROCESSOR
;
562 ProcStruct
->Length
= (UINT8
)Length
;
563 ProcStruct
->Reserved
[0] = EFI_ACPI_RESERVED_BYTE
;
564 ProcStruct
->Reserved
[1] = EFI_ACPI_RESERVED_BYTE
;
566 // Populate the flags
567 ProcStruct
->Flags
.PhysicalPackage
= ProcInfoNode
->Flags
& BIT0
;
568 ProcStruct
->Flags
.AcpiProcessorIdValid
= (ProcInfoNode
->Flags
& BIT1
) >> 1;
569 ProcStruct
->Flags
.ProcessorIsAThread
= (ProcInfoNode
->Flags
& BIT2
) >> 2;
570 ProcStruct
->Flags
.NodeIsALeaf
= (ProcInfoNode
->Flags
& BIT3
) >> 3;
571 ProcStruct
->Flags
.IdenticalImplementation
=
572 (ProcInfoNode
->Flags
& BIT4
) >> 4;
573 ProcStruct
->Flags
.Reserved
= 0;
575 // Populate the parent reference
576 if (ProcInfoNode
->ParentToken
== CM_NULL_TOKEN
) {
577 ProcStruct
->Parent
= 0;
579 Status
= GetPpttNodeReferencedByToken (
580 Generator
->ProcHierarchyNodeIndexedList
,
581 Generator
->ProcHierarchyNodeCount
,
582 ProcInfoNode
->ParentToken
,
585 if (EFI_ERROR (Status
)) {
588 "ERROR: PPTT: Failed to get parent processor hierarchy node " \
589 "reference. Token = %p, Status = %r\n",
590 ProcInfoNode
->ParentToken
,
597 // Test if the reference is to a 'leaf' node
598 if (IS_PROC_NODE_LEAF (
599 ((CM_ARM_PROC_HIERARCHY_INFO
*)PpttNodeFound
->Object
)
602 Status
= EFI_INVALID_PARAMETER
;
605 "ERROR: PPTT: Reference to a leaf Processor Hierarchy Node. " \
606 "ParentToken = %p. ChildToken = %p. Status = %r\n",
607 ProcInfoNode
->ParentToken
,
614 // Update Proc Structure with the offset of the parent node
615 ProcStruct
->Parent
= PpttNodeFound
->Offset
;
617 // Store the reference for the parent node in the Node Indexer
618 // so that this can be used later for cycle detection
619 ProcNodeIterator
->TopologyParent
= PpttNodeFound
;
622 // Populate ACPI Processor ID
623 if (!IS_ACPI_PROC_ID_VALID (ProcInfoNode
)) {
624 // Default invalid ACPI Processor ID to 0
625 ProcStruct
->AcpiProcessorId
= 0;
626 } else if (ProcInfoNode
->GicCToken
== CM_NULL_TOKEN
) {
627 Status
= EFI_INVALID_PARAMETER
;
630 "ERROR: PPTT: The 'ACPI Processor ID valid' flag is set but no GICC " \
631 "structure token was provided. GicCToken = %p. RequestorToken = %p. " \
633 ProcInfoNode
->GicCToken
,
639 Status
= GetEArmObjGicCInfo (
641 ProcInfoNode
->GicCToken
,
645 if (EFI_ERROR (Status
)) {
648 "ERROR: PPTT: Failed to get GICC structure. ACPI Processor ID " \
649 "can't be populated. GicCToken = %p. RequestorToken = %p. " \
651 ProcInfoNode
->GicCToken
,
658 if (GicCInfoCount
!= 1) {
659 Status
= EFI_INVALID_PARAMETER
;
662 "ERROR: PPTT: Failed to find a unique GICC structure. " \
663 "ACPI Processor ID can't be populated. " \
664 "GICC Structure Count = %d. GicCToken = %p. RequestorToken = %p " \
667 ProcInfoNode
->GicCToken
,
674 // Update the ACPI Processor Id
675 ProcStruct
->AcpiProcessorId
= GicCInfoList
->AcpiProcessorUid
;
677 // Increment the reference count for the number of
678 // Unique GICC objects that were retrieved.
679 UniqueGicCRefCount
++;
682 ProcStruct
->NumberOfPrivateResources
= ProcInfoNode
->NoOfPrivateResources
;
683 PrivateResources
= (UINT32
*)((UINT8
*)ProcStruct
+
684 sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR
));
686 if (ProcStruct
->NumberOfPrivateResources
!= 0) {
687 // Populate the private resources array
688 Status
= AddPrivateResources (
692 ProcStruct
->NumberOfPrivateResources
,
693 ProcInfoNode
->PrivateResourcesArrayToken
695 if (EFI_ERROR (Status
)) {
698 "ERROR: PPTT: Failed to populate the private resources array. " \
706 // Next Processor Hierarchy Node
707 ProcStruct
= (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR
*)((UINT8
*)ProcStruct
+
710 } // Processor Hierarchy Node
712 // Knowing the total number of GICC references made and that all GICC Token
713 // references are unique, we can test if no GICC instances have been left out.
714 Status
= GetEArmObjGicCInfo (
720 if (EFI_ERROR (Status
)) {
723 "ERROR: PPTT: Failed to get GICC Info. Status = %r\n",
729 // MADT - PPTT cross validation
730 // This checks that one and only one GICC structure is referenced by a
731 // Processor Hierarchy Node in the PPTT.
732 // Since we have already checked that the GICC objects referenced by the
733 // Proc Nodes are unique, the UniqueGicCRefCount cannot be greater than
734 // the total number of GICC objects in the platform.
735 if (GicCInfoCount
> UniqueGicCRefCount
) {
736 Status
= EFI_INVALID_PARAMETER
;
739 "ERROR: PPTT: %d GICC structure(s) exposed by MADT don't have " \
740 "a corresponding Processor Hierarchy Node. Status = %r\n",
741 GicCInfoCount
- UniqueGicCRefCount
,
750 Update the Cache Type Structure (Type 1) information.
752 This function populates the Cache Type Structures with information from
753 the Configuration Manager and adds this information to the PPTT table.
755 @param [in] Generator Pointer to the PPTT Generator.
756 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
758 @param [in] Pptt Pointer to PPTT table structure.
759 @param [in] NodesStartOffset Offset from the start of PPTT table to the
760 start of Cache Type Structures.
762 @retval EFI_SUCCESS Structures updated successfully.
763 @retval EFI_INVALID_PARAMETER A parameter is invalid.
764 @retval EFI_NOT_FOUND A required object was not found.
768 AddCacheTypeStructures (
769 IN CONST ACPI_PPTT_GENERATOR
*CONST Generator
,
770 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
771 IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
*Pptt
,
772 IN CONST UINT32 NodesStartOffset
776 EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE
*CacheStruct
;
777 PPTT_NODE_INDEXER
*PpttNodeFound
;
778 CM_ARM_CACHE_INFO
*CacheInfoNode
;
779 PPTT_NODE_INDEXER
*CacheNodeIterator
;
783 (Generator
!= NULL
) &&
784 (CfgMgrProtocol
!= NULL
) &&
788 CacheStruct
= (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE
*)((UINT8
*)Pptt
+
791 CacheNodeIterator
= Generator
->CacheStructIndexedList
;
792 NodeCount
= Generator
->CacheStructCount
;
794 while (NodeCount
-- != 0) {
795 CacheInfoNode
= (CM_ARM_CACHE_INFO
*)CacheNodeIterator
->Object
;
797 // Populate the node header
798 CacheStruct
->Type
= EFI_ACPI_6_3_PPTT_TYPE_CACHE
;
799 CacheStruct
->Length
= sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE
);
800 CacheStruct
->Reserved
[0] = EFI_ACPI_RESERVED_BYTE
;
801 CacheStruct
->Reserved
[1] = EFI_ACPI_RESERVED_BYTE
;
803 // "On Arm-based systems, all cache properties must be provided in the
804 // table." (ACPI 6.3, Section 5.2.29.2)
805 CacheStruct
->Flags
.SizePropertyValid
= 1;
806 CacheStruct
->Flags
.NumberOfSetsValid
= 1;
807 CacheStruct
->Flags
.AssociativityValid
= 1;
808 CacheStruct
->Flags
.AllocationTypeValid
= 1;
809 CacheStruct
->Flags
.CacheTypeValid
= 1;
810 CacheStruct
->Flags
.WritePolicyValid
= 1;
811 CacheStruct
->Flags
.LineSizeValid
= 1;
812 CacheStruct
->Flags
.Reserved
= 0;
814 // Populate the reference to the next level of cache
815 if (CacheInfoNode
->NextLevelOfCacheToken
== CM_NULL_TOKEN
) {
816 CacheStruct
->NextLevelOfCache
= 0;
818 Status
= GetPpttNodeReferencedByToken (
819 Generator
->CacheStructIndexedList
,
820 Generator
->CacheStructCount
,
821 CacheInfoNode
->NextLevelOfCacheToken
,
824 if (EFI_ERROR (Status
)) {
827 "ERROR: PPTT: Failed to get the reference to the Next Level of " \
828 "Cache. NextLevelOfCacheToken = %p. RequestorToken = %p. " \
830 CacheInfoNode
->NextLevelOfCacheToken
,
831 CacheInfoNode
->Token
,
837 // Update Cache Structure with the offset for the next level of cache
838 CacheStruct
->NextLevelOfCache
= PpttNodeFound
->Offset
;
840 // Store the next level of cache information in the Node Indexer
841 // so that this can be used later for cycle detection
842 CacheNodeIterator
->TopologyParent
= PpttNodeFound
;
845 CacheStruct
->Size
= CacheInfoNode
->Size
;
847 // Validate and populate the 'Number of sets' field
848 if (CacheInfoNode
->NumberOfSets
> PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX
) {
849 Status
= EFI_INVALID_PARAMETER
;
852 "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum number " \
853 "of sets can be %d. NumberOfSets = %d. Status = %r\n",
854 PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX
,
855 CacheInfoNode
->NumberOfSets
,
861 if (CacheInfoNode
->NumberOfSets
> PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX
) {
864 "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \
865 "number of sets can be %d. NumberOfSets = %d\n",
866 PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX
,
867 CacheInfoNode
->NumberOfSets
871 CacheStruct
->NumberOfSets
= CacheInfoNode
->NumberOfSets
;
873 // Validate Associativity field based on maximum associativity
874 // supported by ACPI Cache type structure.
875 if (CacheInfoNode
->Associativity
> MAX_UINT8
) {
876 Status
= EFI_INVALID_PARAMETER
;
879 "ERROR: PPTT: The maximum associativity supported by ACPI " \
880 "Cache type structure is %d. Associativity = %d, Status = %r\n",
882 CacheInfoNode
->Associativity
,
888 // Validate the Associativity field based on the architecture specification
889 // The architecture supports much larger associativity values than the
890 // current ACPI specification.
891 // These checks will be needed in the future when the ACPI specification
892 // is extended. Disabling this code for now.
894 if (CacheInfoNode
->Associativity
> PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX
) {
895 Status
= EFI_INVALID_PARAMETER
;
898 "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum cache " \
899 "associativity can be %d. Associativity = %d. Status = %r\n",
900 PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX
,
901 CacheInfoNode
->Associativity
,
907 if (CacheInfoNode
->Associativity
> PPTT_ARM_CACHE_ASSOCIATIVITY_MAX
) {
910 "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \
911 "cache associativity can be %d. Associativity = %d\n",
912 PPTT_ARM_CACHE_ASSOCIATIVITY_MAX
,
913 CacheInfoNode
->Associativity
919 // Note a typecast is needed as the maximum associativity
920 // supported by ACPI Cache type structure is MAX_UINT8.
921 CacheStruct
->Associativity
= (UINT8
)CacheInfoNode
->Associativity
;
923 // Populate cache attributes
924 CacheStruct
->Attributes
.AllocationType
=
925 CacheInfoNode
->Attributes
& (BIT0
| BIT1
);
926 CacheStruct
->Attributes
.CacheType
=
927 (CacheInfoNode
->Attributes
& (BIT2
| BIT3
)) >> 2;
928 CacheStruct
->Attributes
.WritePolicy
=
929 (CacheInfoNode
->Attributes
& BIT4
) >> 4;
930 CacheStruct
->Attributes
.Reserved
= 0;
932 // Validate and populate cache line size
933 if ((CacheInfoNode
->LineSize
< PPTT_ARM_CACHE_LINE_SIZE_MIN
) ||
934 (CacheInfoNode
->LineSize
> PPTT_ARM_CACHE_LINE_SIZE_MAX
))
936 Status
= EFI_INVALID_PARAMETER
;
939 "ERROR: PPTT: The cache line size must be between %d and %d bytes " \
940 "on ARM Platforms. LineSize = %d. Status = %r\n",
941 PPTT_ARM_CACHE_LINE_SIZE_MIN
,
942 PPTT_ARM_CACHE_LINE_SIZE_MAX
,
943 CacheInfoNode
->LineSize
,
949 if ((CacheInfoNode
->LineSize
& (CacheInfoNode
->LineSize
- 1)) != 0) {
950 Status
= EFI_INVALID_PARAMETER
;
953 "ERROR: PPTT: The cache line size is not a power of 2. " \
954 "LineSize = %d. Status = %r\n",
955 CacheInfoNode
->LineSize
,
961 CacheStruct
->LineSize
= CacheInfoNode
->LineSize
;
963 // Next Cache Type Structure
964 CacheStruct
= (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE
*)((UINT8
*)CacheStruct
+
965 CacheStruct
->Length
);
967 } // Cache Type Structure
973 Update the ID Type Structure (Type 2) information.
975 This function populates the ID Type Structures with information from
976 the Configuration Manager and and adds this information to the PPTT table.
978 @param [in] Generator Pointer to the PPTT Generator.
979 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
981 @param [in] Pptt Pointer to PPTT table structure.
982 @param [in] NodesStartOffset Offset from the start of PPTT table to the
983 start of ID Type Structures.
985 @retval EFI_SUCCESS Structures updated successfully.
986 @retval EFI_INVALID_PARAMETER A parameter is invalid.
987 @retval EFI_NOT_FOUND A required object was not found.
991 AddIdTypeStructures (
992 IN CONST ACPI_PPTT_GENERATOR
*CONST Generator
,
993 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
994 IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
*Pptt
,
995 IN CONST UINT32 NodesStartOffset
998 EFI_ACPI_6_3_PPTT_STRUCTURE_ID
*IdStruct
;
999 CM_ARM_PROC_NODE_ID_INFO
*ProcIdInfoNode
;
1000 PPTT_NODE_INDEXER
*IdStructIterator
;
1004 (Generator
!= NULL
) &&
1005 (CfgMgrProtocol
!= NULL
) &&
1009 IdStruct
= (EFI_ACPI_6_3_PPTT_STRUCTURE_ID
*)((UINT8
*)Pptt
+ NodesStartOffset
);
1011 IdStructIterator
= Generator
->IdStructIndexedList
;
1012 NodeCount
= Generator
->IdStructCount
;
1013 while (NodeCount
-- != 0) {
1014 ProcIdInfoNode
= (CM_ARM_PROC_NODE_ID_INFO
*)IdStructIterator
->Object
;
1016 // Populate the node
1017 IdStruct
->Type
= EFI_ACPI_6_3_PPTT_TYPE_ID
;
1018 IdStruct
->Length
= sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_ID
);
1019 IdStruct
->Reserved
[0] = EFI_ACPI_RESERVED_BYTE
;
1020 IdStruct
->Reserved
[1] = EFI_ACPI_RESERVED_BYTE
;
1021 IdStruct
->VendorId
= ProcIdInfoNode
->VendorId
;
1022 IdStruct
->Level1Id
= ProcIdInfoNode
->Level1Id
;
1023 IdStruct
->Level2Id
= ProcIdInfoNode
->Level2Id
;
1024 IdStruct
->MajorRev
= ProcIdInfoNode
->MajorRev
;
1025 IdStruct
->MinorRev
= ProcIdInfoNode
->MinorRev
;
1026 IdStruct
->SpinRev
= ProcIdInfoNode
->SpinRev
;
1028 // Next ID Type Structure
1029 IdStruct
= (EFI_ACPI_6_3_PPTT_STRUCTURE_ID
*)((UINT8
*)IdStruct
+
1032 } // ID Type Structure
1038 Construct the PPTT ACPI table.
1040 This function invokes the Configuration Manager protocol interface
1041 to get the required hardware information for generating the ACPI
1044 If this function allocates any resources then they must be freed
1045 in the FreeXXXXTableResources function.
1047 @param [in] This Pointer to the table generator.
1048 @param [in] AcpiTableInfo Pointer to the ACPI table generator to be used.
1049 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1051 @param [out] Table Pointer to the constructed ACPI Table.
1053 @retval EFI_SUCCESS Table generated successfully.
1054 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1055 @retval EFI_NOT_FOUND The required object was not found.
1056 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
1057 Manager is less than the Object size for
1058 the requested object.
1064 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
1065 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
1066 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1067 OUT EFI_ACPI_DESCRIPTION_HEADER
**CONST Table
1072 UINT32 ProcTopologyStructCount
;
1073 UINT32 ProcHierarchyNodeCount
;
1074 UINT32 CacheStructCount
;
1075 UINT32 IdStructCount
;
1077 UINT32 ProcHierarchyNodeOffset
;
1078 UINT32 CacheStructOffset
;
1079 UINT32 IdStructOffset
;
1081 CM_ARM_PROC_HIERARCHY_INFO
*ProcHierarchyNodeList
;
1082 CM_ARM_CACHE_INFO
*CacheStructList
;
1083 CM_ARM_PROC_NODE_ID_INFO
*IdStructList
;
1085 ACPI_PPTT_GENERATOR
*Generator
;
1087 // Pointer to the Node Indexer array
1088 PPTT_NODE_INDEXER
*NodeIndexer
;
1090 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
*Pptt
;
1094 (AcpiTableInfo
!= NULL
) &&
1095 (CfgMgrProtocol
!= NULL
) &&
1097 (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
) &&
1098 (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
)
1101 if ((AcpiTableInfo
->AcpiTableRevision
< This
->MinAcpiTableRevision
) ||
1102 (AcpiTableInfo
->AcpiTableRevision
> This
->AcpiTableRevision
))
1106 "ERROR: PPTT: Requested table revision = %d is not supported. "
1107 "Supported table revisions: Minimum = %d. Maximum = %d\n",
1108 AcpiTableInfo
->AcpiTableRevision
,
1109 This
->MinAcpiTableRevision
,
1110 This
->AcpiTableRevision
1112 return EFI_INVALID_PARAMETER
;
1115 Generator
= (ACPI_PPTT_GENERATOR
*)This
;
1118 // Get the processor hierarchy info and update the processor topology
1119 // structure count with Processor Hierarchy Nodes (Type 0)
1120 Status
= GetEArmObjProcHierarchyInfo (
1123 &ProcHierarchyNodeList
,
1124 &ProcHierarchyNodeCount
1126 if (EFI_ERROR (Status
)) {
1129 "ERROR: PPTT: Failed to get processor hierarchy info. Status = %r\n",
1135 ProcTopologyStructCount
= ProcHierarchyNodeCount
;
1136 Generator
->ProcHierarchyNodeCount
= ProcHierarchyNodeCount
;
1138 // Get the cache info and update the processor topology structure count with
1139 // Cache Type Structures (Type 1)
1140 Status
= GetEArmObjCacheInfo (
1146 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1149 "ERROR: PPTT: Failed to get cache info. Status = %r\n",
1155 ProcTopologyStructCount
+= CacheStructCount
;
1156 Generator
->CacheStructCount
= CacheStructCount
;
1158 // Get the processor hierarchy node ID info and update the processor topology
1159 // structure count with ID Structures (Type 2)
1160 Status
= GetEArmObjProcNodeIdInfo (
1166 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1169 "ERROR: PPTT: Failed to get processor hierarchy node ID info. " \
1176 ProcTopologyStructCount
+= IdStructCount
;
1177 Generator
->IdStructCount
= IdStructCount
;
1179 // Allocate Node Indexer array
1180 NodeIndexer
= (PPTT_NODE_INDEXER
*)AllocateZeroPool (
1181 sizeof (PPTT_NODE_INDEXER
) *
1182 ProcTopologyStructCount
1184 if (NodeIndexer
== NULL
) {
1185 Status
= EFI_OUT_OF_RESOURCES
;
1188 "ERROR: PPTT: Failed to allocate memory for Node Indexer. Status = %r\n ",
1194 DEBUG ((DEBUG_INFO
, "INFO: NodeIndexer = %p\n", NodeIndexer
));
1195 Generator
->ProcTopologyStructCount
= ProcTopologyStructCount
;
1196 Generator
->NodeIndexer
= NodeIndexer
;
1198 // Calculate the size of the PPTT table
1199 TableSize
= sizeof (EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
);
1201 // Include the size of Processor Hierarchy Nodes and index them
1202 if (Generator
->ProcHierarchyNodeCount
!= 0) {
1203 ProcHierarchyNodeOffset
= TableSize
;
1204 Generator
->ProcHierarchyNodeIndexedList
= NodeIndexer
;
1205 TableSize
+= GetSizeofProcHierarchyNodes (
1206 ProcHierarchyNodeOffset
,
1207 ProcHierarchyNodeList
,
1208 Generator
->ProcHierarchyNodeCount
,
1214 " ProcHierarchyNodeCount = %d\n" \
1215 " ProcHierarchyNodeOffset = 0x%x\n" \
1216 " ProcHierarchyNodeIndexedList = 0x%p\n",
1217 Generator
->ProcHierarchyNodeCount
,
1218 ProcHierarchyNodeOffset
,
1219 Generator
->ProcHierarchyNodeIndexedList
1223 // Include the size of Cache Type Structures and index them
1224 if (Generator
->CacheStructCount
!= 0) {
1225 CacheStructOffset
= TableSize
;
1226 Generator
->CacheStructIndexedList
= NodeIndexer
;
1227 TableSize
+= GetSizeofCacheTypeStructs (
1230 Generator
->CacheStructCount
,
1235 " CacheStructCount = %d\n" \
1236 " CacheStructOffset = 0x%x\n" \
1237 " CacheStructIndexedList = 0x%p\n",
1238 Generator
->CacheStructCount
,
1240 Generator
->CacheStructIndexedList
1244 // Include the size of ID Type Structures and index them
1245 if (Generator
->IdStructCount
!= 0) {
1246 IdStructOffset
= TableSize
;
1247 Generator
->IdStructIndexedList
= NodeIndexer
;
1248 TableSize
+= GetSizeofIdStructs (
1251 Generator
->IdStructCount
,
1256 " IdStructCount = %d\n" \
1257 " IdStructOffset = 0x%x\n" \
1258 " IdStructIndexedList = 0x%p\n",
1259 Generator
->IdStructCount
,
1261 Generator
->IdStructIndexedList
1268 " ProcTopologyStructCount = %d\n" \
1269 " TableSize = %d\n",
1270 ProcTopologyStructCount
,
1274 // Allocate the Buffer for the PPTT table
1275 *Table
= (EFI_ACPI_DESCRIPTION_HEADER
*)AllocateZeroPool (TableSize
);
1276 if (*Table
== NULL
) {
1277 Status
= EFI_OUT_OF_RESOURCES
;
1280 "ERROR: PPTT: Failed to allocate memory for PPTT Table. " \
1281 "Size = %d. Status = %r\n",
1288 Pptt
= (EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
*)*Table
;
1292 "PPTT: Pptt = 0x%p. TableSize = 0x%x\n",
1298 Status
= AddAcpiHeader (
1305 if (EFI_ERROR (Status
)) {
1308 "ERROR: PPTT: Failed to add ACPI header. Status = %r\n",
1314 // Add Processor Hierarchy Nodes (Type 0) to the generated table
1315 if (Generator
->ProcHierarchyNodeCount
!= 0) {
1316 Status
= AddProcHierarchyNodes (
1320 ProcHierarchyNodeOffset
1322 if (EFI_ERROR (Status
)) {
1325 "ERROR: PPTT: Failed to add Processor Hierarchy Nodes. Status = %r\n",
1332 // Add Cache Type Structures (Type 1) to the generated table
1333 if (Generator
->CacheStructCount
!= 0) {
1334 Status
= AddCacheTypeStructures (
1340 if (EFI_ERROR (Status
)) {
1343 "ERROR: PPTT: Failed to add Cache Type Structures. Status = %r\n",
1350 // Add ID Type Structures (Type 2) to the generated table
1351 if (Generator
->IdStructCount
!= 0) {
1352 Status
= AddIdTypeStructures (
1358 if (EFI_ERROR (Status
)) {
1361 "ERROR: PPTT: Failed to add ID Type Structures. Status = %r\n",
1368 // Validate CM object cross-references in PPTT
1369 Status
= DetectCyclesInTopology (Generator
);
1370 if (EFI_ERROR (Status
)) {
1373 "ERROR: PPTT: Invalid processor and cache topology. Status = %r\n",
1382 if (Generator
->NodeIndexer
!= NULL
) {
1383 FreePool (Generator
->NodeIndexer
);
1384 Generator
->NodeIndexer
= NULL
;
1387 if (*Table
!= NULL
) {
1396 Free any resources allocated for constructing the PPTT
1398 @param [in] This Pointer to the table generator.
1399 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1400 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1402 @param [in, out] Table Pointer to the ACPI Table.
1404 @retval EFI_SUCCESS The resources were freed successfully.
1405 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
1409 FreePpttTableResources (
1410 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
1411 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
1412 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1413 IN OUT EFI_ACPI_DESCRIPTION_HEADER
**CONST Table
1416 ACPI_PPTT_GENERATOR
*Generator
;
1420 (AcpiTableInfo
!= NULL
) &&
1421 (CfgMgrProtocol
!= NULL
) &&
1422 (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
) &&
1423 (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
)
1426 Generator
= (ACPI_PPTT_GENERATOR
*)This
;
1428 // Free any memory allocated by the generator
1429 if (Generator
->NodeIndexer
!= NULL
) {
1430 FreePool (Generator
->NodeIndexer
);
1431 Generator
->NodeIndexer
= NULL
;
1434 if ((Table
== NULL
) || (*Table
== NULL
)) {
1435 DEBUG ((DEBUG_ERROR
, "ERROR: PPTT: Invalid Table Pointer\n"));
1440 return EFI_INVALID_PARAMETER
;
1448 /** The PPTT Table Generator revision.
1450 #define PPTT_GENERATOR_REVISION CREATE_REVISION (1, 0)
1452 /** The interface for the PPTT Table Generator.
1455 ACPI_PPTT_GENERATOR PpttGenerator
= {
1456 // ACPI table generator header
1459 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdPptt
),
1460 // Generator Description
1461 L
"ACPI.STD.PPTT.GENERATOR",
1462 // ACPI Table Signature
1463 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE
,
1464 // ACPI Table Revision supported by this Generator
1465 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION
,
1466 // Minimum supported ACPI Table Revision
1467 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION
,
1469 TABLE_GENERATOR_CREATOR_ID_ARM
,
1471 PPTT_GENERATOR_REVISION
,
1472 // Build Table function
1474 // Free Resource function
1475 FreePpttTableResources
,
1476 // Extended build function not needed
1478 // Extended build function not implemented by the generator.
1479 // Hence extended free resource function is not required.
1483 // PPTT Generator private data
1485 // Processor topology node count
1487 // Count of Processor Hierarchy Nodes
1489 // Count of Cache Structures
1491 // Count of Id Structures
1493 // Pointer to PPTT Node Indexer
1498 Register the Generator with the ACPI Table Factory.
1500 @param [in] ImageHandle The handle to the image.
1501 @param [in] SystemTable Pointer to the System Table.
1503 @retval EFI_SUCCESS The Generator is registered.
1504 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1505 @retval EFI_ALREADY_STARTED The Generator for the Table ID
1506 is already registered.
1510 AcpiPpttLibConstructor (
1511 IN EFI_HANDLE ImageHandle
,
1512 IN EFI_SYSTEM_TABLE
*SystemTable
1517 Status
= RegisterAcpiTableGenerator (&PpttGenerator
.Header
);
1518 DEBUG ((DEBUG_INFO
, "PPTT: Register Generator. Status = %r\n", Status
));
1519 ASSERT_EFI_ERROR (Status
);
1524 Deregister the Generator from the ACPI Table Factory.
1526 @param [in] ImageHandle The handle to the image.
1527 @param [in] SystemTable Pointer to the System Table.
1529 @retval EFI_SUCCESS The Generator is deregistered.
1530 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1531 @retval EFI_NOT_FOUND The Generator is not registered.
1535 AcpiPpttLibDestructor (
1536 IN EFI_HANDLE ImageHandle
,
1537 IN EFI_SYSTEM_TABLE
*SystemTable
1542 Status
= DeregisterAcpiTableGenerator (&PpttGenerator
.Header
);
1543 DEBUG ((DEBUG_INFO
, "PPTT: Deregister Generator. Status = %r\n", Status
));
1544 ASSERT_EFI_ERROR (Status
);