2 SSDT Cpu Topology Table Generator.
4 Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
8 - ACPI 6.3 Specification - January 2019 - s8.4 Declaring Processors
11 #include <Library/AcpiLib.h>
12 #include <Library/BaseLib.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/MemoryAllocationLib.h>
16 #include <Protocol/AcpiTable.h>
18 // Module specific include files.
19 #include <AcpiTableGenerator.h>
20 #include <ConfigurationManagerObject.h>
21 #include <ConfigurationManagerHelper.h>
22 #include <Library/AcpiHelperLib.h>
23 #include <Library/TableHelperLib.h>
24 #include <Library/AmlLib/AmlLib.h>
25 #include <Protocol/ConfigurationManagerProtocol.h>
27 #include "SsdtCpuTopologyGenerator.h"
29 /** ARM standard SSDT Cpu Topology Table Generator.
32 The following Configuration Manager Object(s) are required by
35 - EArmObjProcHierarchyInfo (OPTIONAL) along with
36 - EArmObjCmRef (OPTIONAL)
37 - EArmObjLpiInfo (OPTIONAL)
40 /** This macro expands to a function that retrieves the GIC
41 CPU interface Information from the Configuration Manager.
50 This macro expands to a function that retrieves the Processor Hierarchy
51 information from the Configuration Manager.
55 EArmObjProcHierarchyInfo
,
56 CM_ARM_PROC_HIERARCHY_INFO
60 This macro expands to a function that retrieves the cross-CM-object-
61 reference information from the Configuration Manager.
70 This macro expands to a function that retrieves the Lpi
71 information from the Configuration Manager.
79 /** Initialize the TokenTable.
81 One entry should be allocated for each CM_ARM_PROC_HIERARCHY_INFO
82 structure of the platform. The TokenTable allows to have a mapping:
83 Index <-> CM_OBJECT_TOKEN (to CM_ARM_LPI_INFO structures).
85 There will always be less sets of Lpi states (CM_ARM_OBJ_REF)
86 than the number of cpus/clusters (CM_ARM_PROC_HIERARCHY_INFO).
88 @param [in] Generator The SSDT Cpu Topology generator.
89 @param [in] Count Number of entries to allocate in the TokenTable.
91 @retval EFI_SUCCESS Success.
92 @retval EFI_INVALID_PARAMETER Invalid parameter.
93 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
98 TokenTableInitialize (
99 IN ACPI_CPU_TOPOLOGY_GENERATOR
*Generator
,
103 CM_OBJECT_TOKEN
*Table
;
105 if ((Generator
== NULL
) ||
107 (Count
>= MAX_NODE_COUNT
))
110 return EFI_INVALID_PARAMETER
;
113 Table
= AllocateZeroPool (sizeof (CM_OBJECT_TOKEN
) * Count
);
116 return EFI_OUT_OF_RESOURCES
;
119 Generator
->TokenTable
.Table
= Table
;
124 /** Free the TokenTable.
126 @param [in] Generator The SSDT Cpu Topology generator.
132 IN ACPI_CPU_TOPOLOGY_GENERATOR
*Generator
135 ASSERT (Generator
!= NULL
);
136 ASSERT (Generator
->TokenTable
.Table
!= NULL
);
138 if (Generator
->TokenTable
.Table
!= NULL
) {
139 FreePool (Generator
->TokenTable
.Table
);
143 /** Add a new entry to the TokenTable and return its index.
145 If an entry with Token is already available in the table,
146 return its index without adding a new entry.
148 @param [in] Generator The SSDT Cpu Topology generator.
149 @param [in] Token New Token entry to add.
151 @retval The index of the token entry in the TokenTable.
157 IN ACPI_CPU_TOPOLOGY_GENERATOR
*Generator
,
158 IN CM_OBJECT_TOKEN Token
161 CM_OBJECT_TOKEN
*Table
;
165 ASSERT (Generator
!= NULL
);
166 ASSERT (Generator
->TokenTable
.Table
!= NULL
);
168 Table
= Generator
->TokenTable
.Table
;
169 LastIndex
= Generator
->TokenTable
.LastIndex
;
171 // Search if there is already an entry with this Token.
172 for (Index
= 0; Index
< LastIndex
; Index
++) {
173 if (Table
[Index
] == Token
) {
178 ASSERT (LastIndex
< MAX_NODE_COUNT
);
179 ASSERT (LastIndex
< Generator
->ProcNodeCount
);
181 // If no, create a new entry.
182 Table
[LastIndex
] = Token
;
184 return Generator
->TokenTable
.LastIndex
++;
187 /** Write a string 'Xxxx\0' in AslName (5 bytes long),
188 with 'X' being the leading char of the name, and
189 with 'xxx' being Value in hexadecimal.
191 As 'xxx' in hexadecimal represents a number on 12 bits,
192 we have Value < (1 << 12).
194 @param [in] LeadChar Leading char of the name.
195 @param [in] Value Hex value of the name.
196 Must be lower than (2 << 12).
197 @param [in, out] AslName Pointer to write the 'Xxxx' string to.
198 Must be at least 5 bytes long.
200 @retval EFI_SUCCESS Success.
201 @retval EFI_INVALID_PARAMETER Invalid parameter.
209 IN OUT CHAR8
*AslName
214 if ((Value
>= MAX_NODE_COUNT
) ||
218 return EFI_INVALID_PARAMETER
;
221 AslName
[0] = LeadChar
;
222 AslName
[AML_NAME_SEG_SIZE
] = '\0';
224 for (Index
= 0; Index
< AML_NAME_SEG_SIZE
- 1; Index
++) {
225 AslName
[AML_NAME_SEG_SIZE
- Index
- 1] =
226 AsciiFromHex (((Value
>> (4 * Index
)) & 0xF));
232 /** Create and add an _LPI method to Cpu/Cluster Node.
234 For instance, transform an AML node from:
238 Name (_HID, "ACPI0007")
245 Name (_HID, "ACPI0007")
246 Method (_LPI, 0, NotSerialized)
252 @param [in] Generator The SSDT Cpu Topology generator.
253 @param [in] ProcHierarchyNodeInfo CM_ARM_PROC_HIERARCHY_INFO describing
255 @param [in] Node Node to which the _LPI method is
256 attached. Can represent a Cpu or a
259 @retval EFI_SUCCESS The function completed successfully.
260 @retval EFI_INVALID_PARAMETER Invalid parameter.
261 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
267 IN ACPI_CPU_TOPOLOGY_GENERATOR
*Generator
,
268 IN CM_ARM_PROC_HIERARCHY_INFO
*ProcHierarchyNodeInfo
,
269 IN AML_OBJECT_NODE_HANDLE
*Node
274 CHAR8 AslName
[SB_SCOPE_PREFIX_SIZE
+ AML_NAME_SEG_SIZE
];
276 ASSERT (Generator
!= NULL
);
277 ASSERT (ProcHierarchyNodeInfo
!= NULL
);
278 ASSERT (ProcHierarchyNodeInfo
->LpiToken
!= CM_NULL_TOKEN
);
279 ASSERT (Node
!= NULL
);
281 TokenIndex
= TokenTableAdd (Generator
, ProcHierarchyNodeInfo
->LpiToken
);
283 CopyMem (AslName
, SB_SCOPE_PREFIX
, SB_SCOPE_PREFIX_SIZE
);
285 Status
= WriteAslName (
288 AslName
+ SB_SCOPE_PREFIX_SIZE
- 1
290 if (EFI_ERROR (Status
)) {
296 // Method (_LPI, 0) {
297 // Return ([AslName])
299 Status
= AmlCodeGenMethodRetNameString (
308 if (EFI_ERROR (Status
)) {
315 /** Generate all the Lpi states under the '_SB' scope.
317 This function generates the following ASL code:
319 Name (L000, Package() {
331 Name (L001, Package() {
338 The Lpi states are fetched from the Configuration Manager.
339 The names of the Lpi states are generated from the TokenTable.
341 @param [in] Generator The SSDT Cpu Topology generator.
342 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
344 @param [in] ScopeNode Scope node handle ('\_SB' scope).
346 @retval EFI_SUCCESS Success.
347 @retval EFI_INVALID_PARAMETER Invalid parameter.
348 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
354 IN ACPI_CPU_TOPOLOGY_GENERATOR
*Generator
,
355 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
356 IN AML_OBJECT_NODE_HANDLE ScopeNode
364 AML_OBJECT_NODE_HANDLE LpiNode
;
365 CM_ARM_OBJ_REF
*LpiRefInfo
;
366 UINT32 LpiRefInfoCount
;
368 CM_ARM_LPI_INFO
*LpiInfo
;
369 CHAR8 AslName
[AML_NAME_SEG_SIZE
+ 1];
371 ASSERT (Generator
!= NULL
);
372 ASSERT (Generator
->TokenTable
.Table
!= NULL
);
373 ASSERT (CfgMgrProtocol
!= NULL
);
374 ASSERT (ScopeNode
!= NULL
);
376 LastIndex
= Generator
->TokenTable
.LastIndex
;
378 // For each entry in the TokenTable, create a name in the AML namespace
379 // under SB_SCOPE, to store the Lpi states associated with the LpiToken.
380 for (Index
= 0; Index
< LastIndex
; Index
++) {
381 Status
= WriteAslName ('L', Index
, AslName
);
382 if (EFI_ERROR (Status
)) {
387 // We do not support the LevelId field for now, let it to 0.
388 Status
= AmlCreateLpiNode (AslName
, 1, 0, ScopeNode
, &LpiNode
);
389 if (EFI_ERROR (Status
)) {
394 // Fetch the LPI objects referenced by the token.
395 Status
= GetEArmObjCmRef (
397 Generator
->TokenTable
.Table
[Index
],
401 if (EFI_ERROR (Status
)) {
406 for (LpiRefIndex
= 0; LpiRefIndex
< LpiRefInfoCount
; LpiRefIndex
++) {
407 // For each CM_ARM_LPI_INFO referenced by the token, add an Lpi state.
408 Status
= GetEArmObjLpiInfo (
410 LpiRefInfo
[LpiRefIndex
].ReferenceToken
,
414 if (EFI_ERROR (Status
)) {
419 Status
= AmlAddLpiState (
420 LpiInfo
->MinResidency
,
421 LpiInfo
->WorstCaseWakeLatency
,
425 LpiInfo
->EnableParentState
,
428 &LpiInfo
->RegisterEntryMethod
,
430 LpiInfo
->IntegerEntryMethod
:
432 &LpiInfo
->ResidencyCounterRegister
,
433 &LpiInfo
->UsageCounterRegister
,
437 if (EFI_ERROR (Status
)) {
447 /** Create a Cpu in the AML namespace.
449 This generates the following ASL code:
453 Name (_HID, "ACPI0007")
456 @param [in] Generator The SSDT Cpu Topology generator.
457 @param [in] ParentNode Parent node to attach the Cpu node to.
458 @param [in] GicCInfo CM_ARM_GICC_INFO object used to create the node.
459 @param [in] CpuIndex Index used to generate the node name.
460 @param [out] CpuNodePtr If not NULL, return the created Cpu node.
462 @retval EFI_SUCCESS Success.
463 @retval EFI_INVALID_PARAMETER Invalid parameter.
464 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
470 IN ACPI_CPU_TOPOLOGY_GENERATOR
*Generator
,
471 IN AML_NODE_HANDLE ParentNode
,
472 IN CM_ARM_GICC_INFO
*GicCInfo
,
474 OUT AML_OBJECT_NODE_HANDLE
*CpuNodePtr OPTIONAL
478 AML_OBJECT_NODE_HANDLE CpuNode
;
479 CHAR8 AslName
[AML_NAME_SEG_SIZE
+ 1];
481 ASSERT (Generator
!= NULL
);
482 ASSERT (ParentNode
!= NULL
);
483 ASSERT (GicCInfo
!= NULL
);
485 Status
= WriteAslName ('C', CpuIndex
, AslName
);
486 if (EFI_ERROR (Status
)) {
491 Status
= AmlCodeGenDevice (AslName
, ParentNode
, &CpuNode
);
492 if (EFI_ERROR (Status
)) {
497 Status
= AmlCodeGenNameInteger (
499 GicCInfo
->AcpiProcessorUid
,
503 if (EFI_ERROR (Status
)) {
508 Status
= AmlCodeGenNameString (
510 ACPI_HID_PROCESSOR_DEVICE
,
514 if (EFI_ERROR (Status
)) {
519 // If requested, return the handle to the CpuNode.
520 if (CpuNodePtr
!= NULL
) {
521 *CpuNodePtr
= CpuNode
;
527 /** Create a Cpu in the AML namespace from a CM_ARM_PROC_HIERARCHY_INFO
530 @param [in] Generator The SSDT Cpu Topology generator.
531 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
533 @param [in] ParentNode Parent node to attach the Cpu node to.
534 @param [in] CpuIndex Index used to generate the node name.
535 @param [in] ProcHierarchyNodeInfo CM_ARM_PROC_HIERARCHY_INFO describing
538 @retval EFI_SUCCESS Success.
539 @retval EFI_INVALID_PARAMETER Invalid parameter.
540 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
545 CreateAmlCpuFromProcHierarchy (
546 IN ACPI_CPU_TOPOLOGY_GENERATOR
*Generator
,
547 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
548 IN AML_NODE_HANDLE ParentNode
,
550 IN CM_ARM_PROC_HIERARCHY_INFO
*ProcHierarchyNodeInfo
554 CM_ARM_GICC_INFO
*GicCInfo
;
555 AML_OBJECT_NODE_HANDLE CpuNode
;
557 ASSERT (Generator
!= NULL
);
558 ASSERT (CfgMgrProtocol
!= NULL
);
559 ASSERT (ParentNode
!= NULL
);
560 ASSERT (ProcHierarchyNodeInfo
!= NULL
);
561 ASSERT (ProcHierarchyNodeInfo
->GicCToken
!= CM_NULL_TOKEN
);
563 Status
= GetEArmObjGicCInfo (
565 ProcHierarchyNodeInfo
->GicCToken
,
569 if (EFI_ERROR (Status
)) {
574 Status
= CreateAmlCpu (Generator
, ParentNode
, GicCInfo
, CpuIndex
, &CpuNode
);
575 if (EFI_ERROR (Status
)) {
580 // If a set of Lpi states is associated with the
581 // CM_ARM_PROC_HIERARCHY_INFO, create an _LPI method returning them.
582 if (ProcHierarchyNodeInfo
->LpiToken
!= CM_NULL_TOKEN
) {
583 Status
= CreateAmlLpiMethod (Generator
, ProcHierarchyNodeInfo
, CpuNode
);
584 ASSERT_EFI_ERROR (Status
);
590 /** Create a Cluster in the AML namespace.
592 Any CM_ARM_PROC_HIERARCHY_INFO object with the following flags is
593 assumed to be a cluster:
594 - EFI_ACPI_6_3_PPTT_PACKAGE_NOT_PHYSICAL
595 - EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID
596 - EFI_ACPI_6_3_PPTT_NODE_IS_NOT_LEAF
598 This generates the following ASL code:
602 Name (_HID, "ACPI0010")
605 @param [in] Generator The SSDT Cpu Topology generator.
606 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
608 @param [in] ParentNode Parent node to attach the Cluster
610 @param [in] ProcHierarchyNodeInfo CM_ARM_PROC_HIERARCHY_INFO object used
612 @param [in] ClusterIndex Index used to generate the node name.
613 @param [out] ClusterNodePtr If success, contains the created Cluster
616 @retval EFI_SUCCESS Success.
617 @retval EFI_INVALID_PARAMETER Invalid parameter.
618 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
624 IN ACPI_CPU_TOPOLOGY_GENERATOR
*Generator
,
625 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
626 IN AML_NODE_HANDLE ParentNode
,
627 IN CM_ARM_PROC_HIERARCHY_INFO
*ProcHierarchyNodeInfo
,
628 IN UINT32 ClusterIndex
,
629 OUT AML_OBJECT_NODE_HANDLE
*ClusterNodePtr
633 AML_OBJECT_NODE_HANDLE ClusterNode
;
634 CHAR8 AslNameCluster
[AML_NAME_SEG_SIZE
+ 1];
636 ASSERT (Generator
!= NULL
);
637 ASSERT (CfgMgrProtocol
!= NULL
);
638 ASSERT (ParentNode
!= NULL
);
639 ASSERT (ProcHierarchyNodeInfo
!= NULL
);
640 ASSERT (ClusterNodePtr
!= NULL
);
642 Status
= WriteAslName ('C', ClusterIndex
, AslNameCluster
);
643 if (EFI_ERROR (Status
)) {
648 Status
= AmlCodeGenDevice (AslNameCluster
, ParentNode
, &ClusterNode
);
649 if (EFI_ERROR (Status
)) {
654 // Use the ClusterIndex for the _UID value as there is no AcpiProcessorUid
655 // and EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID is set for non-Cpus.
656 Status
= AmlCodeGenNameInteger (
662 if (EFI_ERROR (Status
)) {
667 Status
= AmlCodeGenNameString (
669 ACPI_HID_PROCESSOR_CONTAINER_DEVICE
,
673 if (EFI_ERROR (Status
)) {
678 // If a set of Lpi states are associated with the
679 // CM_ARM_PROC_HIERARCHY_INFO, create an _LPI method returning them.
680 if (ProcHierarchyNodeInfo
->LpiToken
!= CM_NULL_TOKEN
) {
681 Status
= CreateAmlLpiMethod (
683 ProcHierarchyNodeInfo
,
686 if (EFI_ERROR (Status
)) {
692 *ClusterNodePtr
= ClusterNode
;
697 /** Create an AML representation of the Cpu topology.
699 A cluster is by extension any non-leave device in the cpu topology.
701 @param [in] Generator The SSDT Cpu Topology generator.
702 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
704 @param [in] NodeToken Token of the CM_ARM_PROC_HIERARCHY_INFO
706 Cannot be CM_NULL_TOKEN.
707 @param [in] ParentNode Parent node to attach the created
710 @retval EFI_SUCCESS Success.
711 @retval EFI_INVALID_PARAMETER Invalid parameter.
712 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
717 CreateAmlCpuTopologyTree (
718 IN ACPI_CPU_TOPOLOGY_GENERATOR
*Generator
,
719 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
720 IN CM_OBJECT_TOKEN NodeToken
,
721 IN AML_NODE_HANDLE ParentNode
728 AML_OBJECT_NODE_HANDLE ClusterNode
;
730 ASSERT (Generator
!= NULL
);
731 ASSERT (Generator
->ProcNodeList
!= NULL
);
732 ASSERT (Generator
->ProcNodeCount
!= 0);
733 ASSERT (CfgMgrProtocol
!= NULL
);
734 ASSERT (NodeToken
!= CM_NULL_TOKEN
);
735 ASSERT (ParentNode
!= NULL
);
740 for (Index
= 0; Index
< Generator
->ProcNodeCount
; Index
++) {
741 // Find the children of the CM_ARM_PROC_HIERARCHY_INFO
742 // currently being handled (i.e. ParentToken == NodeToken).
743 if (Generator
->ProcNodeList
[Index
].ParentToken
== NodeToken
) {
744 // Only Cpus (leaf nodes in this tree) have a GicCToken.
745 // Create a Cpu node.
746 if (Generator
->ProcNodeList
[Index
].GicCToken
!= CM_NULL_TOKEN
) {
747 if ((Generator
->ProcNodeList
[Index
].Flags
& PPTT_PROCESSOR_MASK
) !=
748 PPTT_CPU_PROCESSOR_MASK
)
752 "ERROR: SSDT-CPU-TOPOLOGY: Invalid flags for cpu: 0x%x.\n",
753 Generator
->ProcNodeList
[Index
].Flags
756 return EFI_INVALID_PARAMETER
;
759 Status
= CreateAmlCpuFromProcHierarchy (
764 &Generator
->ProcNodeList
[Index
]
766 if (EFI_ERROR (Status
)) {
773 // If this is not a Cpu, then this is a cluster.
775 // Acpi processor Id for clusters is not handled.
776 if ((Generator
->ProcNodeList
[Index
].Flags
& PPTT_PROCESSOR_MASK
) !=
777 PPTT_CLUSTER_PROCESSOR_MASK
)
781 "ERROR: SSDT-CPU-TOPOLOGY: Invalid flags for cluster: 0x%x.\n",
782 Generator
->ProcNodeList
[Index
].Flags
785 return EFI_INVALID_PARAMETER
;
788 Status
= CreateAmlCluster (
792 &Generator
->ProcNodeList
[Index
],
796 if (EFI_ERROR (Status
)) {
801 // Nodes must have a unique name in the ASL namespace.
802 // Reset the Cpu index whenever we create a new Cluster.
806 // Recursively continue creating an AML tree.
807 Status
= CreateAmlCpuTopologyTree (
810 Generator
->ProcNodeList
[Index
].Token
,
813 if (EFI_ERROR (Status
)) {
818 } // if ParentToken == NodeToken
824 /** Create the processor hierarchy AML tree from CM_ARM_PROC_HIERARCHY_INFO
827 @param [in] Generator The SSDT Cpu Topology generator.
828 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
830 @param [in] ScopeNode Scope node handle ('\_SB' scope).
832 @retval EFI_SUCCESS Success.
833 @retval EFI_INVALID_PARAMETER Invalid parameter.
834 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
839 CreateTopologyFromProcHierarchy (
840 IN ACPI_CPU_TOPOLOGY_GENERATOR
*Generator
,
841 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
842 IN AML_OBJECT_NODE_HANDLE ScopeNode
847 UINT32 TopLevelProcNodeIndex
;
849 ASSERT (Generator
!= NULL
);
850 ASSERT (Generator
->ProcNodeCount
!= 0);
851 ASSERT (Generator
->ProcNodeList
!= NULL
);
852 ASSERT (CfgMgrProtocol
!= NULL
);
853 ASSERT (ScopeNode
!= NULL
);
855 TopLevelProcNodeIndex
= MAX_UINT32
;
857 Status
= TokenTableInitialize (Generator
, Generator
->ProcNodeCount
);
858 if (EFI_ERROR (Status
)) {
863 // It is assumed that there is one unique CM_ARM_PROC_HIERARCHY_INFO
864 // structure with no ParentToken and the EFI_ACPI_6_3_PPTT_PACKAGE_PHYSICAL
865 // flag set. All other CM_ARM_PROC_HIERARCHY_INFO are non-physical and
866 // have a ParentToken.
867 for (Index
= 0; Index
< Generator
->ProcNodeCount
; Index
++) {
868 if ((Generator
->ProcNodeList
[Index
].ParentToken
== CM_NULL_TOKEN
) &&
869 (Generator
->ProcNodeList
[Index
].Flags
&
870 EFI_ACPI_6_3_PPTT_PACKAGE_PHYSICAL
))
872 if (TopLevelProcNodeIndex
!= MAX_UINT32
) {
875 "ERROR: SSDT-CPU-TOPOLOGY: Top level CM_ARM_PROC_HIERARCHY_INFO "
882 TopLevelProcNodeIndex
= Index
;
886 Status
= CreateAmlCpuTopologyTree (
889 Generator
->ProcNodeList
[TopLevelProcNodeIndex
].Token
,
892 if (EFI_ERROR (Status
)) {
897 Status
= GenerateLpiStates (Generator
, CfgMgrProtocol
, ScopeNode
);
898 if (EFI_ERROR (Status
)) {
904 TokenTableFree (Generator
);
908 /** Create the processor hierarchy AML tree from CM_ARM_GICC_INFO
911 A cluster is by extension any non-leave device in the cpu topology.
913 @param [in] Generator The SSDT Cpu Topology generator.
914 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
916 @param [in] ScopeNode Scope node handle ('\_SB' scope).
918 @retval EFI_SUCCESS Success.
919 @retval EFI_INVALID_PARAMETER Invalid parameter.
920 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
925 CreateTopologyFromGicC (
926 IN ACPI_CPU_TOPOLOGY_GENERATOR
*Generator
,
927 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
928 IN AML_OBJECT_NODE_HANDLE ScopeNode
932 CM_ARM_GICC_INFO
*GicCInfo
;
933 UINT32 GicCInfoCount
;
936 ASSERT (Generator
!= NULL
);
937 ASSERT (CfgMgrProtocol
!= NULL
);
938 ASSERT (ScopeNode
!= NULL
);
940 Status
= GetEArmObjGicCInfo (
946 if (EFI_ERROR (Status
)) {
951 // For each CM_ARM_GICC_INFO object, create an AML node.
952 for (Index
= 0; Index
< GicCInfoCount
; Index
++) {
953 Status
= CreateAmlCpu (
960 if (EFI_ERROR (Status
)) {
969 /** Construct the SSDT Cpu Topology ACPI table.
971 This function invokes the Configuration Manager protocol interface
972 to get the required hardware information for generating the ACPI
975 If this function allocates any resources then they must be freed
976 in the FreeXXXXTableResources function.
978 @param [in] This Pointer to the table generator.
979 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
980 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
982 @param [out] Table Pointer to the constructed ACPI Table.
984 @retval EFI_SUCCESS Table generated successfully.
985 @retval EFI_INVALID_PARAMETER A parameter is invalid.
986 @retval EFI_NOT_FOUND The required object was not found.
987 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
988 Manager is less than the Object size for the
994 BuildSsdtCpuTopologyTable (
995 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
996 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
997 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
998 OUT EFI_ACPI_DESCRIPTION_HEADER
**CONST Table
1002 AML_ROOT_NODE_HANDLE RootNode
;
1003 AML_OBJECT_NODE_HANDLE ScopeNode
;
1004 CM_ARM_PROC_HIERARCHY_INFO
*ProcHierarchyNodeList
;
1005 UINT32 ProcHierarchyNodeCount
;
1006 ACPI_CPU_TOPOLOGY_GENERATOR
*Generator
;
1008 ASSERT (This
!= NULL
);
1009 ASSERT (AcpiTableInfo
!= NULL
);
1010 ASSERT (CfgMgrProtocol
!= NULL
);
1011 ASSERT (Table
!= NULL
);
1012 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
1013 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
1015 Generator
= (ACPI_CPU_TOPOLOGY_GENERATOR
*)This
;
1017 Status
= AddSsdtAcpiHeader (
1023 if (EFI_ERROR (Status
)) {
1027 Status
= AmlCodeGenScope (SB_SCOPE
, RootNode
, &ScopeNode
);
1028 if (EFI_ERROR (Status
)) {
1032 // Get the processor hierarchy info and update the processor topology
1033 // structure count with Processor Hierarchy Nodes (Type 0)
1034 Status
= GetEArmObjProcHierarchyInfo (
1037 &ProcHierarchyNodeList
,
1038 &ProcHierarchyNodeCount
1040 if (EFI_ERROR (Status
) &&
1041 (Status
!= EFI_NOT_FOUND
))
1046 if (Status
== EFI_NOT_FOUND
) {
1047 // If hierarchy information is not found generate a flat topology
1048 // using CM_ARM_GICC_INFO objects.
1049 Status
= CreateTopologyFromGicC (
1054 if (EFI_ERROR (Status
)) {
1058 // Generate the topology from CM_ARM_PROC_HIERARCHY_INFO objects.
1059 Generator
->ProcNodeList
= ProcHierarchyNodeList
;
1060 Generator
->ProcNodeCount
= ProcHierarchyNodeCount
;
1062 Status
= CreateTopologyFromProcHierarchy (
1067 if (EFI_ERROR (Status
)) {
1072 Status
= AmlSerializeDefinitionBlock (
1076 if (EFI_ERROR (Status
)) {
1079 "ERROR: SSDT-CPU-TOPOLOGY: Failed to Serialize SSDT Table Data."
1087 // Delete the RootNode and its attached children.
1088 return AmlDeleteTree (RootNode
);
1091 /** Free any resources allocated for constructing the
1092 SSDT Cpu Topology ACPI table.
1094 @param [in] This Pointer to the table generator.
1095 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1096 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1098 @param [in, out] Table Pointer to the ACPI Table.
1100 @retval EFI_SUCCESS The resources were freed successfully.
1101 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
1105 FreeSsdtCpuTopologyTableResources (
1106 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
1107 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
1108 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1109 IN OUT EFI_ACPI_DESCRIPTION_HEADER
**CONST Table
1112 ASSERT (This
!= NULL
);
1113 ASSERT (AcpiTableInfo
!= NULL
);
1114 ASSERT (CfgMgrProtocol
!= NULL
);
1115 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
1116 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
1118 if ((Table
== NULL
) || (*Table
== NULL
)) {
1119 DEBUG ((DEBUG_ERROR
, "ERROR: SSDT-CPU-TOPOLOGY: Invalid Table Pointer\n"));
1120 ASSERT ((Table
!= NULL
) && (*Table
!= NULL
));
1121 return EFI_INVALID_PARAMETER
;
1129 /** This macro defines the SSDT Cpu Topology Table Generator revision.
1131 #define SSDT_CPU_TOPOLOGY_GENERATOR_REVISION CREATE_REVISION (1, 0)
1133 /** The interface for the SSDT Cpu Topology Table Generator.
1136 ACPI_CPU_TOPOLOGY_GENERATOR SsdtCpuTopologyGenerator
= {
1137 // ACPI table generator header
1140 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtCpuTopology
),
1141 // Generator Description
1142 L
"ACPI.STD.SSDT.CPU.TOPOLOGY.GENERATOR",
1143 // ACPI Table Signature
1144 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
,
1145 // ACPI Table Revision - Unused
1147 // Minimum ACPI Table Revision - Unused
1150 TABLE_GENERATOR_CREATOR_ID_ARM
,
1152 SSDT_CPU_TOPOLOGY_GENERATOR_REVISION
,
1153 // Build Table function
1154 BuildSsdtCpuTopologyTable
,
1155 // Free Resource function
1156 FreeSsdtCpuTopologyTableResources
,
1157 // Extended build function not needed
1159 // Extended build function not implemented by the generator.
1160 // Hence extended free resource function is not required.
1164 // Private fields are defined from here.
1179 /** Register the Generator with the ACPI Table Factory.
1181 @param [in] ImageHandle The handle to the image.
1182 @param [in] SystemTable Pointer to the System Table.
1184 @retval EFI_SUCCESS The Generator is registered.
1185 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1186 @retval EFI_ALREADY_STARTED The Generator for the Table ID
1187 is already registered.
1191 AcpiSsdtCpuTopologyLibConstructor (
1192 IN EFI_HANDLE ImageHandle
,
1193 IN EFI_SYSTEM_TABLE
*SystemTable
1198 Status
= RegisterAcpiTableGenerator (&SsdtCpuTopologyGenerator
.Header
);
1201 "SSDT-CPU-TOPOLOGY: Register Generator. Status = %r\n",
1204 ASSERT_EFI_ERROR (Status
);
1209 /** Deregister the Generator from the ACPI Table Factory.
1211 @param [in] ImageHandle The handle to the image.
1212 @param [in] SystemTable Pointer to the System Table.
1214 @retval EFI_SUCCESS The Generator is deregistered.
1215 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1216 @retval EFI_NOT_FOUND The Generator is not registered.
1220 AcpiSsdtCpuTopologyLibDestructor (
1221 IN EFI_HANDLE ImageHandle
,
1222 IN EFI_SYSTEM_TABLE
*SystemTable
1227 Status
= DeregisterAcpiTableGenerator (&SsdtCpuTopologyGenerator
.Header
);
1230 "SSDT-CPU-TOPOLOGY: Deregister Generator. Status = %r\n",
1233 ASSERT_EFI_ERROR (Status
);