]> git.proxmox.com Git - mirror_edk2.git/blame - DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.c
DynamicTablesPkg: PPTT: Fix uninitialized memory usage
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiPpttLibArm / PpttGenerator.c
CommitLineData
77db1156
KK
1/** @file\r
2 PPTT Table Generator\r
3\r
4 Copyright (c) 2019, ARM Limited. All rights reserved.\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7 @par Reference(s):\r
8 - ACPI 6.3 Specification, January 2019\r
9\r
10 @par Glossary:\r
11 - Cm or CM - Configuration Manager\r
12 - Obj or OBJ - Object\r
13**/\r
14\r
15#include <Library/AcpiLib.h>\r
16#include <Library/BaseLib.h>\r
17#include <Library/DebugLib.h>\r
18#include <Library/MemoryAllocationLib.h>\r
19#include <Protocol/AcpiTable.h>\r
20\r
21// Module specific include files.\r
22#include <AcpiTableGenerator.h>\r
23#include <ConfigurationManagerObject.h>\r
24#include <ConfigurationManagerHelper.h>\r
25#include <Library/TableHelperLib.h>\r
26#include <Protocol/ConfigurationManagerProtocol.h>\r
27\r
28#include "PpttGenerator.h"\r
29\r
30/**\r
31 ARM standard PPTT Generator\r
32\r
33 Requirements:\r
34 The following Configuration Manager Object(s) are used by this Generator:\r
35 - EArmObjProcHierarchyInfo (REQUIRED)\r
36 - EArmObjCacheInfo\r
37 - EArmObjProcNodeIdInfo\r
38 - EArmObjCmRef\r
39 - EArmObjGicCInfo (REQUIRED)\r
40*/\r
41\r
42/**\r
43 This macro expands to a function that retrieves the Processor Hierarchy\r
44 information from the Configuration Manager.\r
45*/\r
46GET_OBJECT_LIST (\r
47 EObjNameSpaceArm,\r
48 EArmObjProcHierarchyInfo,\r
49 CM_ARM_PROC_HIERARCHY_INFO\r
50 );\r
51\r
52/**\r
53 This macro expands to a function that retrieves the cache information\r
54 from the Configuration Manager.\r
55*/\r
56GET_OBJECT_LIST (\r
57 EObjNameSpaceArm,\r
58 EArmObjCacheInfo,\r
59 CM_ARM_CACHE_INFO\r
60 );\r
61\r
62/**\r
63 This macro expands to a function that retrieves the ID information for\r
64 Processor Hierarchy Nodes from the Configuration Manager.\r
65*/\r
66GET_OBJECT_LIST (\r
67 EObjNameSpaceArm,\r
68 EArmObjProcNodeIdInfo,\r
69 CM_ARM_PROC_NODE_ID_INFO\r
70 );\r
71\r
72/**\r
73 This macro expands to a function that retrieves the cross-CM-object-\r
74 reference information from the Configuration Manager.\r
75*/\r
76GET_OBJECT_LIST (\r
77 EObjNameSpaceArm,\r
78 EArmObjCmRef,\r
79 CM_ARM_OBJ_REF\r
80 );\r
81\r
82/**\r
83 This macro expands to a function that retrieves the GIC CPU interface\r
84 information from the Configuration Manager.\r
85*/\r
86GET_OBJECT_LIST (\r
87 EObjNameSpaceArm,\r
88 EArmObjGicCInfo,\r
89 CM_ARM_GICC_INFO\r
90 );\r
91\r
92/**\r
93 Returns the size of the PPTT Processor Hierarchy Node (Type 0) given a\r
94 Processor Hierarchy Info CM object.\r
95\r
96 @param [in] Node Pointer to Processor Hierarchy Info CM object which\r
97 represents the Processor Hierarchy Node to be generated.\r
98\r
99 @retval Size of the Processor Hierarchy Node in bytes.\r
100**/\r
101STATIC\r
102UINT32\r
103GetProcHierarchyNodeSize (\r
104 IN CONST CM_ARM_PROC_HIERARCHY_INFO * Node\r
105 )\r
106{\r
107 ASSERT (Node != NULL);\r
108\r
109 // <size of Processor Hierarchy Node> + <size of Private Resources array>\r
110 return sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR) +\r
111 (Node->NoOfPrivateResources * sizeof (UINT32));\r
112}\r
113\r
114/**\r
115 This macro expands to a function that retrieves the amount of memory required\r
116 to store the Processor Hierarchy Nodes (Type 0) and updates the Node Indexer.\r
117*/\r
118GET_SIZE_OF_PPTT_STRUCTS (\r
119 ProcHierarchyNodes,\r
120 GetProcHierarchyNodeSize (NodesToIndex),\r
121 CM_ARM_PROC_HIERARCHY_INFO\r
122 );\r
123\r
124/**\r
125 This macro expands to a function that retrieves the amount of memory required\r
126 to store the Cache Type Structures (Type 1) and updates the Node Indexer.\r
127*/\r
128GET_SIZE_OF_PPTT_STRUCTS (\r
129 CacheTypeStructs,\r
130 sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE),\r
131 CM_ARM_CACHE_INFO\r
132 );\r
133\r
134/** This macro expands to a function that retrieves the amount of memory\r
135 required to store the ID Structures (Type 2) and updates the Node Indexer.\r
136*/\r
137GET_SIZE_OF_PPTT_STRUCTS (\r
138 IdStructs,\r
139 sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_ID),\r
140 CM_ARM_PROC_NODE_ID_INFO\r
141 );\r
142\r
143/**\r
144 Search the Node Indexer and return the indexed PPTT node with the given\r
145 Token.\r
146\r
147 @param [in] NodeIndexer Pointer to the Node Indexer array.\r
148 @param [in] NodeCount Number of elements in Node Indexer.\r
149 @param [in] SearchToken Token used for Node Indexer lookup.\r
150 @param [out] IndexedNodeFound Pointer to the Node Indexer array element\r
151 with the given Token.\r
152\r
153 @retval EFI_SUCCESS Success.\r
154 @retval EFI_NOT_FOUND No element with a matching token was\r
155 found in the Node Indexer array.\r
156**/\r
157STATIC\r
158EFI_STATUS\r
159GetPpttNodeReferencedByToken (\r
160 IN PPTT_NODE_INDEXER * NodeIndexer,\r
161 IN UINT32 NodeCount,\r
162 IN CONST CM_OBJECT_TOKEN SearchToken,\r
163 OUT PPTT_NODE_INDEXER ** IndexedNodeFound\r
164 )\r
165{\r
166 EFI_STATUS Status;\r
167\r
168 ASSERT (NodeIndexer != NULL);\r
169\r
170 DEBUG ((\r
171 DEBUG_INFO,\r
172 "PPTT: Node Indexer: SearchToken = %p\n",\r
173 SearchToken\r
174 ));\r
175\r
176 while (NodeCount-- != 0) {\r
177 DEBUG ((\r
178 DEBUG_INFO,\r
179 "PPTT: Node Indexer: NodeIndexer->Token = %p. Offset = %d\n",\r
180 NodeIndexer->Token,\r
181 NodeIndexer->Offset\r
182 ));\r
183\r
184 if (NodeIndexer->Token == SearchToken) {\r
185 *IndexedNodeFound = NodeIndexer;\r
186 Status = EFI_SUCCESS;\r
187 DEBUG ((\r
188 DEBUG_INFO,\r
189 "PPTT: Node Indexer: Token = %p. Found, Status = %r\n",\r
190 SearchToken,\r
191 Status\r
192 ));\r
193 return Status;\r
194 }\r
195 NodeIndexer++;\r
196 }\r
197\r
198 Status = EFI_NOT_FOUND;\r
199 DEBUG ((\r
200 DEBUG_ERROR,\r
201 "PPTT: Node Indexer: SearchToken = %p. Status = %r\n",\r
202 SearchToken,\r
203 Status\r
204 ));\r
205\r
206 return Status;\r
207}\r
208\r
209/**\r
210 Detect cycles in the processor and cache topology graph represented in\r
211 the PPTT table.\r
212\r
213 @param [in] Generator Pointer to the PPTT Generator.\r
214\r
215 @retval EFI_SUCCESS There are no cyclic references in the graph.\r
216 @retval EFI_INVALID_PARAMETER Processor or cache references form a cycle.\r
217**/\r
218STATIC\r
219EFI_STATUS\r
220DetectCyclesInTopology (\r
221 IN CONST ACPI_PPTT_GENERATOR * CONST Generator\r
222 )\r
223{\r
224 EFI_STATUS Status;\r
225 PPTT_NODE_INDEXER * Iterator;\r
226 PPTT_NODE_INDEXER * CycleDetector;\r
227 UINT32 NodesRemaining;\r
228\r
229 ASSERT (Generator != NULL);\r
230\r
231 Iterator = Generator->NodeIndexer;\r
232 NodesRemaining = Generator->ProcTopologyStructCount;\r
233\r
234 while (NodesRemaining != 0) {\r
235 DEBUG ((\r
236 DEBUG_INFO,\r
237 "INFO: PPTT: Cycle detection for element with index %d\n",\r
238 Generator->ProcTopologyStructCount - NodesRemaining\r
239 ));\r
240\r
241 CycleDetector = Iterator;\r
242\r
243 // Walk the topology tree\r
244 while (CycleDetector->TopologyParent != NULL) {\r
245 DEBUG ((\r
246 DEBUG_INFO,\r
247 "INFO: PPTT: %p -> %p\n",\r
248 CycleDetector->Token,\r
249 CycleDetector->TopologyParent->Token\r
250 ));\r
251\r
252 // Check if we have already visited this node\r
253 if (CycleDetector->CycleDetectionStamp == NodesRemaining) {\r
254 Status = EFI_INVALID_PARAMETER;\r
255 DEBUG ((\r
256 DEBUG_ERROR,\r
257 "ERROR: PPTT: Cycle in processor and cache topology detected for " \\r
258 "a chain of references originating from a node with: Token = %p " \\r
259 "Status = %r\n",\r
260 Iterator->Token,\r
261 Status\r
262 ));\r
263 return Status;\r
264 }\r
265\r
266 // Stamp the visited node\r
267 CycleDetector->CycleDetectionStamp = NodesRemaining;\r
268 CycleDetector = CycleDetector->TopologyParent;\r
269 } // Continue topology tree walk\r
270\r
271 Iterator++;\r
272 NodesRemaining--;\r
273 } // Next Node Indexer\r
274\r
275 return EFI_SUCCESS;\r
276}\r
277\r
278/**\r
279 Update the array of private resources for a given Processor Hierarchy Node.\r
280\r
281 @param [in] Generator Pointer to the PPTT Generator.\r
282 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
283 Protocol Interface.\r
284 @param [in] PrivResArray Pointer to the array of private resources.\r
285 @param [in] PrivResCount Number of private resources.\r
286 @param [in] PrivResArrayToken Reference Token for the CM_ARM_OBJ_REF\r
287 array describing node's private resources.\r
288\r
289 @retval EFI_SUCCESS Array updated successfully.\r
290 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
291 @retval EFI_NOT_FOUND A private resource was not found.\r
292**/\r
293STATIC\r
294EFI_STATUS\r
295AddPrivateResources (\r
296 IN CONST ACPI_PPTT_GENERATOR * CONST Generator,\r
297 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
298 IN UINT32 * PrivResArray,\r
299 IN UINT32 PrivResCount,\r
300 IN CONST CM_OBJECT_TOKEN PrivResArrayToken\r
301 )\r
302{\r
303 EFI_STATUS Status;\r
304 CM_ARM_OBJ_REF * CmObjRefs;\r
305 UINT32 CmObjRefCount;\r
306 PPTT_NODE_INDEXER * PpttNodeFound;\r
307\r
308 ASSERT (\r
309 (Generator != NULL) &&\r
310 (CfgMgrProtocol != NULL) &&\r
311 (PrivResArray != NULL) &&\r
312 (PrivResCount != 0)\r
313 );\r
314\r
315 // Validate input arguments\r
316 if (PrivResArrayToken == CM_NULL_TOKEN) {\r
317 Status = EFI_INVALID_PARAMETER;\r
318 DEBUG ((\r
319 DEBUG_ERROR,\r
320 "ERROR: PPTT: The number of private resources is %d while " \\r
321 "PrivResToken = CM_NULL_TOKEN. Status = %r\n",\r
322 PrivResCount,\r
323 Status\r
324 ));\r
325 return Status;\r
326 }\r
327\r
328 CmObjRefCount = 0;\r
329 // Get the CM Object References\r
330 Status = GetEArmObjCmRef (\r
331 CfgMgrProtocol,\r
332 PrivResArrayToken,\r
333 &CmObjRefs,\r
334 &CmObjRefCount\r
335 );\r
336 if (EFI_ERROR (Status)) {\r
337 DEBUG ((\r
338 DEBUG_ERROR,\r
339 "ERROR: PPTT: Failed to get CM Object References. " \\r
340 "PrivResToken = %p. Status = %r\n",\r
341 PrivResArrayToken,\r
342 Status\r
343 ));\r
344 return Status;\r
345 }\r
346\r
347 if (CmObjRefCount != PrivResCount) {\r
348 Status = EFI_INVALID_PARAMETER;\r
349 DEBUG ((\r
350 DEBUG_ERROR,\r
351 "ERROR: PPTT: The number of CM Object References retrieved and the " \\r
352 "number of private resources don't match. CmObjRefCount = %d. " \\r
353 "PrivResourceCount = %d. PrivResToken = %p. Status = %r\n",\r
354 CmObjRefCount,\r
355 PrivResCount,\r
356 PrivResArrayToken,\r
357 Status\r
358 ));\r
359 return Status;\r
360 }\r
361\r
362 while (PrivResCount-- != 0) {\r
363 if (CmObjRefs->ReferenceToken == CM_NULL_TOKEN) {\r
364 Status = EFI_INVALID_PARAMETER;\r
365 DEBUG ((\r
366 DEBUG_ERROR,\r
367 "ERROR: PPTT: CM_NULL_TOKEN provided as reference token for a " \\r
368 "private resource. Status = %r\n",\r
369 Status\r
370 ));\r
371 return Status;\r
372 }\r
373\r
374 // The Node indexer has the Processor hierarchy nodes at the begining\r
375 // followed by the cache structs and Id structs. Therefore we can\r
376 // skip the Processor hierarchy nodes in the node indexer search.\r
377 Status = GetPpttNodeReferencedByToken (\r
378 Generator->CacheStructIndexedList,\r
379 (Generator->ProcTopologyStructCount -\r
380 Generator->ProcHierarchyNodeCount),\r
381 CmObjRefs->ReferenceToken,\r
382 &PpttNodeFound\r
383 );\r
384 if (EFI_ERROR (Status)) {\r
385 DEBUG ((\r
386 DEBUG_ERROR,\r
387 "ERROR: PPTT: Failed to get a private resource with Token = %p from " \\r
388 "Node Indexer. Status = %r\n",\r
389 CmObjRefs->ReferenceToken,\r
390 Status\r
391 ));\r
392 return Status;\r
393 }\r
394\r
395 // Update the offset of the private resources in the Processor\r
396 // Hierarchy Node structure\r
397 *(PrivResArray++) = PpttNodeFound->Offset;\r
398 CmObjRefs++;\r
399 }\r
400\r
401 return EFI_SUCCESS;\r
402}\r
403\r
404/**\r
405 Function to test if two indexed Processor Hierarchy Info objects map to the\r
406 same GIC CPU Interface Info object.\r
407\r
408 This is a callback function that can be invoked by FindDuplicateValue ().\r
409\r
410 @param [in] Object1 Pointer to the first indexed Processor Hierarchy\r
411 Info object.\r
412 @param [in] Object2 Pointer to the second indexed Processor Hierarchy\r
413 Info object.\r
414 @param [in] Index1 Index of Object1 to be displayed for debugging\r
415 purposes.\r
416 @param [in] Index2 Index of Object2 to be displayed for debugging\r
417 purposes.\r
418\r
419 @retval TRUE Object1 and Object2 have the same GicCToken.\r
420 @retval FALSE Object1 and Object2 have different GicCTokens.\r
421**/\r
422BOOLEAN\r
423EFIAPI\r
424IsGicCTokenEqual (\r
425 IN CONST VOID * Object1,\r
426 IN CONST VOID * Object2,\r
427 IN UINTN Index1,\r
428 IN UINTN Index2\r
429 )\r
430{\r
431 PPTT_NODE_INDEXER * IndexedObject1;\r
432 PPTT_NODE_INDEXER * IndexedObject2;\r
433 CM_ARM_PROC_HIERARCHY_INFO * ProcNode1;\r
434 CM_ARM_PROC_HIERARCHY_INFO * ProcNode2;\r
435\r
436 ASSERT (\r
437 (Object1 != NULL) &&\r
438 (Object2 != NULL)\r
439 );\r
440\r
441 IndexedObject1 = (PPTT_NODE_INDEXER*)Object1;\r
442 IndexedObject2 = (PPTT_NODE_INDEXER*)Object2;\r
443 ProcNode1 = (CM_ARM_PROC_HIERARCHY_INFO*)IndexedObject1->Object;\r
444 ProcNode2 = (CM_ARM_PROC_HIERARCHY_INFO*)IndexedObject2->Object;\r
445\r
446 if (IS_ACPI_PROC_ID_VALID (ProcNode1) &&\r
447 IS_ACPI_PROC_ID_VALID (ProcNode2) &&\r
448 (ProcNode1->GicCToken != CM_NULL_TOKEN) &&\r
449 (ProcNode2->GicCToken != CM_NULL_TOKEN) &&\r
450 (ProcNode1->GicCToken == ProcNode2->GicCToken)) {\r
451 DEBUG ((\r
452 DEBUG_ERROR,\r
453 "ERROR: PPTT: Two Processor Hierarchy Info objects (%d and %d) map to " \\r
454 "the same GICC Info object. ACPI Processor IDs are not unique. " \\r
455 "GicCToken = %p.\n",\r
456 Index1,\r
457 IndexedObject1->Token,\r
458 Index2,\r
459 ProcNode1->GicCToken\r
460 ));\r
461 return TRUE;\r
462 }\r
463\r
464 return FALSE;\r
465}\r
466\r
467/**\r
468 Update the Processor Hierarchy Node (Type 0) information.\r
469\r
470 This function populates the Processor Hierarchy Nodes with information from\r
471 the Configuration Manager and adds this information to the PPTT table.\r
472\r
473 @param [in] Generator Pointer to the PPTT Generator.\r
474 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
475 Protocol Interface.\r
476 @param [in] Pptt Pointer to PPTT table structure.\r
477 @param [in] NodesStartOffset Offset from the start of PPTT table to the\r
478 start of Processor Hierarchy Nodes.\r
479\r
480 @retval EFI_SUCCESS Node updated successfully.\r
481 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
482 @retval EFI_NOT_FOUND The required object was not found.\r
483**/\r
484STATIC\r
485EFI_STATUS\r
486AddProcHierarchyNodes (\r
487 IN CONST ACPI_PPTT_GENERATOR * CONST Generator,\r
488 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
489 IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER * Pptt,\r
490 IN CONST UINT32 NodesStartOffset\r
491 )\r
492{\r
493 EFI_STATUS Status;\r
494 EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR * ProcStruct;\r
495 UINT32 * PrivateResources;\r
496 BOOLEAN IsGicCTokenDuplicated;\r
497\r
498 CM_ARM_GICC_INFO * GicCInfoList;\r
499 UINT32 GicCInfoCount;\r
500 UINT32 UniqueGicCRefCount;\r
501\r
502 PPTT_NODE_INDEXER * PpttNodeFound;\r
503 CM_ARM_PROC_HIERARCHY_INFO * ProcInfoNode;\r
504\r
505 PPTT_NODE_INDEXER * ProcNodeIterator;\r
506 UINT32 NodeCount;\r
96bb6704 507 UINT32 Length;\r
77db1156
KK
508\r
509 ASSERT (\r
510 (Generator != NULL) &&\r
511 (CfgMgrProtocol != NULL) &&\r
512 (Pptt != NULL)\r
513 );\r
514\r
515 ProcStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR*)((UINT8*)Pptt +\r
516 NodesStartOffset);\r
517\r
518 ProcNodeIterator = Generator->ProcHierarchyNodeIndexedList;\r
519 NodeCount = Generator->ProcHierarchyNodeCount;\r
520\r
521 // Check if every GICC Object is referenced by onlu one Proc Node\r
522 IsGicCTokenDuplicated = FindDuplicateValue (\r
523 ProcNodeIterator,\r
524 NodeCount,\r
525 sizeof (PPTT_NODE_INDEXER),\r
526 IsGicCTokenEqual\r
527 );\r
528 // Duplicate GIC CPU Interface Token was found so two PPTT Processor Hierarchy\r
529 // Nodes map to the same MADT GICC structure\r
530 if (IsGicCTokenDuplicated) {\r
531 return EFI_INVALID_PARAMETER;\r
532 }\r
533\r
534 UniqueGicCRefCount = 0;\r
535\r
536 while (NodeCount-- != 0) {\r
537 ProcInfoNode = (CM_ARM_PROC_HIERARCHY_INFO*)ProcNodeIterator->Object;\r
538\r
539 // Check if the private resource count is within the size limit\r
540 // imposed on the Processor Hierarchy node by the specification.\r
541 // Note: The length field is 8 bit wide while the number of private\r
542 // resource field is 32 bit wide.\r
96bb6704
SM
543 Length = GetProcHierarchyNodeSize (ProcInfoNode);\r
544 if (Length > MAX_UINT8) {\r
77db1156
KK
545 Status = EFI_INVALID_PARAMETER;\r
546 DEBUG ((\r
547 DEBUG_ERROR,\r
548 "ERROR: PPTT: Too many private resources. Count = %d. " \\r
549 "Maximum supported Processor Node size exceeded. " \\r
550 "Token = %p. Status = %r\n",\r
551 ProcInfoNode->NoOfPrivateResources,\r
552 ProcInfoNode->ParentToken,\r
553 Status\r
554 ));\r
555 return Status;\r
556 }\r
557\r
558 // Populate the node header\r
559 ProcStruct->Type = EFI_ACPI_6_3_PPTT_TYPE_PROCESSOR;\r
96bb6704 560 ProcStruct->Length = (UINT8)Length;\r
77db1156
KK
561 ProcStruct->Reserved[0] = EFI_ACPI_RESERVED_BYTE;\r
562 ProcStruct->Reserved[1] = EFI_ACPI_RESERVED_BYTE;\r
563\r
564 // Populate the flags\r
565 ProcStruct->Flags.PhysicalPackage = ProcInfoNode->Flags & BIT0;\r
566 ProcStruct->Flags.AcpiProcessorIdValid = (ProcInfoNode->Flags & BIT1) >> 1;\r
567 ProcStruct->Flags.ProcessorIsAThread = (ProcInfoNode->Flags & BIT2) >> 2;\r
568 ProcStruct->Flags.NodeIsALeaf = (ProcInfoNode->Flags & BIT3) >> 3;\r
569 ProcStruct->Flags.IdenticalImplementation =\r
570 (ProcInfoNode->Flags & BIT4) >> 4;\r
571 ProcStruct->Flags.Reserved = 0;\r
572\r
573 // Populate the parent reference\r
574 if (ProcInfoNode->ParentToken == CM_NULL_TOKEN) {\r
575 ProcStruct->Parent = 0;\r
576 } else {\r
577 Status = GetPpttNodeReferencedByToken (\r
578 Generator->ProcHierarchyNodeIndexedList,\r
579 Generator->ProcHierarchyNodeCount,\r
580 ProcInfoNode->ParentToken,\r
581 &PpttNodeFound\r
582 );\r
583 if (EFI_ERROR (Status)) {\r
584 DEBUG ((\r
585 DEBUG_ERROR,\r
586 "ERROR: PPTT: Failed to get parent processor hierarchy node " \\r
587 "reference. Token = %p, Status = %r\n",\r
588 ProcInfoNode->ParentToken,\r
589 ProcInfoNode->Token,\r
590 Status\r
591 ));\r
592 return Status;\r
593 }\r
594\r
595 // Test if the reference is to a 'leaf' node\r
596 if (IS_PROC_NODE_LEAF (\r
597 ((CM_ARM_PROC_HIERARCHY_INFO*)PpttNodeFound->Object))) {\r
598 Status = EFI_INVALID_PARAMETER;\r
599 DEBUG ((\r
600 DEBUG_ERROR,\r
601 "ERROR: PPTT: Reference to a leaf Processor Hierarchy Node. " \\r
602 "ParentToken = %p. ChildToken = %p. Status = %r\n",\r
603 ProcInfoNode->ParentToken,\r
604 ProcInfoNode->Token,\r
605 Status\r
606 ));\r
607 return Status;\r
608 }\r
609\r
610 // Update Proc Structure with the offset of the parent node\r
611 ProcStruct->Parent = PpttNodeFound->Offset;\r
612\r
613 // Store the reference for the parent node in the Node Indexer\r
614 // so that this can be used later for cycle detection\r
615 ProcNodeIterator->TopologyParent = PpttNodeFound;\r
616 }\r
617\r
618 // Populate ACPI Processor ID\r
619 if (!IS_ACPI_PROC_ID_VALID (ProcInfoNode)) {\r
620 // Default invalid ACPI Processor ID to 0\r
621 ProcStruct->AcpiProcessorId = 0;\r
622 } else if (ProcInfoNode->GicCToken == CM_NULL_TOKEN) {\r
623 Status = EFI_INVALID_PARAMETER;\r
624 DEBUG ((\r
625 DEBUG_ERROR,\r
626 "ERROR: PPTT: The 'ACPI Processor ID valid' flag is set but no GICC " \\r
627 "structure token was provided. GicCToken = %p. RequestorToken = %p. " \\r
628 "Status = %r\n",\r
629 ProcInfoNode->GicCToken,\r
630 ProcInfoNode->Token,\r
631 Status\r
632 ));\r
633 return Status;\r
634 } else {\r
635 Status = GetEArmObjGicCInfo (\r
636 CfgMgrProtocol,\r
637 ProcInfoNode->GicCToken,\r
638 &GicCInfoList,\r
639 &GicCInfoCount\r
640 );\r
641 if (EFI_ERROR (Status)) {\r
642 DEBUG ((\r
643 DEBUG_ERROR,\r
644 "ERROR: PPTT: Failed to get GICC structure. ACPI Processor ID " \\r
645 "can't be populated. GicCToken = %p. RequestorToken = %p. " \\r
646 "Status = %r\n",\r
647 ProcInfoNode->GicCToken,\r
648 ProcInfoNode->Token,\r
649 Status\r
650 ));\r
651 return Status;\r
652 }\r
653\r
654 if (GicCInfoCount != 1) {\r
655 Status = EFI_INVALID_PARAMETER;\r
656 DEBUG ((\r
657 DEBUG_ERROR,\r
658 "ERROR: PPTT: Failed to find a unique GICC structure. " \\r
659 "ACPI Processor ID can't be populated. " \\r
660 "GICC Structure Count = %d. GicCToken = %p. RequestorToken = %p " \\r
661 "Status = %r\n",\r
662 GicCInfoCount,\r
663 ProcInfoNode->GicCToken,\r
664 ProcInfoNode->Token,\r
665 Status\r
666 ));\r
667 return Status;\r
668 }\r
669\r
670 // Update the ACPI Processor Id\r
671 ProcStruct->AcpiProcessorId = GicCInfoList->AcpiProcessorUid;\r
672\r
673 // Increment the reference count for the number of\r
674 // Unique GICC objects that were retrieved.\r
675 UniqueGicCRefCount++;\r
676 }\r
677\r
678 ProcStruct->NumberOfPrivateResources = ProcInfoNode->NoOfPrivateResources;\r
679 PrivateResources = (UINT32*)((UINT8*)ProcStruct +\r
680 sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR));\r
681\r
682 if (ProcStruct->NumberOfPrivateResources != 0) {\r
683 // Populate the private resources array\r
684 Status = AddPrivateResources (\r
685 Generator,\r
686 CfgMgrProtocol,\r
687 PrivateResources,\r
688 ProcStruct->NumberOfPrivateResources,\r
689 ProcInfoNode->PrivateResourcesArrayToken\r
690 );\r
691 if (EFI_ERROR (Status)) {\r
692 DEBUG ((\r
693 DEBUG_ERROR,\r
694 "ERROR: PPTT: Failed to populate the private resources array. " \\r
695 "Status = %r\n",\r
696 Status\r
697 ));\r
698 return Status;\r
699 }\r
700 }\r
701\r
702 // Next Processor Hierarchy Node\r
703 ProcStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR*)((UINT8*)ProcStruct +\r
704 ProcStruct->Length);\r
705 ProcNodeIterator++;\r
706 } // Processor Hierarchy Node\r
707\r
708 // Knowing the total number of GICC references made and that all GICC Token\r
709 // references are unique, we can test if no GICC instances have been left out.\r
710 Status = GetEArmObjGicCInfo (\r
711 CfgMgrProtocol,\r
712 CM_NULL_TOKEN,\r
713 &GicCInfoList,\r
714 &GicCInfoCount\r
715 );\r
716 if (EFI_ERROR (Status)) {\r
717 DEBUG ((\r
718 DEBUG_ERROR,\r
719 "ERROR: PPTT: Failed to get GICC Info. Status = %r\n",\r
720 Status\r
721 ));\r
722 return Status;\r
723 }\r
724\r
725 // MADT - PPTT cross validation\r
726 // This checks that one and only one GICC structure is referenced by a\r
727 // Processor Hierarchy Node in the PPTT.\r
728 // Since we have already checked that the GICC objects referenced by the\r
729 // Proc Nodes are unique, the UniqueGicCRefCount cannot be greater than\r
730 // the total number of GICC objects in the platform.\r
731 if (GicCInfoCount > UniqueGicCRefCount) {\r
732 Status = EFI_INVALID_PARAMETER;\r
733 DEBUG ((\r
734 DEBUG_ERROR,\r
735 "ERROR: PPTT: %d GICC structure(s) exposed by MADT don't have " \\r
736 "a corresponding Processor Hierarchy Node. Status = %r\n",\r
737 GicCInfoCount - UniqueGicCRefCount,\r
738 Status\r
739 ));\r
740 }\r
741\r
742 return Status;\r
743}\r
744\r
745/**\r
746 Update the Cache Type Structure (Type 1) information.\r
747\r
748 This function populates the Cache Type Structures with information from\r
749 the Configuration Manager and adds this information to the PPTT table.\r
750\r
751 @param [in] Generator Pointer to the PPTT Generator.\r
752 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
753 Protocol Interface.\r
754 @param [in] Pptt Pointer to PPTT table structure.\r
755 @param [in] NodesStartOffset Offset from the start of PPTT table to the\r
756 start of Cache Type Structures.\r
757\r
758 @retval EFI_SUCCESS Structures updated successfully.\r
759 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
760 @retval EFI_NOT_FOUND A required object was not found.\r
761**/\r
762STATIC\r
763EFI_STATUS\r
764AddCacheTypeStructures (\r
765 IN CONST ACPI_PPTT_GENERATOR * CONST Generator,\r
766 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
767 IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER * Pptt,\r
768 IN CONST UINT32 NodesStartOffset\r
769 )\r
770{\r
771 EFI_STATUS Status;\r
772 EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE * CacheStruct;\r
773 PPTT_NODE_INDEXER * PpttNodeFound;\r
774 CM_ARM_CACHE_INFO * CacheInfoNode;\r
775 PPTT_NODE_INDEXER * CacheNodeIterator;\r
776 UINT32 NodeCount;\r
777\r
778 ASSERT (\r
779 (Generator != NULL) &&\r
780 (CfgMgrProtocol != NULL) &&\r
781 (Pptt != NULL)\r
782 );\r
783\r
784 CacheStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE*)((UINT8*)Pptt +\r
785 NodesStartOffset);\r
786\r
787 CacheNodeIterator = Generator->CacheStructIndexedList;\r
788 NodeCount = Generator->CacheStructCount;\r
789\r
790 while (NodeCount-- != 0) {\r
791 CacheInfoNode = (CM_ARM_CACHE_INFO*)CacheNodeIterator->Object;\r
792\r
793 // Populate the node header\r
794 CacheStruct->Type = EFI_ACPI_6_3_PPTT_TYPE_CACHE;\r
795 CacheStruct->Length = sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE);\r
796 CacheStruct->Reserved[0] = EFI_ACPI_RESERVED_BYTE;\r
797 CacheStruct->Reserved[1] = EFI_ACPI_RESERVED_BYTE;\r
798\r
799 // "On Arm-based systems, all cache properties must be provided in the\r
800 // table." (ACPI 6.3, Section 5.2.29.2)\r
801 CacheStruct->Flags.SizePropertyValid = 1;\r
802 CacheStruct->Flags.NumberOfSetsValid = 1;\r
803 CacheStruct->Flags.AssociativityValid = 1;\r
804 CacheStruct->Flags.AllocationTypeValid = 1;\r
805 CacheStruct->Flags.CacheTypeValid = 1;\r
806 CacheStruct->Flags.WritePolicyValid = 1;\r
807 CacheStruct->Flags.LineSizeValid = 1;\r
808 CacheStruct->Flags.Reserved = 0;\r
809\r
810 // Populate the reference to the next level of cache\r
811 if (CacheInfoNode->NextLevelOfCacheToken == CM_NULL_TOKEN) {\r
812 CacheStruct->NextLevelOfCache = 0;\r
813 } else {\r
814 Status = GetPpttNodeReferencedByToken (\r
815 Generator->CacheStructIndexedList,\r
816 Generator->CacheStructCount,\r
817 CacheInfoNode->NextLevelOfCacheToken,\r
818 &PpttNodeFound\r
819 );\r
820 if (EFI_ERROR (Status)) {\r
821 DEBUG ((\r
822 DEBUG_ERROR,\r
823 "ERROR: PPTT: Failed to get the reference to the Next Level of " \\r
824 "Cache. NextLevelOfCacheToken = %p. RequestorToken = %p. " \\r
825 "Status = %r\n",\r
826 CacheInfoNode->NextLevelOfCacheToken,\r
827 CacheInfoNode->Token,\r
828 Status\r
829 ));\r
830 return Status;\r
831 }\r
832\r
833 // Update Cache Structure with the offset for the next level of cache\r
834 CacheStruct->NextLevelOfCache = PpttNodeFound->Offset;\r
835\r
836 // Store the next level of cache information in the Node Indexer\r
837 // so that this can be used later for cycle detection\r
838 CacheNodeIterator->TopologyParent = PpttNodeFound;\r
839 }\r
840\r
841 CacheStruct->Size = CacheInfoNode->Size;\r
842\r
843 // Validate and populate the 'Number of sets' field\r
844 if (CacheInfoNode->NumberOfSets > PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX) {\r
845 Status = EFI_INVALID_PARAMETER;\r
846 DEBUG ((\r
847 DEBUG_ERROR,\r
848 "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum number " \\r
849 "of sets can be %d. NumberOfSets = %d. Status = %r\n",\r
850 PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX,\r
851 CacheInfoNode->NumberOfSets,\r
852 Status\r
853 ));\r
854 return Status;\r
855 }\r
856\r
857 if (CacheInfoNode->NumberOfSets > PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX) {\r
858 DEBUG ((\r
859 DEBUG_INFO,\r
860 "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \\r
861 "number of sets can be %d. NumberOfSets = %d\n",\r
862 PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX,\r
863 CacheInfoNode->NumberOfSets\r
864 ));\r
865 }\r
866\r
867 CacheStruct->NumberOfSets = CacheInfoNode->NumberOfSets;\r
868\r
869 // Validate Associativity field based on maximum associativity\r
870 // supported by ACPI Cache type structure.\r
871 if (CacheInfoNode->Associativity > MAX_UINT8) {\r
872 Status = EFI_INVALID_PARAMETER;\r
873 DEBUG ((\r
874 DEBUG_ERROR,\r
875 "ERROR: PPTT: The maximum associativity supported by ACPI " \\r
876 "Cache type structure is %d. Associativity = %d, Status = %r\n",\r
877 MAX_UINT8,\r
878 CacheInfoNode->Associativity,\r
879 Status\r
880 ));\r
881 return Status;\r
882 }\r
883\r
884 // Validate the Associativity field based on the architecture specification\r
885 // The architecture supports much larger associativity values than the\r
886 // current ACPI specification.\r
887 // These checks will be needed in the future when the ACPI specification\r
888 // is extended. Disabling this code for now.\r
889#if 0\r
890 if (CacheInfoNode->Associativity > PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX) {\r
891 Status = EFI_INVALID_PARAMETER;\r
892 DEBUG ((\r
893 DEBUG_ERROR,\r
894 "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum cache " \\r
895 "associativity can be %d. Associativity = %d. Status = %r\n",\r
896 PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX,\r
897 CacheInfoNode->Associativity,\r
898 Status\r
899 ));\r
900 return Status;\r
901 }\r
902\r
903 if (CacheInfoNode->Associativity > PPTT_ARM_CACHE_ASSOCIATIVITY_MAX) {\r
904 DEBUG ((\r
905 DEBUG_INFO,\r
906 "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \\r
907 "cache associativity can be %d. Associativity = %d\n",\r
908 PPTT_ARM_CACHE_ASSOCIATIVITY_MAX,\r
909 CacheInfoNode->Associativity\r
910 ));\r
911 }\r
912#endif\r
913\r
914 // Note a typecast is needed as the maximum associativity\r
915 // supported by ACPI Cache type structure is MAX_UINT8.\r
916 CacheStruct->Associativity = (UINT8)CacheInfoNode->Associativity;\r
917\r
918 // Populate cache attributes\r
919 CacheStruct->Attributes.AllocationType =\r
920 CacheInfoNode->Attributes & (BIT0 | BIT1);\r
921 CacheStruct->Attributes.CacheType =\r
922 (CacheInfoNode->Attributes & (BIT2 | BIT3)) >> 2;\r
923 CacheStruct->Attributes.WritePolicy =\r
924 (CacheInfoNode->Attributes & BIT4) >> 4;\r
925 CacheStruct->Attributes.Reserved = 0;\r
926\r
927 // Validate and populate cache line size\r
928 if ((CacheInfoNode->LineSize < PPTT_ARM_CACHE_LINE_SIZE_MIN) ||\r
929 (CacheInfoNode->LineSize > PPTT_ARM_CACHE_LINE_SIZE_MAX)) {\r
930\r
931 Status = EFI_INVALID_PARAMETER;\r
932 DEBUG ((\r
933 DEBUG_ERROR,\r
934 "ERROR: PPTT: The cache line size must be between %d and %d bytes " \\r
935 "on ARM Platforms. LineSize = %d. Status = %r\n" ,\r
936 PPTT_ARM_CACHE_LINE_SIZE_MIN,\r
937 PPTT_ARM_CACHE_LINE_SIZE_MAX,\r
938 CacheInfoNode->LineSize,\r
939 Status\r
940 ));\r
941 return Status;\r
942 }\r
943\r
944 if ((CacheInfoNode->LineSize & (CacheInfoNode->LineSize - 1)) != 0) {\r
945 Status = EFI_INVALID_PARAMETER;\r
946 DEBUG ((\r
947 DEBUG_ERROR,\r
948 "ERROR: PPTT: The cache line size is not a power of 2. " \\r
949 "LineSize = %d. Status = %r\n" ,\r
950 CacheInfoNode->LineSize,\r
951 Status\r
952 ));\r
953 return Status;\r
954 }\r
955\r
956 CacheStruct->LineSize = CacheInfoNode->LineSize;\r
957\r
958 // Next Cache Type Structure\r
959 CacheStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE*)((UINT8*)CacheStruct +\r
960 CacheStruct->Length);\r
961 CacheNodeIterator++;\r
962 } // Cache Type Structure\r
963\r
964 return EFI_SUCCESS;\r
965}\r
966\r
967/**\r
968 Update the ID Type Structure (Type 2) information.\r
969\r
970 This function populates the ID Type Structures with information from\r
971 the Configuration Manager and and adds this information to the PPTT table.\r
972\r
973 @param [in] Generator Pointer to the PPTT Generator.\r
974 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
975 Protocol Interface.\r
976 @param [in] Pptt Pointer to PPTT table structure.\r
977 @param [in] NodesStartOffset Offset from the start of PPTT table to the\r
978 start of ID Type Structures.\r
979\r
980 @retval EFI_SUCCESS Structures updated successfully.\r
981 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
982 @retval EFI_NOT_FOUND A required object was not found.\r
983**/\r
984STATIC\r
985EFI_STATUS\r
986AddIdTypeStructures (\r
987 IN CONST ACPI_PPTT_GENERATOR * CONST Generator,\r
988 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
989 IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER * Pptt,\r
990 IN CONST UINT32 NodesStartOffset\r
991 )\r
992{\r
993 EFI_ACPI_6_3_PPTT_STRUCTURE_ID * IdStruct;\r
994 CM_ARM_PROC_NODE_ID_INFO * ProcIdInfoNode;\r
995 PPTT_NODE_INDEXER * IdStructIterator;\r
996 UINT32 NodeCount;\r
997\r
998\r
999 ASSERT (\r
1000 (Generator != NULL) &&\r
1001 (CfgMgrProtocol != NULL) &&\r
1002 (Pptt != NULL)\r
1003 );\r
1004\r
1005 IdStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_ID*)((UINT8*)Pptt + NodesStartOffset);\r
1006\r
1007 IdStructIterator = Generator->IdStructIndexedList;\r
1008 NodeCount = Generator->IdStructCount;\r
1009 while (NodeCount-- != 0) {\r
1010 ProcIdInfoNode = (CM_ARM_PROC_NODE_ID_INFO*)IdStructIterator->Object;\r
1011\r
1012 // Populate the node\r
1013 IdStruct->Type = EFI_ACPI_6_3_PPTT_TYPE_ID;\r
1014 IdStruct->Length = sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_ID);\r
1015 IdStruct->Reserved[0] = EFI_ACPI_RESERVED_BYTE;\r
1016 IdStruct->Reserved[1] = EFI_ACPI_RESERVED_BYTE;\r
1017 IdStruct->VendorId = ProcIdInfoNode->VendorId;\r
1018 IdStruct->Level1Id = ProcIdInfoNode->Level1Id;\r
1019 IdStruct->Level2Id = ProcIdInfoNode->Level2Id;\r
1020 IdStruct->MajorRev = ProcIdInfoNode->MajorRev;\r
1021 IdStruct->MinorRev = ProcIdInfoNode->MinorRev;\r
1022 IdStruct->SpinRev = ProcIdInfoNode->SpinRev;\r
1023\r
1024 // Next ID Type Structure\r
1025 IdStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_ID*)((UINT8*)IdStruct +\r
1026 IdStruct->Length);\r
1027 IdStructIterator++;\r
1028 } // ID Type Structure\r
1029\r
1030 return EFI_SUCCESS;\r
1031}\r
1032\r
1033/**\r
1034 Construct the PPTT ACPI table.\r
1035\r
1036 This function invokes the Configuration Manager protocol interface\r
1037 to get the required hardware information for generating the ACPI\r
1038 table.\r
1039\r
1040 If this function allocates any resources then they must be freed\r
1041 in the FreeXXXXTableResources function.\r
1042\r
1043 @param [in] This Pointer to the table generator.\r
1044 @param [in] AcpiTableInfo Pointer to the ACPI table generator to be used.\r
1045 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1046 Protocol Interface.\r
1047 @param [out] Table Pointer to the constructed ACPI Table.\r
1048\r
1049 @retval EFI_SUCCESS Table generated successfully.\r
1050 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1051 @retval EFI_NOT_FOUND The required object was not found.\r
1052 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration\r
1053 Manager is less than the Object size for\r
1054 the requested object.\r
1055**/\r
1056STATIC\r
1057EFI_STATUS\r
1058EFIAPI\r
1059BuildPpttTable (\r
1060 IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
1061 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
1062 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
1063 OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table\r
1064 )\r
1065{\r
1066 EFI_STATUS Status;\r
1067 UINT32 TableSize;\r
1068 UINT32 ProcTopologyStructCount;\r
d39271f1
SM
1069 UINT32 ProcHierarchyNodeCount;\r
1070 UINT32 CacheStructCount;\r
1071 UINT32 IdStructCount;\r
77db1156
KK
1072\r
1073 UINT32 ProcHierarchyNodeOffset;\r
1074 UINT32 CacheStructOffset;\r
1075 UINT32 IdStructOffset;\r
1076\r
1077 CM_ARM_PROC_HIERARCHY_INFO * ProcHierarchyNodeList;\r
1078 CM_ARM_CACHE_INFO * CacheStructList;\r
1079 CM_ARM_PROC_NODE_ID_INFO * IdStructList;\r
1080\r
1081 ACPI_PPTT_GENERATOR * Generator;\r
1082\r
1083 // Pointer to the Node Indexer array\r
1084 PPTT_NODE_INDEXER * NodeIndexer;\r
1085\r
1086 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER * Pptt;\r
1087\r
1088 ASSERT (\r
1089 (This != NULL) &&\r
1090 (AcpiTableInfo != NULL) &&\r
1091 (CfgMgrProtocol != NULL) &&\r
1092 (Table != NULL) &&\r
1093 (AcpiTableInfo->TableGeneratorId == This->GeneratorID) &&\r
1094 (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature)\r
1095 );\r
1096\r
1097 if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||\r
1098 (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {\r
1099 DEBUG ((\r
1100 DEBUG_ERROR,\r
1101 "ERROR: PPTT: Requested table revision = %d is not supported. "\r
1102 "Supported table revisions: Minimum = %d. Maximum = %d\n",\r
1103 AcpiTableInfo->AcpiTableRevision,\r
1104 This->MinAcpiTableRevision,\r
1105 This->AcpiTableRevision\r
1106 ));\r
1107 return EFI_INVALID_PARAMETER;\r
1108 }\r
1109\r
1110 Generator = (ACPI_PPTT_GENERATOR*)This;\r
1111 *Table = NULL;\r
1112\r
1113 // Get the processor hierarchy info and update the processor topology\r
1114 // structure count with Processor Hierarchy Nodes (Type 0)\r
1115 Status = GetEArmObjProcHierarchyInfo (\r
1116 CfgMgrProtocol,\r
1117 CM_NULL_TOKEN,\r
1118 &ProcHierarchyNodeList,\r
d39271f1 1119 &ProcHierarchyNodeCount\r
77db1156
KK
1120 );\r
1121 if (EFI_ERROR (Status)) {\r
1122 DEBUG ((\r
1123 DEBUG_ERROR,\r
1124 "ERROR: PPTT: Failed to get processor hierarchy info. Status = %r\n",\r
1125 Status\r
1126 ));\r
1127 goto error_handler;\r
1128 }\r
1129\r
d39271f1
SM
1130 ProcTopologyStructCount = ProcHierarchyNodeCount;\r
1131 Generator->ProcHierarchyNodeCount = ProcHierarchyNodeCount;\r
77db1156
KK
1132\r
1133 // Get the cache info and update the processor topology structure count with\r
1134 // Cache Type Structures (Type 1)\r
1135 Status = GetEArmObjCacheInfo (\r
1136 CfgMgrProtocol,\r
1137 CM_NULL_TOKEN,\r
1138 &CacheStructList,\r
d39271f1 1139 &CacheStructCount\r
77db1156
KK
1140 );\r
1141 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1142 DEBUG ((\r
1143 DEBUG_ERROR,\r
1144 "ERROR: PPTT: Failed to get cache info. Status = %r\n",\r
1145 Status\r
1146 ));\r
1147 goto error_handler;\r
1148 }\r
1149\r
d39271f1
SM
1150 ProcTopologyStructCount += CacheStructCount;\r
1151 Generator->CacheStructCount = CacheStructCount;\r
77db1156
KK
1152\r
1153 // Get the processor hierarchy node ID info and update the processor topology\r
1154 // structure count with ID Structures (Type 2)\r
1155 Status = GetEArmObjProcNodeIdInfo (\r
1156 CfgMgrProtocol,\r
1157 CM_NULL_TOKEN,\r
1158 &IdStructList,\r
d39271f1 1159 &IdStructCount\r
77db1156
KK
1160 );\r
1161 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1162 DEBUG ((\r
1163 DEBUG_ERROR,\r
1164 "ERROR: PPTT: Failed to get processor hierarchy node ID info. " \\r
1165 "Status = %r\n",\r
1166 Status\r
1167 ));\r
1168 goto error_handler;\r
1169 }\r
1170\r
d39271f1
SM
1171 ProcTopologyStructCount += IdStructCount;\r
1172 Generator->IdStructCount = IdStructCount;\r
77db1156
KK
1173\r
1174 // Allocate Node Indexer array\r
1175 NodeIndexer = (PPTT_NODE_INDEXER*)AllocateZeroPool (\r
1176 sizeof (PPTT_NODE_INDEXER) *\r
1177 ProcTopologyStructCount\r
1178 );\r
1179 if (NodeIndexer == NULL) {\r
1180 Status = EFI_OUT_OF_RESOURCES;\r
1181 DEBUG ((\r
1182 DEBUG_ERROR,\r
1183 "ERROR: PPTT: Failed to allocate memory for Node Indexer. Status = %r\n ",\r
1184 Status\r
1185 ));\r
1186 goto error_handler;\r
1187 }\r
1188\r
1189 DEBUG ((DEBUG_INFO, "INFO: NodeIndexer = %p\n", NodeIndexer));\r
1190 Generator->ProcTopologyStructCount = ProcTopologyStructCount;\r
1191 Generator->NodeIndexer = NodeIndexer;\r
1192\r
1193 // Calculate the size of the PPTT table\r
1194 TableSize = sizeof (EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER);\r
1195\r
1196 // Include the size of Processor Hierarchy Nodes and index them\r
1197 if (Generator->ProcHierarchyNodeCount != 0) {\r
1198 ProcHierarchyNodeOffset = TableSize;\r
1199 Generator->ProcHierarchyNodeIndexedList = NodeIndexer;\r
1200 TableSize += GetSizeofProcHierarchyNodes (\r
1201 ProcHierarchyNodeOffset,\r
1202 ProcHierarchyNodeList,\r
1203 Generator->ProcHierarchyNodeCount,\r
1204 &NodeIndexer\r
1205 );\r
4d23a7ec
SM
1206\r
1207 DEBUG ((\r
1208 DEBUG_INFO,\r
1209 " ProcHierarchyNodeCount = %d\n" \\r
1210 " ProcHierarchyNodeOffset = 0x%x\n" \\r
1211 " ProcHierarchyNodeIndexedList = 0x%p\n",\r
1212 Generator->ProcHierarchyNodeCount,\r
1213 ProcHierarchyNodeOffset,\r
1214 Generator->ProcHierarchyNodeIndexedList\r
1215 ));\r
1216\r
77db1156
KK
1217 }\r
1218\r
1219 // Include the size of Cache Type Structures and index them\r
1220 if (Generator->CacheStructCount != 0) {\r
1221 CacheStructOffset = TableSize;\r
1222 Generator->CacheStructIndexedList = NodeIndexer;\r
1223 TableSize += GetSizeofCacheTypeStructs (\r
1224 CacheStructOffset,\r
1225 CacheStructList,\r
1226 Generator->CacheStructCount,\r
1227 &NodeIndexer\r
1228 );\r
4d23a7ec
SM
1229 DEBUG ((\r
1230 DEBUG_INFO,\r
1231 " CacheStructCount = %d\n" \\r
1232 " CacheStructOffset = 0x%x\n" \\r
1233 " CacheStructIndexedList = 0x%p\n",\r
1234 Generator->CacheStructCount,\r
1235 CacheStructOffset,\r
1236 Generator->CacheStructIndexedList\r
1237 ));\r
77db1156
KK
1238 }\r
1239\r
1240 // Include the size of ID Type Structures and index them\r
1241 if (Generator->IdStructCount != 0) {\r
1242 IdStructOffset = TableSize;\r
1243 Generator->IdStructIndexedList = NodeIndexer;\r
1244 TableSize += GetSizeofIdStructs (\r
1245 IdStructOffset,\r
1246 IdStructList,\r
1247 Generator->IdStructCount,\r
1248 &NodeIndexer\r
1249 );\r
4d23a7ec
SM
1250 DEBUG ((\r
1251 DEBUG_INFO,\r
1252 " IdStructCount = %d\n" \\r
1253 " IdStructOffset = 0x%x\n" \\r
1254 " IdStructIndexedList = 0x%p\n",\r
1255 Generator->IdStructCount,\r
1256 IdStructOffset,\r
1257 Generator->IdStructIndexedList\r
1258 ));\r
77db1156
KK
1259 }\r
1260\r
1261 DEBUG ((\r
1262 DEBUG_INFO,\r
1263 "INFO: PPTT:\n" \\r
1264 " ProcTopologyStructCount = %d\n" \\r
1265 " TableSize = %d\n",\r
1266 ProcTopologyStructCount,\r
1267 TableSize\r
1268 ));\r
1269\r
77db1156
KK
1270 // Allocate the Buffer for the PPTT table\r
1271 *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);\r
1272 if (*Table == NULL) {\r
1273 Status = EFI_OUT_OF_RESOURCES;\r
1274 DEBUG ((\r
1275 DEBUG_ERROR,\r
1276 "ERROR: PPTT: Failed to allocate memory for PPTT Table. " \\r
1277 "Size = %d. Status = %r\n",\r
1278 TableSize,\r
1279 Status\r
1280 ));\r
1281 goto error_handler;\r
1282 }\r
1283\r
1284 Pptt = (EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER*)*Table;\r
1285\r
1286 DEBUG ((\r
1287 DEBUG_INFO,\r
1288 "PPTT: Pptt = 0x%p. TableSize = 0x%x\n",\r
1289 Pptt,\r
1290 TableSize\r
1291 ));\r
1292\r
1293 // Add ACPI header\r
1294 Status = AddAcpiHeader (\r
1295 CfgMgrProtocol,\r
1296 This,\r
1297 &Pptt->Header,\r
1298 AcpiTableInfo,\r
1299 TableSize\r
1300 );\r
1301 if (EFI_ERROR (Status)) {\r
1302 DEBUG ((\r
1303 DEBUG_ERROR,\r
1304 "ERROR: PPTT: Failed to add ACPI header. Status = %r\n",\r
1305 Status\r
1306 ));\r
1307 goto error_handler;\r
1308 }\r
1309\r
1310 // Add Processor Hierarchy Nodes (Type 0) to the generated table\r
1311 if (Generator->ProcHierarchyNodeCount != 0) {\r
1312 Status = AddProcHierarchyNodes (\r
1313 Generator,\r
1314 CfgMgrProtocol,\r
1315 Pptt,\r
1316 ProcHierarchyNodeOffset\r
1317 );\r
1318 if (EFI_ERROR (Status)) {\r
1319 DEBUG ((\r
1320 DEBUG_ERROR,\r
1321 "ERROR: PPTT: Failed to add Processor Hierarchy Nodes. Status = %r\n",\r
1322 Status\r
1323 ));\r
1324 goto error_handler;\r
1325 }\r
1326 }\r
1327\r
1328 // Add Cache Type Structures (Type 1) to the generated table\r
1329 if (Generator->CacheStructCount != 0) {\r
1330 Status = AddCacheTypeStructures (\r
1331 Generator,\r
1332 CfgMgrProtocol,\r
1333 Pptt,\r
1334 CacheStructOffset\r
1335 );\r
1336 if (EFI_ERROR (Status)) {\r
1337 DEBUG ((\r
1338 DEBUG_ERROR,\r
1339 "ERROR: PPTT: Failed to add Cache Type Structures. Status = %r\n",\r
1340 Status\r
1341 ));\r
1342 goto error_handler;\r
1343 }\r
1344 }\r
1345\r
1346 // Add ID Type Structures (Type 2) to the generated table\r
1347 if (Generator->IdStructCount != 0) {\r
1348 Status = AddIdTypeStructures (\r
1349 Generator,\r
1350 CfgMgrProtocol,\r
1351 Pptt,\r
1352 IdStructOffset\r
1353 );\r
1354 if (EFI_ERROR (Status)) {\r
1355 DEBUG ((\r
1356 DEBUG_ERROR,\r
1357 "ERROR: PPTT: Failed to add ID Type Structures. Status = %r\n",\r
1358 Status\r
1359 ));\r
1360 goto error_handler;\r
1361 }\r
1362 }\r
1363\r
1364 // Validate CM object cross-references in PPTT\r
1365 Status = DetectCyclesInTopology (Generator);\r
1366 if (EFI_ERROR (Status)) {\r
1367 DEBUG ((\r
1368 DEBUG_ERROR,\r
1369 "ERROR: PPTT: Invalid processor and cache topology. Status = %r\n",\r
1370 Status\r
1371 ));\r
1372 goto error_handler;\r
1373 }\r
1374\r
1375 return Status;\r
1376\r
1377error_handler:\r
1378 if (Generator->NodeIndexer != NULL) {\r
1379 FreePool (Generator->NodeIndexer);\r
1380 Generator->NodeIndexer = NULL;\r
1381 }\r
1382\r
1383 if (*Table != NULL) {\r
1384 FreePool (*Table);\r
1385 *Table = NULL;\r
1386 }\r
1387\r
1388 return Status;\r
1389}\r
1390\r
1391/**\r
1392 Free any resources allocated for constructing the PPTT\r
1393\r
1394 @param [in] This Pointer to the table generator.\r
1395 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
1396 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1397 Protocol Interface.\r
1398 @param [in, out] Table Pointer to the ACPI Table.\r
1399\r
1400 @retval EFI_SUCCESS The resources were freed successfully.\r
1401 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.\r
1402**/\r
1403STATIC\r
1404EFI_STATUS\r
1405FreePpttTableResources (\r
1406 IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
1407 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
1408 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
1409 IN OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table\r
1410 )\r
1411{\r
1412 ACPI_PPTT_GENERATOR * Generator;\r
1413\r
1414 ASSERT (\r
1415 (This != NULL) &&\r
1416 (AcpiTableInfo != NULL) &&\r
1417 (CfgMgrProtocol != NULL) &&\r
1418 (AcpiTableInfo->TableGeneratorId == This->GeneratorID) &&\r
1419 (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature)\r
1420 );\r
1421\r
1422 Generator = (ACPI_PPTT_GENERATOR*)This;\r
1423\r
1424 // Free any memory allocated by the generator\r
1425 if (Generator->NodeIndexer != NULL) {\r
1426 FreePool (Generator->NodeIndexer);\r
1427 Generator->NodeIndexer = NULL;\r
1428 }\r
1429\r
1430 if ((Table == NULL) || (*Table == NULL)) {\r
1431 DEBUG ((DEBUG_ERROR, "ERROR: PPTT: Invalid Table Pointer\n"));\r
1432 ASSERT (\r
1433 (Table != NULL) &&\r
1434 (*Table != NULL)\r
1435 );\r
1436 return EFI_INVALID_PARAMETER;\r
1437 }\r
1438\r
1439 FreePool (*Table);\r
1440 *Table = NULL;\r
1441 return EFI_SUCCESS;\r
1442}\r
1443\r
1444/** The PPTT Table Generator revision.\r
1445*/\r
1446#define PPTT_GENERATOR_REVISION CREATE_REVISION (1, 0)\r
1447\r
1448/** The interface for the PPTT Table Generator.\r
1449*/\r
1450STATIC\r
1451ACPI_PPTT_GENERATOR PpttGenerator = {\r
1452 // ACPI table generator header\r
1453 {\r
1454 // Generator ID\r
1455 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdPptt),\r
1456 // Generator Description\r
1457 L"ACPI.STD.PPTT.GENERATOR",\r
1458 // ACPI Table Signature\r
1459 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE,\r
1460 // ACPI Table Revision supported by this Generator\r
1461 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION,\r
1462 // Minimum supported ACPI Table Revision\r
1463 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION,\r
1464 // Creator ID\r
1465 TABLE_GENERATOR_CREATOR_ID_ARM,\r
1466 // Creator Revision\r
1467 PPTT_GENERATOR_REVISION,\r
1468 // Build Table function\r
1469 BuildPpttTable,\r
1470 // Free Resource function\r
1471 FreePpttTableResources,\r
1472 // Extended build function not needed\r
1473 NULL,\r
1474 // Extended build function not implemented by the generator.\r
1475 // Hence extended free resource function is not required.\r
1476 NULL\r
1477 },\r
1478\r
1479 // PPTT Generator private data\r
1480\r
1481 // Processor topology node count\r
1482 0,\r
d39271f1
SM
1483 // Count of Processor Hierarchy Nodes\r
1484 0,\r
1485 // Count of Cache Structures\r
1486 0,\r
1487 // Count of Id Structures\r
1488 0,\r
77db1156
KK
1489 // Pointer to PPTT Node Indexer\r
1490 NULL\r
1491};\r
1492\r
1493/**\r
1494 Register the Generator with the ACPI Table Factory.\r
1495\r
1496 @param [in] ImageHandle The handle to the image.\r
1497 @param [in] SystemTable Pointer to the System Table.\r
1498\r
1499 @retval EFI_SUCCESS The Generator is registered.\r
1500 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1501 @retval EFI_ALREADY_STARTED The Generator for the Table ID\r
1502 is already registered.\r
1503**/\r
1504EFI_STATUS\r
1505EFIAPI\r
1506AcpiPpttLibConstructor (\r
43a0e08d
SM
1507 IN EFI_HANDLE ImageHandle,\r
1508 IN EFI_SYSTEM_TABLE * SystemTable\r
77db1156
KK
1509 )\r
1510{\r
1511 EFI_STATUS Status;\r
1512 Status = RegisterAcpiTableGenerator (&PpttGenerator.Header);\r
1513 DEBUG ((DEBUG_INFO, "PPTT: Register Generator. Status = %r\n", Status));\r
1514 ASSERT_EFI_ERROR (Status);\r
1515 return Status;\r
1516}\r
1517\r
1518/**\r
1519 Deregister the Generator from the ACPI Table Factory.\r
1520\r
1521 @param [in] ImageHandle The handle to the image.\r
1522 @param [in] SystemTable Pointer to the System Table.\r
1523\r
1524 @retval EFI_SUCCESS The Generator is deregistered.\r
1525 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1526 @retval EFI_NOT_FOUND The Generator is not registered.\r
1527**/\r
1528EFI_STATUS\r
1529EFIAPI\r
1530AcpiPpttLibDestructor (\r
43a0e08d
SM
1531 IN EFI_HANDLE ImageHandle,\r
1532 IN EFI_SYSTEM_TABLE * SystemTable\r
77db1156
KK
1533 )\r
1534{\r
1535 EFI_STATUS Status;\r
1536 Status = DeregisterAcpiTableGenerator (&PpttGenerator.Header);\r
1537 DEBUG ((DEBUG_INFO, "PPTT: Deregister Generator. Status = %r\n", Status));\r
1538 ASSERT_EFI_ERROR (Status);\r
1539 return Status;\r
1540}\r