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",
198 Status
= EFI_NOT_FOUND
;
201 "PPTT: Node Indexer: SearchToken = %p. Status = %r\n",
210 Detect cycles in the processor and cache topology graph represented in
213 @param [in] Generator Pointer to the PPTT Generator.
215 @retval EFI_SUCCESS There are no cyclic references in the graph.
216 @retval EFI_INVALID_PARAMETER Processor or cache references form a cycle.
220 DetectCyclesInTopology (
221 IN CONST ACPI_PPTT_GENERATOR
* CONST Generator
225 PPTT_NODE_INDEXER
* Iterator
;
226 PPTT_NODE_INDEXER
* CycleDetector
;
227 UINT32 NodesRemaining
;
229 ASSERT (Generator
!= NULL
);
231 Iterator
= Generator
->NodeIndexer
;
232 NodesRemaining
= Generator
->ProcTopologyStructCount
;
234 while (NodesRemaining
!= 0) {
237 "INFO: PPTT: Cycle detection for element with index %d\n",
238 Generator
->ProcTopologyStructCount
- NodesRemaining
241 CycleDetector
= Iterator
;
243 // Walk the topology tree
244 while (CycleDetector
->TopologyParent
!= NULL
) {
247 "INFO: PPTT: %p -> %p\n",
248 CycleDetector
->Token
,
249 CycleDetector
->TopologyParent
->Token
252 // Check if we have already visited this node
253 if (CycleDetector
->CycleDetectionStamp
== NodesRemaining
) {
254 Status
= EFI_INVALID_PARAMETER
;
257 "ERROR: PPTT: Cycle in processor and cache topology detected for " \
258 "a chain of references originating from a node with: Token = %p " \
266 // Stamp the visited node
267 CycleDetector
->CycleDetectionStamp
= NodesRemaining
;
268 CycleDetector
= CycleDetector
->TopologyParent
;
269 } // Continue topology tree walk
273 } // Next Node Indexer
279 Update the array of private resources for a given Processor Hierarchy Node.
281 @param [in] Generator Pointer to the PPTT Generator.
282 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
284 @param [in] PrivResArray Pointer to the array of private resources.
285 @param [in] PrivResCount Number of private resources.
286 @param [in] PrivResArrayToken Reference Token for the CM_ARM_OBJ_REF
287 array describing node's private resources.
289 @retval EFI_SUCCESS Array updated successfully.
290 @retval EFI_INVALID_PARAMETER A parameter is invalid.
291 @retval EFI_NOT_FOUND A private resource was not found.
295 AddPrivateResources (
296 IN CONST ACPI_PPTT_GENERATOR
* CONST Generator
,
297 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
298 IN UINT32
* PrivResArray
,
299 IN UINT32 PrivResCount
,
300 IN CONST CM_OBJECT_TOKEN PrivResArrayToken
304 CM_ARM_OBJ_REF
* CmObjRefs
;
305 UINT32 CmObjRefCount
;
306 PPTT_NODE_INDEXER
* PpttNodeFound
;
309 (Generator
!= NULL
) &&
310 (CfgMgrProtocol
!= NULL
) &&
311 (PrivResArray
!= NULL
) &&
315 // Validate input arguments
316 if (PrivResArrayToken
== CM_NULL_TOKEN
) {
317 Status
= EFI_INVALID_PARAMETER
;
320 "ERROR: PPTT: The number of private resources is %d while " \
321 "PrivResToken = CM_NULL_TOKEN. Status = %r\n",
329 // Get the CM Object References
330 Status
= GetEArmObjCmRef (
336 if (EFI_ERROR (Status
)) {
339 "ERROR: PPTT: Failed to get CM Object References. " \
340 "PrivResToken = %p. Status = %r\n",
347 if (CmObjRefCount
!= PrivResCount
) {
348 Status
= EFI_INVALID_PARAMETER
;
351 "ERROR: PPTT: The number of CM Object References retrieved and the " \
352 "number of private resources don't match. CmObjRefCount = %d. " \
353 "PrivResourceCount = %d. PrivResToken = %p. Status = %r\n",
362 while (PrivResCount
-- != 0) {
363 if (CmObjRefs
->ReferenceToken
== CM_NULL_TOKEN
) {
364 Status
= EFI_INVALID_PARAMETER
;
367 "ERROR: PPTT: CM_NULL_TOKEN provided as reference token for a " \
368 "private resource. Status = %r\n",
374 // The Node indexer has the Processor hierarchy nodes at the begining
375 // followed by the cache structs and Id structs. Therefore we can
376 // skip the Processor hierarchy nodes in the node indexer search.
377 Status
= GetPpttNodeReferencedByToken (
378 Generator
->CacheStructIndexedList
,
379 (Generator
->ProcTopologyStructCount
-
380 Generator
->ProcHierarchyNodeCount
),
381 CmObjRefs
->ReferenceToken
,
384 if (EFI_ERROR (Status
)) {
387 "ERROR: PPTT: Failed to get a private resource with Token = %p from " \
388 "Node Indexer. Status = %r\n",
389 CmObjRefs
->ReferenceToken
,
395 // Update the offset of the private resources in the Processor
396 // Hierarchy Node structure
397 *(PrivResArray
++) = PpttNodeFound
->Offset
;
405 Function to test if two indexed Processor Hierarchy Info objects map to the
406 same GIC CPU Interface Info object.
408 This is a callback function that can be invoked by FindDuplicateValue ().
410 @param [in] Object1 Pointer to the first indexed Processor Hierarchy
412 @param [in] Object2 Pointer to the second indexed Processor Hierarchy
414 @param [in] Index1 Index of Object1 to be displayed for debugging
416 @param [in] Index2 Index of Object2 to be displayed for debugging
419 @retval TRUE Object1 and Object2 have the same GicCToken.
420 @retval FALSE Object1 and Object2 have different GicCTokens.
425 IN CONST VOID
* Object1
,
426 IN CONST VOID
* Object2
,
431 PPTT_NODE_INDEXER
* IndexedObject1
;
432 PPTT_NODE_INDEXER
* IndexedObject2
;
433 CM_ARM_PROC_HIERARCHY_INFO
* ProcNode1
;
434 CM_ARM_PROC_HIERARCHY_INFO
* ProcNode2
;
441 IndexedObject1
= (PPTT_NODE_INDEXER
*)Object1
;
442 IndexedObject2
= (PPTT_NODE_INDEXER
*)Object2
;
443 ProcNode1
= (CM_ARM_PROC_HIERARCHY_INFO
*)IndexedObject1
->Object
;
444 ProcNode2
= (CM_ARM_PROC_HIERARCHY_INFO
*)IndexedObject2
->Object
;
446 if (IS_ACPI_PROC_ID_VALID (ProcNode1
) &&
447 IS_ACPI_PROC_ID_VALID (ProcNode2
) &&
448 (ProcNode1
->GicCToken
!= CM_NULL_TOKEN
) &&
449 (ProcNode2
->GicCToken
!= CM_NULL_TOKEN
) &&
450 (ProcNode1
->GicCToken
== ProcNode2
->GicCToken
)) {
453 "ERROR: PPTT: Two Processor Hierarchy Info objects (%d and %d) map to " \
454 "the same GICC Info object. ACPI Processor IDs are not unique. " \
457 IndexedObject1
->Token
,
468 Update the Processor Hierarchy Node (Type 0) information.
470 This function populates the Processor Hierarchy Nodes with information from
471 the Configuration Manager and adds this information to the PPTT table.
473 @param [in] Generator Pointer to the PPTT Generator.
474 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
476 @param [in] Pptt Pointer to PPTT table structure.
477 @param [in] NodesStartOffset Offset from the start of PPTT table to the
478 start of Processor Hierarchy Nodes.
480 @retval EFI_SUCCESS Node updated successfully.
481 @retval EFI_INVALID_PARAMETER A parameter is invalid.
482 @retval EFI_NOT_FOUND The required object was not found.
486 AddProcHierarchyNodes (
487 IN CONST ACPI_PPTT_GENERATOR
* CONST Generator
,
488 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
489 IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
* Pptt
,
490 IN CONST UINT32 NodesStartOffset
494 EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR
* ProcStruct
;
495 UINT32
* PrivateResources
;
496 BOOLEAN IsGicCTokenDuplicated
;
498 CM_ARM_GICC_INFO
* GicCInfoList
;
499 UINT32 GicCInfoCount
;
500 UINT32 UniqueGicCRefCount
;
502 PPTT_NODE_INDEXER
* PpttNodeFound
;
503 CM_ARM_PROC_HIERARCHY_INFO
* ProcInfoNode
;
505 PPTT_NODE_INDEXER
* ProcNodeIterator
;
510 (Generator
!= NULL
) &&
511 (CfgMgrProtocol
!= NULL
) &&
515 ProcStruct
= (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR
*)((UINT8
*)Pptt
+
518 ProcNodeIterator
= Generator
->ProcHierarchyNodeIndexedList
;
519 NodeCount
= Generator
->ProcHierarchyNodeCount
;
521 // Check if every GICC Object is referenced by onlu one Proc Node
522 IsGicCTokenDuplicated
= FindDuplicateValue (
525 sizeof (PPTT_NODE_INDEXER
),
528 // Duplicate GIC CPU Interface Token was found so two PPTT Processor Hierarchy
529 // Nodes map to the same MADT GICC structure
530 if (IsGicCTokenDuplicated
) {
531 return EFI_INVALID_PARAMETER
;
534 UniqueGicCRefCount
= 0;
536 while (NodeCount
-- != 0) {
537 ProcInfoNode
= (CM_ARM_PROC_HIERARCHY_INFO
*)ProcNodeIterator
->Object
;
539 // Check if the private resource count is within the size limit
540 // imposed on the Processor Hierarchy node by the specification.
541 // Note: The length field is 8 bit wide while the number of private
542 // resource field is 32 bit wide.
543 Length
= GetProcHierarchyNodeSize (ProcInfoNode
);
544 if (Length
> MAX_UINT8
) {
545 Status
= EFI_INVALID_PARAMETER
;
548 "ERROR: PPTT: Too many private resources. Count = %d. " \
549 "Maximum supported Processor Node size exceeded. " \
550 "Token = %p. Status = %r\n",
551 ProcInfoNode
->NoOfPrivateResources
,
552 ProcInfoNode
->ParentToken
,
558 // Populate the node header
559 ProcStruct
->Type
= EFI_ACPI_6_3_PPTT_TYPE_PROCESSOR
;
560 ProcStruct
->Length
= (UINT8
)Length
;
561 ProcStruct
->Reserved
[0] = EFI_ACPI_RESERVED_BYTE
;
562 ProcStruct
->Reserved
[1] = EFI_ACPI_RESERVED_BYTE
;
564 // Populate the flags
565 ProcStruct
->Flags
.PhysicalPackage
= ProcInfoNode
->Flags
& BIT0
;
566 ProcStruct
->Flags
.AcpiProcessorIdValid
= (ProcInfoNode
->Flags
& BIT1
) >> 1;
567 ProcStruct
->Flags
.ProcessorIsAThread
= (ProcInfoNode
->Flags
& BIT2
) >> 2;
568 ProcStruct
->Flags
.NodeIsALeaf
= (ProcInfoNode
->Flags
& BIT3
) >> 3;
569 ProcStruct
->Flags
.IdenticalImplementation
=
570 (ProcInfoNode
->Flags
& BIT4
) >> 4;
571 ProcStruct
->Flags
.Reserved
= 0;
573 // Populate the parent reference
574 if (ProcInfoNode
->ParentToken
== CM_NULL_TOKEN
) {
575 ProcStruct
->Parent
= 0;
577 Status
= GetPpttNodeReferencedByToken (
578 Generator
->ProcHierarchyNodeIndexedList
,
579 Generator
->ProcHierarchyNodeCount
,
580 ProcInfoNode
->ParentToken
,
583 if (EFI_ERROR (Status
)) {
586 "ERROR: PPTT: Failed to get parent processor hierarchy node " \
587 "reference. Token = %p, Status = %r\n",
588 ProcInfoNode
->ParentToken
,
595 // Test if the reference is to a 'leaf' node
596 if (IS_PROC_NODE_LEAF (
597 ((CM_ARM_PROC_HIERARCHY_INFO
*)PpttNodeFound
->Object
))) {
598 Status
= EFI_INVALID_PARAMETER
;
601 "ERROR: PPTT: Reference to a leaf Processor Hierarchy Node. " \
602 "ParentToken = %p. ChildToken = %p. Status = %r\n",
603 ProcInfoNode
->ParentToken
,
610 // Update Proc Structure with the offset of the parent node
611 ProcStruct
->Parent
= PpttNodeFound
->Offset
;
613 // Store the reference for the parent node in the Node Indexer
614 // so that this can be used later for cycle detection
615 ProcNodeIterator
->TopologyParent
= PpttNodeFound
;
618 // Populate ACPI Processor ID
619 if (!IS_ACPI_PROC_ID_VALID (ProcInfoNode
)) {
620 // Default invalid ACPI Processor ID to 0
621 ProcStruct
->AcpiProcessorId
= 0;
622 } else if (ProcInfoNode
->GicCToken
== CM_NULL_TOKEN
) {
623 Status
= EFI_INVALID_PARAMETER
;
626 "ERROR: PPTT: The 'ACPI Processor ID valid' flag is set but no GICC " \
627 "structure token was provided. GicCToken = %p. RequestorToken = %p. " \
629 ProcInfoNode
->GicCToken
,
635 Status
= GetEArmObjGicCInfo (
637 ProcInfoNode
->GicCToken
,
641 if (EFI_ERROR (Status
)) {
644 "ERROR: PPTT: Failed to get GICC structure. ACPI Processor ID " \
645 "can't be populated. GicCToken = %p. RequestorToken = %p. " \
647 ProcInfoNode
->GicCToken
,
654 if (GicCInfoCount
!= 1) {
655 Status
= EFI_INVALID_PARAMETER
;
658 "ERROR: PPTT: Failed to find a unique GICC structure. " \
659 "ACPI Processor ID can't be populated. " \
660 "GICC Structure Count = %d. GicCToken = %p. RequestorToken = %p " \
663 ProcInfoNode
->GicCToken
,
670 // Update the ACPI Processor Id
671 ProcStruct
->AcpiProcessorId
= GicCInfoList
->AcpiProcessorUid
;
673 // Increment the reference count for the number of
674 // Unique GICC objects that were retrieved.
675 UniqueGicCRefCount
++;
678 ProcStruct
->NumberOfPrivateResources
= ProcInfoNode
->NoOfPrivateResources
;
679 PrivateResources
= (UINT32
*)((UINT8
*)ProcStruct
+
680 sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR
));
682 if (ProcStruct
->NumberOfPrivateResources
!= 0) {
683 // Populate the private resources array
684 Status
= AddPrivateResources (
688 ProcStruct
->NumberOfPrivateResources
,
689 ProcInfoNode
->PrivateResourcesArrayToken
691 if (EFI_ERROR (Status
)) {
694 "ERROR: PPTT: Failed to populate the private resources array. " \
702 // Next Processor Hierarchy Node
703 ProcStruct
= (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR
*)((UINT8
*)ProcStruct
+
706 } // Processor Hierarchy Node
708 // Knowing the total number of GICC references made and that all GICC Token
709 // references are unique, we can test if no GICC instances have been left out.
710 Status
= GetEArmObjGicCInfo (
716 if (EFI_ERROR (Status
)) {
719 "ERROR: PPTT: Failed to get GICC Info. Status = %r\n",
725 // MADT - PPTT cross validation
726 // This checks that one and only one GICC structure is referenced by a
727 // Processor Hierarchy Node in the PPTT.
728 // Since we have already checked that the GICC objects referenced by the
729 // Proc Nodes are unique, the UniqueGicCRefCount cannot be greater than
730 // the total number of GICC objects in the platform.
731 if (GicCInfoCount
> UniqueGicCRefCount
) {
732 Status
= EFI_INVALID_PARAMETER
;
735 "ERROR: PPTT: %d GICC structure(s) exposed by MADT don't have " \
736 "a corresponding Processor Hierarchy Node. Status = %r\n",
737 GicCInfoCount
- UniqueGicCRefCount
,
746 Update the Cache Type Structure (Type 1) information.
748 This function populates the Cache Type Structures with information from
749 the Configuration Manager and adds this information to the PPTT table.
751 @param [in] Generator Pointer to the PPTT Generator.
752 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
754 @param [in] Pptt Pointer to PPTT table structure.
755 @param [in] NodesStartOffset Offset from the start of PPTT table to the
756 start of Cache Type Structures.
758 @retval EFI_SUCCESS Structures updated successfully.
759 @retval EFI_INVALID_PARAMETER A parameter is invalid.
760 @retval EFI_NOT_FOUND A required object was not found.
764 AddCacheTypeStructures (
765 IN CONST ACPI_PPTT_GENERATOR
* CONST Generator
,
766 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
767 IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
* Pptt
,
768 IN CONST UINT32 NodesStartOffset
772 EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE
* CacheStruct
;
773 PPTT_NODE_INDEXER
* PpttNodeFound
;
774 CM_ARM_CACHE_INFO
* CacheInfoNode
;
775 PPTT_NODE_INDEXER
* CacheNodeIterator
;
779 (Generator
!= NULL
) &&
780 (CfgMgrProtocol
!= NULL
) &&
784 CacheStruct
= (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE
*)((UINT8
*)Pptt
+
787 CacheNodeIterator
= Generator
->CacheStructIndexedList
;
788 NodeCount
= Generator
->CacheStructCount
;
790 while (NodeCount
-- != 0) {
791 CacheInfoNode
= (CM_ARM_CACHE_INFO
*)CacheNodeIterator
->Object
;
793 // Populate the node header
794 CacheStruct
->Type
= EFI_ACPI_6_3_PPTT_TYPE_CACHE
;
795 CacheStruct
->Length
= sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE
);
796 CacheStruct
->Reserved
[0] = EFI_ACPI_RESERVED_BYTE
;
797 CacheStruct
->Reserved
[1] = EFI_ACPI_RESERVED_BYTE
;
799 // "On Arm-based systems, all cache properties must be provided in the
800 // table." (ACPI 6.3, Section 5.2.29.2)
801 CacheStruct
->Flags
.SizePropertyValid
= 1;
802 CacheStruct
->Flags
.NumberOfSetsValid
= 1;
803 CacheStruct
->Flags
.AssociativityValid
= 1;
804 CacheStruct
->Flags
.AllocationTypeValid
= 1;
805 CacheStruct
->Flags
.CacheTypeValid
= 1;
806 CacheStruct
->Flags
.WritePolicyValid
= 1;
807 CacheStruct
->Flags
.LineSizeValid
= 1;
808 CacheStruct
->Flags
.Reserved
= 0;
810 // Populate the reference to the next level of cache
811 if (CacheInfoNode
->NextLevelOfCacheToken
== CM_NULL_TOKEN
) {
812 CacheStruct
->NextLevelOfCache
= 0;
814 Status
= GetPpttNodeReferencedByToken (
815 Generator
->CacheStructIndexedList
,
816 Generator
->CacheStructCount
,
817 CacheInfoNode
->NextLevelOfCacheToken
,
820 if (EFI_ERROR (Status
)) {
823 "ERROR: PPTT: Failed to get the reference to the Next Level of " \
824 "Cache. NextLevelOfCacheToken = %p. RequestorToken = %p. " \
826 CacheInfoNode
->NextLevelOfCacheToken
,
827 CacheInfoNode
->Token
,
833 // Update Cache Structure with the offset for the next level of cache
834 CacheStruct
->NextLevelOfCache
= PpttNodeFound
->Offset
;
836 // Store the next level of cache information in the Node Indexer
837 // so that this can be used later for cycle detection
838 CacheNodeIterator
->TopologyParent
= PpttNodeFound
;
841 CacheStruct
->Size
= CacheInfoNode
->Size
;
843 // Validate and populate the 'Number of sets' field
844 if (CacheInfoNode
->NumberOfSets
> PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX
) {
845 Status
= EFI_INVALID_PARAMETER
;
848 "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum number " \
849 "of sets can be %d. NumberOfSets = %d. Status = %r\n",
850 PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX
,
851 CacheInfoNode
->NumberOfSets
,
857 if (CacheInfoNode
->NumberOfSets
> PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX
) {
860 "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \
861 "number of sets can be %d. NumberOfSets = %d\n",
862 PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX
,
863 CacheInfoNode
->NumberOfSets
867 CacheStruct
->NumberOfSets
= CacheInfoNode
->NumberOfSets
;
869 // Validate Associativity field based on maximum associativity
870 // supported by ACPI Cache type structure.
871 if (CacheInfoNode
->Associativity
> MAX_UINT8
) {
872 Status
= EFI_INVALID_PARAMETER
;
875 "ERROR: PPTT: The maximum associativity supported by ACPI " \
876 "Cache type structure is %d. Associativity = %d, Status = %r\n",
878 CacheInfoNode
->Associativity
,
884 // Validate the Associativity field based on the architecture specification
885 // The architecture supports much larger associativity values than the
886 // current ACPI specification.
887 // These checks will be needed in the future when the ACPI specification
888 // is extended. Disabling this code for now.
890 if (CacheInfoNode
->Associativity
> PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX
) {
891 Status
= EFI_INVALID_PARAMETER
;
894 "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum cache " \
895 "associativity can be %d. Associativity = %d. Status = %r\n",
896 PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX
,
897 CacheInfoNode
->Associativity
,
903 if (CacheInfoNode
->Associativity
> PPTT_ARM_CACHE_ASSOCIATIVITY_MAX
) {
906 "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \
907 "cache associativity can be %d. Associativity = %d\n",
908 PPTT_ARM_CACHE_ASSOCIATIVITY_MAX
,
909 CacheInfoNode
->Associativity
914 // Note a typecast is needed as the maximum associativity
915 // supported by ACPI Cache type structure is MAX_UINT8.
916 CacheStruct
->Associativity
= (UINT8
)CacheInfoNode
->Associativity
;
918 // Populate cache attributes
919 CacheStruct
->Attributes
.AllocationType
=
920 CacheInfoNode
->Attributes
& (BIT0
| BIT1
);
921 CacheStruct
->Attributes
.CacheType
=
922 (CacheInfoNode
->Attributes
& (BIT2
| BIT3
)) >> 2;
923 CacheStruct
->Attributes
.WritePolicy
=
924 (CacheInfoNode
->Attributes
& BIT4
) >> 4;
925 CacheStruct
->Attributes
.Reserved
= 0;
927 // Validate and populate cache line size
928 if ((CacheInfoNode
->LineSize
< PPTT_ARM_CACHE_LINE_SIZE_MIN
) ||
929 (CacheInfoNode
->LineSize
> PPTT_ARM_CACHE_LINE_SIZE_MAX
)) {
931 Status
= EFI_INVALID_PARAMETER
;
934 "ERROR: PPTT: The cache line size must be between %d and %d bytes " \
935 "on ARM Platforms. LineSize = %d. Status = %r\n" ,
936 PPTT_ARM_CACHE_LINE_SIZE_MIN
,
937 PPTT_ARM_CACHE_LINE_SIZE_MAX
,
938 CacheInfoNode
->LineSize
,
944 if ((CacheInfoNode
->LineSize
& (CacheInfoNode
->LineSize
- 1)) != 0) {
945 Status
= EFI_INVALID_PARAMETER
;
948 "ERROR: PPTT: The cache line size is not a power of 2. " \
949 "LineSize = %d. Status = %r\n" ,
950 CacheInfoNode
->LineSize
,
956 CacheStruct
->LineSize
= CacheInfoNode
->LineSize
;
958 // Next Cache Type Structure
959 CacheStruct
= (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE
*)((UINT8
*)CacheStruct
+
960 CacheStruct
->Length
);
962 } // Cache Type Structure
968 Update the ID Type Structure (Type 2) information.
970 This function populates the ID Type Structures with information from
971 the Configuration Manager and and adds this information to the PPTT table.
973 @param [in] Generator Pointer to the PPTT Generator.
974 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
976 @param [in] Pptt Pointer to PPTT table structure.
977 @param [in] NodesStartOffset Offset from the start of PPTT table to the
978 start of ID Type Structures.
980 @retval EFI_SUCCESS Structures updated successfully.
981 @retval EFI_INVALID_PARAMETER A parameter is invalid.
982 @retval EFI_NOT_FOUND A required object was not found.
986 AddIdTypeStructures (
987 IN CONST ACPI_PPTT_GENERATOR
* CONST Generator
,
988 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
989 IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
* Pptt
,
990 IN CONST UINT32 NodesStartOffset
993 EFI_ACPI_6_3_PPTT_STRUCTURE_ID
* IdStruct
;
994 CM_ARM_PROC_NODE_ID_INFO
* ProcIdInfoNode
;
995 PPTT_NODE_INDEXER
* IdStructIterator
;
1000 (Generator
!= NULL
) &&
1001 (CfgMgrProtocol
!= NULL
) &&
1005 IdStruct
= (EFI_ACPI_6_3_PPTT_STRUCTURE_ID
*)((UINT8
*)Pptt
+ NodesStartOffset
);
1007 IdStructIterator
= Generator
->IdStructIndexedList
;
1008 NodeCount
= Generator
->IdStructCount
;
1009 while (NodeCount
-- != 0) {
1010 ProcIdInfoNode
= (CM_ARM_PROC_NODE_ID_INFO
*)IdStructIterator
->Object
;
1012 // Populate the node
1013 IdStruct
->Type
= EFI_ACPI_6_3_PPTT_TYPE_ID
;
1014 IdStruct
->Length
= sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_ID
);
1015 IdStruct
->Reserved
[0] = EFI_ACPI_RESERVED_BYTE
;
1016 IdStruct
->Reserved
[1] = EFI_ACPI_RESERVED_BYTE
;
1017 IdStruct
->VendorId
= ProcIdInfoNode
->VendorId
;
1018 IdStruct
->Level1Id
= ProcIdInfoNode
->Level1Id
;
1019 IdStruct
->Level2Id
= ProcIdInfoNode
->Level2Id
;
1020 IdStruct
->MajorRev
= ProcIdInfoNode
->MajorRev
;
1021 IdStruct
->MinorRev
= ProcIdInfoNode
->MinorRev
;
1022 IdStruct
->SpinRev
= ProcIdInfoNode
->SpinRev
;
1024 // Next ID Type Structure
1025 IdStruct
= (EFI_ACPI_6_3_PPTT_STRUCTURE_ID
*)((UINT8
*)IdStruct
+
1028 } // ID Type Structure
1034 Construct the PPTT ACPI table.
1036 This function invokes the Configuration Manager protocol interface
1037 to get the required hardware information for generating the ACPI
1040 If this function allocates any resources then they must be freed
1041 in the FreeXXXXTableResources function.
1043 @param [in] This Pointer to the table generator.
1044 @param [in] AcpiTableInfo Pointer to the ACPI table generator to be used.
1045 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1047 @param [out] Table Pointer to the constructed ACPI Table.
1049 @retval EFI_SUCCESS Table generated successfully.
1050 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1051 @retval EFI_NOT_FOUND The required object was not found.
1052 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
1053 Manager is less than the Object size for
1054 the requested object.
1060 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1061 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
1062 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1063 OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
1068 UINT32 ProcTopologyStructCount
;
1069 UINT32 ProcHierarchyNodeCount
;
1070 UINT32 CacheStructCount
;
1071 UINT32 IdStructCount
;
1073 UINT32 ProcHierarchyNodeOffset
;
1074 UINT32 CacheStructOffset
;
1075 UINT32 IdStructOffset
;
1077 CM_ARM_PROC_HIERARCHY_INFO
* ProcHierarchyNodeList
;
1078 CM_ARM_CACHE_INFO
* CacheStructList
;
1079 CM_ARM_PROC_NODE_ID_INFO
* IdStructList
;
1081 ACPI_PPTT_GENERATOR
* Generator
;
1083 // Pointer to the Node Indexer array
1084 PPTT_NODE_INDEXER
* NodeIndexer
;
1086 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
* Pptt
;
1090 (AcpiTableInfo
!= NULL
) &&
1091 (CfgMgrProtocol
!= NULL
) &&
1093 (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
) &&
1094 (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
)
1097 if ((AcpiTableInfo
->AcpiTableRevision
< This
->MinAcpiTableRevision
) ||
1098 (AcpiTableInfo
->AcpiTableRevision
> This
->AcpiTableRevision
)) {
1101 "ERROR: PPTT: Requested table revision = %d is not supported. "
1102 "Supported table revisions: Minimum = %d. Maximum = %d\n",
1103 AcpiTableInfo
->AcpiTableRevision
,
1104 This
->MinAcpiTableRevision
,
1105 This
->AcpiTableRevision
1107 return EFI_INVALID_PARAMETER
;
1110 Generator
= (ACPI_PPTT_GENERATOR
*)This
;
1113 // Get the processor hierarchy info and update the processor topology
1114 // structure count with Processor Hierarchy Nodes (Type 0)
1115 Status
= GetEArmObjProcHierarchyInfo (
1118 &ProcHierarchyNodeList
,
1119 &ProcHierarchyNodeCount
1121 if (EFI_ERROR (Status
)) {
1124 "ERROR: PPTT: Failed to get processor hierarchy info. Status = %r\n",
1130 ProcTopologyStructCount
= ProcHierarchyNodeCount
;
1131 Generator
->ProcHierarchyNodeCount
= ProcHierarchyNodeCount
;
1133 // Get the cache info and update the processor topology structure count with
1134 // Cache Type Structures (Type 1)
1135 Status
= GetEArmObjCacheInfo (
1141 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1144 "ERROR: PPTT: Failed to get cache info. Status = %r\n",
1150 ProcTopologyStructCount
+= CacheStructCount
;
1151 Generator
->CacheStructCount
= CacheStructCount
;
1153 // Get the processor hierarchy node ID info and update the processor topology
1154 // structure count with ID Structures (Type 2)
1155 Status
= GetEArmObjProcNodeIdInfo (
1161 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1164 "ERROR: PPTT: Failed to get processor hierarchy node ID info. " \
1171 ProcTopologyStructCount
+= IdStructCount
;
1172 Generator
->IdStructCount
= IdStructCount
;
1174 // Allocate Node Indexer array
1175 NodeIndexer
= (PPTT_NODE_INDEXER
*)AllocateZeroPool (
1176 sizeof (PPTT_NODE_INDEXER
) *
1177 ProcTopologyStructCount
1179 if (NodeIndexer
== NULL
) {
1180 Status
= EFI_OUT_OF_RESOURCES
;
1183 "ERROR: PPTT: Failed to allocate memory for Node Indexer. Status = %r\n ",
1189 DEBUG ((DEBUG_INFO
, "INFO: NodeIndexer = %p\n", NodeIndexer
));
1190 Generator
->ProcTopologyStructCount
= ProcTopologyStructCount
;
1191 Generator
->NodeIndexer
= NodeIndexer
;
1193 // Calculate the size of the PPTT table
1194 TableSize
= sizeof (EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
);
1196 // Include the size of Processor Hierarchy Nodes and index them
1197 if (Generator
->ProcHierarchyNodeCount
!= 0) {
1198 ProcHierarchyNodeOffset
= TableSize
;
1199 Generator
->ProcHierarchyNodeIndexedList
= NodeIndexer
;
1200 TableSize
+= GetSizeofProcHierarchyNodes (
1201 ProcHierarchyNodeOffset
,
1202 ProcHierarchyNodeList
,
1203 Generator
->ProcHierarchyNodeCount
,
1209 " ProcHierarchyNodeCount = %d\n" \
1210 " ProcHierarchyNodeOffset = 0x%x\n" \
1211 " ProcHierarchyNodeIndexedList = 0x%p\n",
1212 Generator
->ProcHierarchyNodeCount
,
1213 ProcHierarchyNodeOffset
,
1214 Generator
->ProcHierarchyNodeIndexedList
1219 // Include the size of Cache Type Structures and index them
1220 if (Generator
->CacheStructCount
!= 0) {
1221 CacheStructOffset
= TableSize
;
1222 Generator
->CacheStructIndexedList
= NodeIndexer
;
1223 TableSize
+= GetSizeofCacheTypeStructs (
1226 Generator
->CacheStructCount
,
1231 " CacheStructCount = %d\n" \
1232 " CacheStructOffset = 0x%x\n" \
1233 " CacheStructIndexedList = 0x%p\n",
1234 Generator
->CacheStructCount
,
1236 Generator
->CacheStructIndexedList
1240 // Include the size of ID Type Structures and index them
1241 if (Generator
->IdStructCount
!= 0) {
1242 IdStructOffset
= TableSize
;
1243 Generator
->IdStructIndexedList
= NodeIndexer
;
1244 TableSize
+= GetSizeofIdStructs (
1247 Generator
->IdStructCount
,
1252 " IdStructCount = %d\n" \
1253 " IdStructOffset = 0x%x\n" \
1254 " IdStructIndexedList = 0x%p\n",
1255 Generator
->IdStructCount
,
1257 Generator
->IdStructIndexedList
1264 " ProcTopologyStructCount = %d\n" \
1265 " TableSize = %d\n",
1266 ProcTopologyStructCount
,
1270 // Allocate the Buffer for the PPTT table
1271 *Table
= (EFI_ACPI_DESCRIPTION_HEADER
*)AllocateZeroPool (TableSize
);
1272 if (*Table
== NULL
) {
1273 Status
= EFI_OUT_OF_RESOURCES
;
1276 "ERROR: PPTT: Failed to allocate memory for PPTT Table. " \
1277 "Size = %d. Status = %r\n",
1284 Pptt
= (EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER
*)*Table
;
1288 "PPTT: Pptt = 0x%p. TableSize = 0x%x\n",
1294 Status
= AddAcpiHeader (
1301 if (EFI_ERROR (Status
)) {
1304 "ERROR: PPTT: Failed to add ACPI header. Status = %r\n",
1310 // Add Processor Hierarchy Nodes (Type 0) to the generated table
1311 if (Generator
->ProcHierarchyNodeCount
!= 0) {
1312 Status
= AddProcHierarchyNodes (
1316 ProcHierarchyNodeOffset
1318 if (EFI_ERROR (Status
)) {
1321 "ERROR: PPTT: Failed to add Processor Hierarchy Nodes. Status = %r\n",
1328 // Add Cache Type Structures (Type 1) to the generated table
1329 if (Generator
->CacheStructCount
!= 0) {
1330 Status
= AddCacheTypeStructures (
1336 if (EFI_ERROR (Status
)) {
1339 "ERROR: PPTT: Failed to add Cache Type Structures. Status = %r\n",
1346 // Add ID Type Structures (Type 2) to the generated table
1347 if (Generator
->IdStructCount
!= 0) {
1348 Status
= AddIdTypeStructures (
1354 if (EFI_ERROR (Status
)) {
1357 "ERROR: PPTT: Failed to add ID Type Structures. Status = %r\n",
1364 // Validate CM object cross-references in PPTT
1365 Status
= DetectCyclesInTopology (Generator
);
1366 if (EFI_ERROR (Status
)) {
1369 "ERROR: PPTT: Invalid processor and cache topology. Status = %r\n",
1378 if (Generator
->NodeIndexer
!= NULL
) {
1379 FreePool (Generator
->NodeIndexer
);
1380 Generator
->NodeIndexer
= NULL
;
1383 if (*Table
!= NULL
) {
1392 Free any resources allocated for constructing the PPTT
1394 @param [in] This Pointer to the table generator.
1395 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1396 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1398 @param [in, out] Table Pointer to the ACPI Table.
1400 @retval EFI_SUCCESS The resources were freed successfully.
1401 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
1405 FreePpttTableResources (
1406 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1407 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
1408 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1409 IN OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
1412 ACPI_PPTT_GENERATOR
* Generator
;
1416 (AcpiTableInfo
!= NULL
) &&
1417 (CfgMgrProtocol
!= NULL
) &&
1418 (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
) &&
1419 (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
)
1422 Generator
= (ACPI_PPTT_GENERATOR
*)This
;
1424 // Free any memory allocated by the generator
1425 if (Generator
->NodeIndexer
!= NULL
) {
1426 FreePool (Generator
->NodeIndexer
);
1427 Generator
->NodeIndexer
= NULL
;
1430 if ((Table
== NULL
) || (*Table
== NULL
)) {
1431 DEBUG ((DEBUG_ERROR
, "ERROR: PPTT: Invalid Table Pointer\n"));
1436 return EFI_INVALID_PARAMETER
;
1444 /** The PPTT Table Generator revision.
1446 #define PPTT_GENERATOR_REVISION CREATE_REVISION (1, 0)
1448 /** The interface for the PPTT Table Generator.
1451 ACPI_PPTT_GENERATOR PpttGenerator
= {
1452 // ACPI table generator header
1455 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdPptt
),
1456 // Generator Description
1457 L
"ACPI.STD.PPTT.GENERATOR",
1458 // ACPI Table Signature
1459 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE
,
1460 // ACPI Table Revision supported by this Generator
1461 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION
,
1462 // Minimum supported ACPI Table Revision
1463 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION
,
1465 TABLE_GENERATOR_CREATOR_ID_ARM
,
1467 PPTT_GENERATOR_REVISION
,
1468 // Build Table function
1470 // Free Resource function
1471 FreePpttTableResources
,
1472 // Extended build function not needed
1474 // Extended build function not implemented by the generator.
1475 // Hence extended free resource function is not required.
1479 // PPTT Generator private data
1481 // Processor topology node count
1483 // Count of Processor Hierarchy Nodes
1485 // Count of Cache Structures
1487 // Count of Id Structures
1489 // Pointer to PPTT Node Indexer
1494 Register the Generator with the ACPI Table Factory.
1496 @param [in] ImageHandle The handle to the image.
1497 @param [in] SystemTable Pointer to the System Table.
1499 @retval EFI_SUCCESS The Generator is registered.
1500 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1501 @retval EFI_ALREADY_STARTED The Generator for the Table ID
1502 is already registered.
1506 AcpiPpttLibConstructor (
1507 IN EFI_HANDLE ImageHandle
,
1508 IN EFI_SYSTEM_TABLE
* SystemTable
1512 Status
= RegisterAcpiTableGenerator (&PpttGenerator
.Header
);
1513 DEBUG ((DEBUG_INFO
, "PPTT: Register Generator. Status = %r\n", Status
));
1514 ASSERT_EFI_ERROR (Status
);
1519 Deregister the Generator from the ACPI Table Factory.
1521 @param [in] ImageHandle The handle to the image.
1522 @param [in] SystemTable Pointer to the System Table.
1524 @retval EFI_SUCCESS The Generator is deregistered.
1525 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1526 @retval EFI_NOT_FOUND The Generator is not registered.
1530 AcpiPpttLibDestructor (
1531 IN EFI_HANDLE ImageHandle
,
1532 IN EFI_SYSTEM_TABLE
* SystemTable
1536 Status
= DeregisterAcpiTableGenerator (&PpttGenerator
.Header
);
1537 DEBUG ((DEBUG_INFO
, "PPTT: Deregister Generator. Status = %r\n", Status
));
1538 ASSERT_EFI_ERROR (Status
);