]> git.proxmox.com Git - mirror_edk2.git/blame - DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.c
DynamicTablesPkg: Fix entry point param definition
[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
507\r
508 ASSERT (\r
509 (Generator != NULL) &&\r
510 (CfgMgrProtocol != NULL) &&\r
511 (Pptt != NULL)\r
512 );\r
513\r
514 ProcStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR*)((UINT8*)Pptt +\r
515 NodesStartOffset);\r
516\r
517 ProcNodeIterator = Generator->ProcHierarchyNodeIndexedList;\r
518 NodeCount = Generator->ProcHierarchyNodeCount;\r
519\r
520 // Check if every GICC Object is referenced by onlu one Proc Node\r
521 IsGicCTokenDuplicated = FindDuplicateValue (\r
522 ProcNodeIterator,\r
523 NodeCount,\r
524 sizeof (PPTT_NODE_INDEXER),\r
525 IsGicCTokenEqual\r
526 );\r
527 // Duplicate GIC CPU Interface Token was found so two PPTT Processor Hierarchy\r
528 // Nodes map to the same MADT GICC structure\r
529 if (IsGicCTokenDuplicated) {\r
530 return EFI_INVALID_PARAMETER;\r
531 }\r
532\r
533 UniqueGicCRefCount = 0;\r
534\r
535 while (NodeCount-- != 0) {\r
536 ProcInfoNode = (CM_ARM_PROC_HIERARCHY_INFO*)ProcNodeIterator->Object;\r
537\r
538 // Check if the private resource count is within the size limit\r
539 // imposed on the Processor Hierarchy node by the specification.\r
540 // Note: The length field is 8 bit wide while the number of private\r
541 // resource field is 32 bit wide.\r
542 if ((sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR) +\r
543 (ProcInfoNode->NoOfPrivateResources * sizeof (UINT32))) > MAX_UINT8) {\r
544 Status = EFI_INVALID_PARAMETER;\r
545 DEBUG ((\r
546 DEBUG_ERROR,\r
547 "ERROR: PPTT: Too many private resources. Count = %d. " \\r
548 "Maximum supported Processor Node size exceeded. " \\r
549 "Token = %p. Status = %r\n",\r
550 ProcInfoNode->NoOfPrivateResources,\r
551 ProcInfoNode->ParentToken,\r
552 Status\r
553 ));\r
554 return Status;\r
555 }\r
556\r
557 // Populate the node header\r
558 ProcStruct->Type = EFI_ACPI_6_3_PPTT_TYPE_PROCESSOR;\r
559 ProcStruct->Length = GetProcHierarchyNodeSize (ProcInfoNode);\r
560 ProcStruct->Reserved[0] = EFI_ACPI_RESERVED_BYTE;\r
561 ProcStruct->Reserved[1] = EFI_ACPI_RESERVED_BYTE;\r
562\r
563 // Populate the flags\r
564 ProcStruct->Flags.PhysicalPackage = ProcInfoNode->Flags & BIT0;\r
565 ProcStruct->Flags.AcpiProcessorIdValid = (ProcInfoNode->Flags & BIT1) >> 1;\r
566 ProcStruct->Flags.ProcessorIsAThread = (ProcInfoNode->Flags & BIT2) >> 2;\r
567 ProcStruct->Flags.NodeIsALeaf = (ProcInfoNode->Flags & BIT3) >> 3;\r
568 ProcStruct->Flags.IdenticalImplementation =\r
569 (ProcInfoNode->Flags & BIT4) >> 4;\r
570 ProcStruct->Flags.Reserved = 0;\r
571\r
572 // Populate the parent reference\r
573 if (ProcInfoNode->ParentToken == CM_NULL_TOKEN) {\r
574 ProcStruct->Parent = 0;\r
575 } else {\r
576 Status = GetPpttNodeReferencedByToken (\r
577 Generator->ProcHierarchyNodeIndexedList,\r
578 Generator->ProcHierarchyNodeCount,\r
579 ProcInfoNode->ParentToken,\r
580 &PpttNodeFound\r
581 );\r
582 if (EFI_ERROR (Status)) {\r
583 DEBUG ((\r
584 DEBUG_ERROR,\r
585 "ERROR: PPTT: Failed to get parent processor hierarchy node " \\r
586 "reference. Token = %p, Status = %r\n",\r
587 ProcInfoNode->ParentToken,\r
588 ProcInfoNode->Token,\r
589 Status\r
590 ));\r
591 return Status;\r
592 }\r
593\r
594 // Test if the reference is to a 'leaf' node\r
595 if (IS_PROC_NODE_LEAF (\r
596 ((CM_ARM_PROC_HIERARCHY_INFO*)PpttNodeFound->Object))) {\r
597 Status = EFI_INVALID_PARAMETER;\r
598 DEBUG ((\r
599 DEBUG_ERROR,\r
600 "ERROR: PPTT: Reference to a leaf Processor Hierarchy Node. " \\r
601 "ParentToken = %p. ChildToken = %p. Status = %r\n",\r
602 ProcInfoNode->ParentToken,\r
603 ProcInfoNode->Token,\r
604 Status\r
605 ));\r
606 return Status;\r
607 }\r
608\r
609 // Update Proc Structure with the offset of the parent node\r
610 ProcStruct->Parent = PpttNodeFound->Offset;\r
611\r
612 // Store the reference for the parent node in the Node Indexer\r
613 // so that this can be used later for cycle detection\r
614 ProcNodeIterator->TopologyParent = PpttNodeFound;\r
615 }\r
616\r
617 // Populate ACPI Processor ID\r
618 if (!IS_ACPI_PROC_ID_VALID (ProcInfoNode)) {\r
619 // Default invalid ACPI Processor ID to 0\r
620 ProcStruct->AcpiProcessorId = 0;\r
621 } else if (ProcInfoNode->GicCToken == CM_NULL_TOKEN) {\r
622 Status = EFI_INVALID_PARAMETER;\r
623 DEBUG ((\r
624 DEBUG_ERROR,\r
625 "ERROR: PPTT: The 'ACPI Processor ID valid' flag is set but no GICC " \\r
626 "structure token was provided. GicCToken = %p. RequestorToken = %p. " \\r
627 "Status = %r\n",\r
628 ProcInfoNode->GicCToken,\r
629 ProcInfoNode->Token,\r
630 Status\r
631 ));\r
632 return Status;\r
633 } else {\r
634 Status = GetEArmObjGicCInfo (\r
635 CfgMgrProtocol,\r
636 ProcInfoNode->GicCToken,\r
637 &GicCInfoList,\r
638 &GicCInfoCount\r
639 );\r
640 if (EFI_ERROR (Status)) {\r
641 DEBUG ((\r
642 DEBUG_ERROR,\r
643 "ERROR: PPTT: Failed to get GICC structure. ACPI Processor ID " \\r
644 "can't be populated. GicCToken = %p. RequestorToken = %p. " \\r
645 "Status = %r\n",\r
646 ProcInfoNode->GicCToken,\r
647 ProcInfoNode->Token,\r
648 Status\r
649 ));\r
650 return Status;\r
651 }\r
652\r
653 if (GicCInfoCount != 1) {\r
654 Status = EFI_INVALID_PARAMETER;\r
655 DEBUG ((\r
656 DEBUG_ERROR,\r
657 "ERROR: PPTT: Failed to find a unique GICC structure. " \\r
658 "ACPI Processor ID can't be populated. " \\r
659 "GICC Structure Count = %d. GicCToken = %p. RequestorToken = %p " \\r
660 "Status = %r\n",\r
661 GicCInfoCount,\r
662 ProcInfoNode->GicCToken,\r
663 ProcInfoNode->Token,\r
664 Status\r
665 ));\r
666 return Status;\r
667 }\r
668\r
669 // Update the ACPI Processor Id\r
670 ProcStruct->AcpiProcessorId = GicCInfoList->AcpiProcessorUid;\r
671\r
672 // Increment the reference count for the number of\r
673 // Unique GICC objects that were retrieved.\r
674 UniqueGicCRefCount++;\r
675 }\r
676\r
677 ProcStruct->NumberOfPrivateResources = ProcInfoNode->NoOfPrivateResources;\r
678 PrivateResources = (UINT32*)((UINT8*)ProcStruct +\r
679 sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR));\r
680\r
681 if (ProcStruct->NumberOfPrivateResources != 0) {\r
682 // Populate the private resources array\r
683 Status = AddPrivateResources (\r
684 Generator,\r
685 CfgMgrProtocol,\r
686 PrivateResources,\r
687 ProcStruct->NumberOfPrivateResources,\r
688 ProcInfoNode->PrivateResourcesArrayToken\r
689 );\r
690 if (EFI_ERROR (Status)) {\r
691 DEBUG ((\r
692 DEBUG_ERROR,\r
693 "ERROR: PPTT: Failed to populate the private resources array. " \\r
694 "Status = %r\n",\r
695 Status\r
696 ));\r
697 return Status;\r
698 }\r
699 }\r
700\r
701 // Next Processor Hierarchy Node\r
702 ProcStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR*)((UINT8*)ProcStruct +\r
703 ProcStruct->Length);\r
704 ProcNodeIterator++;\r
705 } // Processor Hierarchy Node\r
706\r
707 // Knowing the total number of GICC references made and that all GICC Token\r
708 // references are unique, we can test if no GICC instances have been left out.\r
709 Status = GetEArmObjGicCInfo (\r
710 CfgMgrProtocol,\r
711 CM_NULL_TOKEN,\r
712 &GicCInfoList,\r
713 &GicCInfoCount\r
714 );\r
715 if (EFI_ERROR (Status)) {\r
716 DEBUG ((\r
717 DEBUG_ERROR,\r
718 "ERROR: PPTT: Failed to get GICC Info. Status = %r\n",\r
719 Status\r
720 ));\r
721 return Status;\r
722 }\r
723\r
724 // MADT - PPTT cross validation\r
725 // This checks that one and only one GICC structure is referenced by a\r
726 // Processor Hierarchy Node in the PPTT.\r
727 // Since we have already checked that the GICC objects referenced by the\r
728 // Proc Nodes are unique, the UniqueGicCRefCount cannot be greater than\r
729 // the total number of GICC objects in the platform.\r
730 if (GicCInfoCount > UniqueGicCRefCount) {\r
731 Status = EFI_INVALID_PARAMETER;\r
732 DEBUG ((\r
733 DEBUG_ERROR,\r
734 "ERROR: PPTT: %d GICC structure(s) exposed by MADT don't have " \\r
735 "a corresponding Processor Hierarchy Node. Status = %r\n",\r
736 GicCInfoCount - UniqueGicCRefCount,\r
737 Status\r
738 ));\r
739 }\r
740\r
741 return Status;\r
742}\r
743\r
744/**\r
745 Update the Cache Type Structure (Type 1) information.\r
746\r
747 This function populates the Cache Type Structures with information from\r
748 the Configuration Manager and adds this information to the PPTT table.\r
749\r
750 @param [in] Generator Pointer to the PPTT Generator.\r
751 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
752 Protocol Interface.\r
753 @param [in] Pptt Pointer to PPTT table structure.\r
754 @param [in] NodesStartOffset Offset from the start of PPTT table to the\r
755 start of Cache Type Structures.\r
756\r
757 @retval EFI_SUCCESS Structures updated successfully.\r
758 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
759 @retval EFI_NOT_FOUND A required object was not found.\r
760**/\r
761STATIC\r
762EFI_STATUS\r
763AddCacheTypeStructures (\r
764 IN CONST ACPI_PPTT_GENERATOR * CONST Generator,\r
765 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
766 IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER * Pptt,\r
767 IN CONST UINT32 NodesStartOffset\r
768 )\r
769{\r
770 EFI_STATUS Status;\r
771 EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE * CacheStruct;\r
772 PPTT_NODE_INDEXER * PpttNodeFound;\r
773 CM_ARM_CACHE_INFO * CacheInfoNode;\r
774 PPTT_NODE_INDEXER * CacheNodeIterator;\r
775 UINT32 NodeCount;\r
776\r
777 ASSERT (\r
778 (Generator != NULL) &&\r
779 (CfgMgrProtocol != NULL) &&\r
780 (Pptt != NULL)\r
781 );\r
782\r
783 CacheStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE*)((UINT8*)Pptt +\r
784 NodesStartOffset);\r
785\r
786 CacheNodeIterator = Generator->CacheStructIndexedList;\r
787 NodeCount = Generator->CacheStructCount;\r
788\r
789 while (NodeCount-- != 0) {\r
790 CacheInfoNode = (CM_ARM_CACHE_INFO*)CacheNodeIterator->Object;\r
791\r
792 // Populate the node header\r
793 CacheStruct->Type = EFI_ACPI_6_3_PPTT_TYPE_CACHE;\r
794 CacheStruct->Length = sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE);\r
795 CacheStruct->Reserved[0] = EFI_ACPI_RESERVED_BYTE;\r
796 CacheStruct->Reserved[1] = EFI_ACPI_RESERVED_BYTE;\r
797\r
798 // "On Arm-based systems, all cache properties must be provided in the\r
799 // table." (ACPI 6.3, Section 5.2.29.2)\r
800 CacheStruct->Flags.SizePropertyValid = 1;\r
801 CacheStruct->Flags.NumberOfSetsValid = 1;\r
802 CacheStruct->Flags.AssociativityValid = 1;\r
803 CacheStruct->Flags.AllocationTypeValid = 1;\r
804 CacheStruct->Flags.CacheTypeValid = 1;\r
805 CacheStruct->Flags.WritePolicyValid = 1;\r
806 CacheStruct->Flags.LineSizeValid = 1;\r
807 CacheStruct->Flags.Reserved = 0;\r
808\r
809 // Populate the reference to the next level of cache\r
810 if (CacheInfoNode->NextLevelOfCacheToken == CM_NULL_TOKEN) {\r
811 CacheStruct->NextLevelOfCache = 0;\r
812 } else {\r
813 Status = GetPpttNodeReferencedByToken (\r
814 Generator->CacheStructIndexedList,\r
815 Generator->CacheStructCount,\r
816 CacheInfoNode->NextLevelOfCacheToken,\r
817 &PpttNodeFound\r
818 );\r
819 if (EFI_ERROR (Status)) {\r
820 DEBUG ((\r
821 DEBUG_ERROR,\r
822 "ERROR: PPTT: Failed to get the reference to the Next Level of " \\r
823 "Cache. NextLevelOfCacheToken = %p. RequestorToken = %p. " \\r
824 "Status = %r\n",\r
825 CacheInfoNode->NextLevelOfCacheToken,\r
826 CacheInfoNode->Token,\r
827 Status\r
828 ));\r
829 return Status;\r
830 }\r
831\r
832 // Update Cache Structure with the offset for the next level of cache\r
833 CacheStruct->NextLevelOfCache = PpttNodeFound->Offset;\r
834\r
835 // Store the next level of cache information in the Node Indexer\r
836 // so that this can be used later for cycle detection\r
837 CacheNodeIterator->TopologyParent = PpttNodeFound;\r
838 }\r
839\r
840 CacheStruct->Size = CacheInfoNode->Size;\r
841\r
842 // Validate and populate the 'Number of sets' field\r
843 if (CacheInfoNode->NumberOfSets > PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX) {\r
844 Status = EFI_INVALID_PARAMETER;\r
845 DEBUG ((\r
846 DEBUG_ERROR,\r
847 "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum number " \\r
848 "of sets can be %d. NumberOfSets = %d. Status = %r\n",\r
849 PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX,\r
850 CacheInfoNode->NumberOfSets,\r
851 Status\r
852 ));\r
853 return Status;\r
854 }\r
855\r
856 if (CacheInfoNode->NumberOfSets > PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX) {\r
857 DEBUG ((\r
858 DEBUG_INFO,\r
859 "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \\r
860 "number of sets can be %d. NumberOfSets = %d\n",\r
861 PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX,\r
862 CacheInfoNode->NumberOfSets\r
863 ));\r
864 }\r
865\r
866 CacheStruct->NumberOfSets = CacheInfoNode->NumberOfSets;\r
867\r
868 // Validate Associativity field based on maximum associativity\r
869 // supported by ACPI Cache type structure.\r
870 if (CacheInfoNode->Associativity > MAX_UINT8) {\r
871 Status = EFI_INVALID_PARAMETER;\r
872 DEBUG ((\r
873 DEBUG_ERROR,\r
874 "ERROR: PPTT: The maximum associativity supported by ACPI " \\r
875 "Cache type structure is %d. Associativity = %d, Status = %r\n",\r
876 MAX_UINT8,\r
877 CacheInfoNode->Associativity,\r
878 Status\r
879 ));\r
880 return Status;\r
881 }\r
882\r
883 // Validate the Associativity field based on the architecture specification\r
884 // The architecture supports much larger associativity values than the\r
885 // current ACPI specification.\r
886 // These checks will be needed in the future when the ACPI specification\r
887 // is extended. Disabling this code for now.\r
888#if 0\r
889 if (CacheInfoNode->Associativity > PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX) {\r
890 Status = EFI_INVALID_PARAMETER;\r
891 DEBUG ((\r
892 DEBUG_ERROR,\r
893 "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum cache " \\r
894 "associativity can be %d. Associativity = %d. Status = %r\n",\r
895 PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX,\r
896 CacheInfoNode->Associativity,\r
897 Status\r
898 ));\r
899 return Status;\r
900 }\r
901\r
902 if (CacheInfoNode->Associativity > PPTT_ARM_CACHE_ASSOCIATIVITY_MAX) {\r
903 DEBUG ((\r
904 DEBUG_INFO,\r
905 "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \\r
906 "cache associativity can be %d. Associativity = %d\n",\r
907 PPTT_ARM_CACHE_ASSOCIATIVITY_MAX,\r
908 CacheInfoNode->Associativity\r
909 ));\r
910 }\r
911#endif\r
912\r
913 // Note a typecast is needed as the maximum associativity\r
914 // supported by ACPI Cache type structure is MAX_UINT8.\r
915 CacheStruct->Associativity = (UINT8)CacheInfoNode->Associativity;\r
916\r
917 // Populate cache attributes\r
918 CacheStruct->Attributes.AllocationType =\r
919 CacheInfoNode->Attributes & (BIT0 | BIT1);\r
920 CacheStruct->Attributes.CacheType =\r
921 (CacheInfoNode->Attributes & (BIT2 | BIT3)) >> 2;\r
922 CacheStruct->Attributes.WritePolicy =\r
923 (CacheInfoNode->Attributes & BIT4) >> 4;\r
924 CacheStruct->Attributes.Reserved = 0;\r
925\r
926 // Validate and populate cache line size\r
927 if ((CacheInfoNode->LineSize < PPTT_ARM_CACHE_LINE_SIZE_MIN) ||\r
928 (CacheInfoNode->LineSize > PPTT_ARM_CACHE_LINE_SIZE_MAX)) {\r
929\r
930 Status = EFI_INVALID_PARAMETER;\r
931 DEBUG ((\r
932 DEBUG_ERROR,\r
933 "ERROR: PPTT: The cache line size must be between %d and %d bytes " \\r
934 "on ARM Platforms. LineSize = %d. Status = %r\n" ,\r
935 PPTT_ARM_CACHE_LINE_SIZE_MIN,\r
936 PPTT_ARM_CACHE_LINE_SIZE_MAX,\r
937 CacheInfoNode->LineSize,\r
938 Status\r
939 ));\r
940 return Status;\r
941 }\r
942\r
943 if ((CacheInfoNode->LineSize & (CacheInfoNode->LineSize - 1)) != 0) {\r
944 Status = EFI_INVALID_PARAMETER;\r
945 DEBUG ((\r
946 DEBUG_ERROR,\r
947 "ERROR: PPTT: The cache line size is not a power of 2. " \\r
948 "LineSize = %d. Status = %r\n" ,\r
949 CacheInfoNode->LineSize,\r
950 Status\r
951 ));\r
952 return Status;\r
953 }\r
954\r
955 CacheStruct->LineSize = CacheInfoNode->LineSize;\r
956\r
957 // Next Cache Type Structure\r
958 CacheStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE*)((UINT8*)CacheStruct +\r
959 CacheStruct->Length);\r
960 CacheNodeIterator++;\r
961 } // Cache Type Structure\r
962\r
963 return EFI_SUCCESS;\r
964}\r
965\r
966/**\r
967 Update the ID Type Structure (Type 2) information.\r
968\r
969 This function populates the ID Type Structures with information from\r
970 the Configuration Manager and and adds this information to the PPTT table.\r
971\r
972 @param [in] Generator Pointer to the PPTT Generator.\r
973 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
974 Protocol Interface.\r
975 @param [in] Pptt Pointer to PPTT table structure.\r
976 @param [in] NodesStartOffset Offset from the start of PPTT table to the\r
977 start of ID Type Structures.\r
978\r
979 @retval EFI_SUCCESS Structures updated successfully.\r
980 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
981 @retval EFI_NOT_FOUND A required object was not found.\r
982**/\r
983STATIC\r
984EFI_STATUS\r
985AddIdTypeStructures (\r
986 IN CONST ACPI_PPTT_GENERATOR * CONST Generator,\r
987 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
988 IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER * Pptt,\r
989 IN CONST UINT32 NodesStartOffset\r
990 )\r
991{\r
992 EFI_ACPI_6_3_PPTT_STRUCTURE_ID * IdStruct;\r
993 CM_ARM_PROC_NODE_ID_INFO * ProcIdInfoNode;\r
994 PPTT_NODE_INDEXER * IdStructIterator;\r
995 UINT32 NodeCount;\r
996\r
997\r
998 ASSERT (\r
999 (Generator != NULL) &&\r
1000 (CfgMgrProtocol != NULL) &&\r
1001 (Pptt != NULL)\r
1002 );\r
1003\r
1004 IdStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_ID*)((UINT8*)Pptt + NodesStartOffset);\r
1005\r
1006 IdStructIterator = Generator->IdStructIndexedList;\r
1007 NodeCount = Generator->IdStructCount;\r
1008 while (NodeCount-- != 0) {\r
1009 ProcIdInfoNode = (CM_ARM_PROC_NODE_ID_INFO*)IdStructIterator->Object;\r
1010\r
1011 // Populate the node\r
1012 IdStruct->Type = EFI_ACPI_6_3_PPTT_TYPE_ID;\r
1013 IdStruct->Length = sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_ID);\r
1014 IdStruct->Reserved[0] = EFI_ACPI_RESERVED_BYTE;\r
1015 IdStruct->Reserved[1] = EFI_ACPI_RESERVED_BYTE;\r
1016 IdStruct->VendorId = ProcIdInfoNode->VendorId;\r
1017 IdStruct->Level1Id = ProcIdInfoNode->Level1Id;\r
1018 IdStruct->Level2Id = ProcIdInfoNode->Level2Id;\r
1019 IdStruct->MajorRev = ProcIdInfoNode->MajorRev;\r
1020 IdStruct->MinorRev = ProcIdInfoNode->MinorRev;\r
1021 IdStruct->SpinRev = ProcIdInfoNode->SpinRev;\r
1022\r
1023 // Next ID Type Structure\r
1024 IdStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_ID*)((UINT8*)IdStruct +\r
1025 IdStruct->Length);\r
1026 IdStructIterator++;\r
1027 } // ID Type Structure\r
1028\r
1029 return EFI_SUCCESS;\r
1030}\r
1031\r
1032/**\r
1033 Construct the PPTT ACPI table.\r
1034\r
1035 This function invokes the Configuration Manager protocol interface\r
1036 to get the required hardware information for generating the ACPI\r
1037 table.\r
1038\r
1039 If this function allocates any resources then they must be freed\r
1040 in the FreeXXXXTableResources function.\r
1041\r
1042 @param [in] This Pointer to the table generator.\r
1043 @param [in] AcpiTableInfo Pointer to the ACPI table generator to be used.\r
1044 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1045 Protocol Interface.\r
1046 @param [out] Table Pointer to the constructed ACPI Table.\r
1047\r
1048 @retval EFI_SUCCESS Table generated successfully.\r
1049 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1050 @retval EFI_NOT_FOUND The required object was not found.\r
1051 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration\r
1052 Manager is less than the Object size for\r
1053 the requested object.\r
1054**/\r
1055STATIC\r
1056EFI_STATUS\r
1057EFIAPI\r
1058BuildPpttTable (\r
1059 IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
1060 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
1061 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
1062 OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table\r
1063 )\r
1064{\r
1065 EFI_STATUS Status;\r
1066 UINT32 TableSize;\r
1067 UINT32 ProcTopologyStructCount;\r
1068\r
1069 UINT32 ProcHierarchyNodeOffset;\r
1070 UINT32 CacheStructOffset;\r
1071 UINT32 IdStructOffset;\r
1072\r
1073 CM_ARM_PROC_HIERARCHY_INFO * ProcHierarchyNodeList;\r
1074 CM_ARM_CACHE_INFO * CacheStructList;\r
1075 CM_ARM_PROC_NODE_ID_INFO * IdStructList;\r
1076\r
1077 ACPI_PPTT_GENERATOR * Generator;\r
1078\r
1079 // Pointer to the Node Indexer array\r
1080 PPTT_NODE_INDEXER * NodeIndexer;\r
1081\r
1082 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER * Pptt;\r
1083\r
1084 ASSERT (\r
1085 (This != NULL) &&\r
1086 (AcpiTableInfo != NULL) &&\r
1087 (CfgMgrProtocol != NULL) &&\r
1088 (Table != NULL) &&\r
1089 (AcpiTableInfo->TableGeneratorId == This->GeneratorID) &&\r
1090 (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature)\r
1091 );\r
1092\r
1093 if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||\r
1094 (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {\r
1095 DEBUG ((\r
1096 DEBUG_ERROR,\r
1097 "ERROR: PPTT: Requested table revision = %d is not supported. "\r
1098 "Supported table revisions: Minimum = %d. Maximum = %d\n",\r
1099 AcpiTableInfo->AcpiTableRevision,\r
1100 This->MinAcpiTableRevision,\r
1101 This->AcpiTableRevision\r
1102 ));\r
1103 return EFI_INVALID_PARAMETER;\r
1104 }\r
1105\r
1106 Generator = (ACPI_PPTT_GENERATOR*)This;\r
1107 *Table = NULL;\r
1108\r
1109 // Get the processor hierarchy info and update the processor topology\r
1110 // structure count with Processor Hierarchy Nodes (Type 0)\r
1111 Status = GetEArmObjProcHierarchyInfo (\r
1112 CfgMgrProtocol,\r
1113 CM_NULL_TOKEN,\r
1114 &ProcHierarchyNodeList,\r
1115 &Generator->ProcHierarchyNodeCount\r
1116 );\r
1117 if (EFI_ERROR (Status)) {\r
1118 DEBUG ((\r
1119 DEBUG_ERROR,\r
1120 "ERROR: PPTT: Failed to get processor hierarchy info. Status = %r\n",\r
1121 Status\r
1122 ));\r
1123 goto error_handler;\r
1124 }\r
1125\r
1126 ProcTopologyStructCount = Generator->ProcHierarchyNodeCount;\r
1127\r
1128 // Get the cache info and update the processor topology structure count with\r
1129 // Cache Type Structures (Type 1)\r
1130 Status = GetEArmObjCacheInfo (\r
1131 CfgMgrProtocol,\r
1132 CM_NULL_TOKEN,\r
1133 &CacheStructList,\r
1134 &Generator->CacheStructCount\r
1135 );\r
1136 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1137 DEBUG ((\r
1138 DEBUG_ERROR,\r
1139 "ERROR: PPTT: Failed to get cache info. Status = %r\n",\r
1140 Status\r
1141 ));\r
1142 goto error_handler;\r
1143 }\r
1144\r
1145 ProcTopologyStructCount += Generator->CacheStructCount;\r
1146\r
1147 // Get the processor hierarchy node ID info and update the processor topology\r
1148 // structure count with ID Structures (Type 2)\r
1149 Status = GetEArmObjProcNodeIdInfo (\r
1150 CfgMgrProtocol,\r
1151 CM_NULL_TOKEN,\r
1152 &IdStructList,\r
1153 &Generator->IdStructCount\r
1154 );\r
1155 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1156 DEBUG ((\r
1157 DEBUG_ERROR,\r
1158 "ERROR: PPTT: Failed to get processor hierarchy node ID info. " \\r
1159 "Status = %r\n",\r
1160 Status\r
1161 ));\r
1162 goto error_handler;\r
1163 }\r
1164\r
1165 ProcTopologyStructCount += Generator->IdStructCount;\r
1166\r
1167 // Allocate Node Indexer array\r
1168 NodeIndexer = (PPTT_NODE_INDEXER*)AllocateZeroPool (\r
1169 sizeof (PPTT_NODE_INDEXER) *\r
1170 ProcTopologyStructCount\r
1171 );\r
1172 if (NodeIndexer == NULL) {\r
1173 Status = EFI_OUT_OF_RESOURCES;\r
1174 DEBUG ((\r
1175 DEBUG_ERROR,\r
1176 "ERROR: PPTT: Failed to allocate memory for Node Indexer. Status = %r\n ",\r
1177 Status\r
1178 ));\r
1179 goto error_handler;\r
1180 }\r
1181\r
1182 DEBUG ((DEBUG_INFO, "INFO: NodeIndexer = %p\n", NodeIndexer));\r
1183 Generator->ProcTopologyStructCount = ProcTopologyStructCount;\r
1184 Generator->NodeIndexer = NodeIndexer;\r
1185\r
1186 // Calculate the size of the PPTT table\r
1187 TableSize = sizeof (EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER);\r
1188\r
1189 // Include the size of Processor Hierarchy Nodes and index them\r
1190 if (Generator->ProcHierarchyNodeCount != 0) {\r
1191 ProcHierarchyNodeOffset = TableSize;\r
1192 Generator->ProcHierarchyNodeIndexedList = NodeIndexer;\r
1193 TableSize += GetSizeofProcHierarchyNodes (\r
1194 ProcHierarchyNodeOffset,\r
1195 ProcHierarchyNodeList,\r
1196 Generator->ProcHierarchyNodeCount,\r
1197 &NodeIndexer\r
1198 );\r
1199 }\r
1200\r
1201 // Include the size of Cache Type Structures and index them\r
1202 if (Generator->CacheStructCount != 0) {\r
1203 CacheStructOffset = TableSize;\r
1204 Generator->CacheStructIndexedList = NodeIndexer;\r
1205 TableSize += GetSizeofCacheTypeStructs (\r
1206 CacheStructOffset,\r
1207 CacheStructList,\r
1208 Generator->CacheStructCount,\r
1209 &NodeIndexer\r
1210 );\r
1211 }\r
1212\r
1213 // Include the size of ID Type Structures and index them\r
1214 if (Generator->IdStructCount != 0) {\r
1215 IdStructOffset = TableSize;\r
1216 Generator->IdStructIndexedList = NodeIndexer;\r
1217 TableSize += GetSizeofIdStructs (\r
1218 IdStructOffset,\r
1219 IdStructList,\r
1220 Generator->IdStructCount,\r
1221 &NodeIndexer\r
1222 );\r
1223 }\r
1224\r
1225 DEBUG ((\r
1226 DEBUG_INFO,\r
1227 "INFO: PPTT:\n" \\r
1228 " ProcTopologyStructCount = %d\n" \\r
1229 " TableSize = %d\n",\r
1230 ProcTopologyStructCount,\r
1231 TableSize\r
1232 ));\r
1233\r
1234 DEBUG ((\r
1235 DEBUG_INFO,\r
1236 " ProcHierarchyNodeCount = %d\n" \\r
1237 " ProcHierarchyNodeOffset = 0x%x\n" \\r
1238 " ProcHierarchyNodeIndexedList = 0x%p\n",\r
1239 Generator->ProcHierarchyNodeCount,\r
1240 ProcHierarchyNodeOffset,\r
1241 Generator->ProcHierarchyNodeIndexedList\r
1242 ));\r
1243\r
1244 DEBUG ((\r
1245 DEBUG_INFO,\r
1246 " CacheStructCount = %d\n" \\r
1247 " CacheStructOffset = 0x%x\n" \\r
1248 " CacheStructIndexedList = 0x%p\n",\r
1249 Generator->CacheStructCount,\r
1250 CacheStructOffset,\r
1251 Generator->CacheStructIndexedList\r
1252 ));\r
1253\r
1254 DEBUG ((\r
1255 DEBUG_INFO,\r
1256 " IdStructCount = %d\n" \\r
1257 " IdStructOffset = 0x%x\n" \\r
1258 " IdStructIndexedList = 0x%p\n",\r
1259 Generator->IdStructCount,\r
1260 IdStructOffset,\r
1261 Generator->IdStructIndexedList\r
1262 ));\r
1263\r
1264 // Allocate the Buffer for the PPTT table\r
1265 *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);\r
1266 if (*Table == NULL) {\r
1267 Status = EFI_OUT_OF_RESOURCES;\r
1268 DEBUG ((\r
1269 DEBUG_ERROR,\r
1270 "ERROR: PPTT: Failed to allocate memory for PPTT Table. " \\r
1271 "Size = %d. Status = %r\n",\r
1272 TableSize,\r
1273 Status\r
1274 ));\r
1275 goto error_handler;\r
1276 }\r
1277\r
1278 Pptt = (EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER*)*Table;\r
1279\r
1280 DEBUG ((\r
1281 DEBUG_INFO,\r
1282 "PPTT: Pptt = 0x%p. TableSize = 0x%x\n",\r
1283 Pptt,\r
1284 TableSize\r
1285 ));\r
1286\r
1287 // Add ACPI header\r
1288 Status = AddAcpiHeader (\r
1289 CfgMgrProtocol,\r
1290 This,\r
1291 &Pptt->Header,\r
1292 AcpiTableInfo,\r
1293 TableSize\r
1294 );\r
1295 if (EFI_ERROR (Status)) {\r
1296 DEBUG ((\r
1297 DEBUG_ERROR,\r
1298 "ERROR: PPTT: Failed to add ACPI header. Status = %r\n",\r
1299 Status\r
1300 ));\r
1301 goto error_handler;\r
1302 }\r
1303\r
1304 // Add Processor Hierarchy Nodes (Type 0) to the generated table\r
1305 if (Generator->ProcHierarchyNodeCount != 0) {\r
1306 Status = AddProcHierarchyNodes (\r
1307 Generator,\r
1308 CfgMgrProtocol,\r
1309 Pptt,\r
1310 ProcHierarchyNodeOffset\r
1311 );\r
1312 if (EFI_ERROR (Status)) {\r
1313 DEBUG ((\r
1314 DEBUG_ERROR,\r
1315 "ERROR: PPTT: Failed to add Processor Hierarchy Nodes. Status = %r\n",\r
1316 Status\r
1317 ));\r
1318 goto error_handler;\r
1319 }\r
1320 }\r
1321\r
1322 // Add Cache Type Structures (Type 1) to the generated table\r
1323 if (Generator->CacheStructCount != 0) {\r
1324 Status = AddCacheTypeStructures (\r
1325 Generator,\r
1326 CfgMgrProtocol,\r
1327 Pptt,\r
1328 CacheStructOffset\r
1329 );\r
1330 if (EFI_ERROR (Status)) {\r
1331 DEBUG ((\r
1332 DEBUG_ERROR,\r
1333 "ERROR: PPTT: Failed to add Cache Type Structures. Status = %r\n",\r
1334 Status\r
1335 ));\r
1336 goto error_handler;\r
1337 }\r
1338 }\r
1339\r
1340 // Add ID Type Structures (Type 2) to the generated table\r
1341 if (Generator->IdStructCount != 0) {\r
1342 Status = AddIdTypeStructures (\r
1343 Generator,\r
1344 CfgMgrProtocol,\r
1345 Pptt,\r
1346 IdStructOffset\r
1347 );\r
1348 if (EFI_ERROR (Status)) {\r
1349 DEBUG ((\r
1350 DEBUG_ERROR,\r
1351 "ERROR: PPTT: Failed to add ID Type Structures. Status = %r\n",\r
1352 Status\r
1353 ));\r
1354 goto error_handler;\r
1355 }\r
1356 }\r
1357\r
1358 // Validate CM object cross-references in PPTT\r
1359 Status = DetectCyclesInTopology (Generator);\r
1360 if (EFI_ERROR (Status)) {\r
1361 DEBUG ((\r
1362 DEBUG_ERROR,\r
1363 "ERROR: PPTT: Invalid processor and cache topology. Status = %r\n",\r
1364 Status\r
1365 ));\r
1366 goto error_handler;\r
1367 }\r
1368\r
1369 return Status;\r
1370\r
1371error_handler:\r
1372 if (Generator->NodeIndexer != NULL) {\r
1373 FreePool (Generator->NodeIndexer);\r
1374 Generator->NodeIndexer = NULL;\r
1375 }\r
1376\r
1377 if (*Table != NULL) {\r
1378 FreePool (*Table);\r
1379 *Table = NULL;\r
1380 }\r
1381\r
1382 return Status;\r
1383}\r
1384\r
1385/**\r
1386 Free any resources allocated for constructing the PPTT\r
1387\r
1388 @param [in] This Pointer to the table generator.\r
1389 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
1390 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1391 Protocol Interface.\r
1392 @param [in, out] Table Pointer to the ACPI Table.\r
1393\r
1394 @retval EFI_SUCCESS The resources were freed successfully.\r
1395 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.\r
1396**/\r
1397STATIC\r
1398EFI_STATUS\r
1399FreePpttTableResources (\r
1400 IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
1401 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
1402 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
1403 IN OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table\r
1404 )\r
1405{\r
1406 ACPI_PPTT_GENERATOR * Generator;\r
1407\r
1408 ASSERT (\r
1409 (This != NULL) &&\r
1410 (AcpiTableInfo != NULL) &&\r
1411 (CfgMgrProtocol != NULL) &&\r
1412 (AcpiTableInfo->TableGeneratorId == This->GeneratorID) &&\r
1413 (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature)\r
1414 );\r
1415\r
1416 Generator = (ACPI_PPTT_GENERATOR*)This;\r
1417\r
1418 // Free any memory allocated by the generator\r
1419 if (Generator->NodeIndexer != NULL) {\r
1420 FreePool (Generator->NodeIndexer);\r
1421 Generator->NodeIndexer = NULL;\r
1422 }\r
1423\r
1424 if ((Table == NULL) || (*Table == NULL)) {\r
1425 DEBUG ((DEBUG_ERROR, "ERROR: PPTT: Invalid Table Pointer\n"));\r
1426 ASSERT (\r
1427 (Table != NULL) &&\r
1428 (*Table != NULL)\r
1429 );\r
1430 return EFI_INVALID_PARAMETER;\r
1431 }\r
1432\r
1433 FreePool (*Table);\r
1434 *Table = NULL;\r
1435 return EFI_SUCCESS;\r
1436}\r
1437\r
1438/** The PPTT Table Generator revision.\r
1439*/\r
1440#define PPTT_GENERATOR_REVISION CREATE_REVISION (1, 0)\r
1441\r
1442/** The interface for the PPTT Table Generator.\r
1443*/\r
1444STATIC\r
1445ACPI_PPTT_GENERATOR PpttGenerator = {\r
1446 // ACPI table generator header\r
1447 {\r
1448 // Generator ID\r
1449 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdPptt),\r
1450 // Generator Description\r
1451 L"ACPI.STD.PPTT.GENERATOR",\r
1452 // ACPI Table Signature\r
1453 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE,\r
1454 // ACPI Table Revision supported by this Generator\r
1455 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION,\r
1456 // Minimum supported ACPI Table Revision\r
1457 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION,\r
1458 // Creator ID\r
1459 TABLE_GENERATOR_CREATOR_ID_ARM,\r
1460 // Creator Revision\r
1461 PPTT_GENERATOR_REVISION,\r
1462 // Build Table function\r
1463 BuildPpttTable,\r
1464 // Free Resource function\r
1465 FreePpttTableResources,\r
1466 // Extended build function not needed\r
1467 NULL,\r
1468 // Extended build function not implemented by the generator.\r
1469 // Hence extended free resource function is not required.\r
1470 NULL\r
1471 },\r
1472\r
1473 // PPTT Generator private data\r
1474\r
1475 // Processor topology node count\r
1476 0,\r
1477 // Pointer to PPTT Node Indexer\r
1478 NULL\r
1479};\r
1480\r
1481/**\r
1482 Register the Generator with the ACPI Table Factory.\r
1483\r
1484 @param [in] ImageHandle The handle to the image.\r
1485 @param [in] SystemTable Pointer to the System Table.\r
1486\r
1487 @retval EFI_SUCCESS The Generator is registered.\r
1488 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1489 @retval EFI_ALREADY_STARTED The Generator for the Table ID\r
1490 is already registered.\r
1491**/\r
1492EFI_STATUS\r
1493EFIAPI\r
1494AcpiPpttLibConstructor (\r
43a0e08d
SM
1495 IN EFI_HANDLE ImageHandle,\r
1496 IN EFI_SYSTEM_TABLE * SystemTable\r
77db1156
KK
1497 )\r
1498{\r
1499 EFI_STATUS Status;\r
1500 Status = RegisterAcpiTableGenerator (&PpttGenerator.Header);\r
1501 DEBUG ((DEBUG_INFO, "PPTT: Register Generator. Status = %r\n", Status));\r
1502 ASSERT_EFI_ERROR (Status);\r
1503 return Status;\r
1504}\r
1505\r
1506/**\r
1507 Deregister the Generator from the ACPI Table Factory.\r
1508\r
1509 @param [in] ImageHandle The handle to the image.\r
1510 @param [in] SystemTable Pointer to the System Table.\r
1511\r
1512 @retval EFI_SUCCESS The Generator is deregistered.\r
1513 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1514 @retval EFI_NOT_FOUND The Generator is not registered.\r
1515**/\r
1516EFI_STATUS\r
1517EFIAPI\r
1518AcpiPpttLibDestructor (\r
43a0e08d
SM
1519 IN EFI_HANDLE ImageHandle,\r
1520 IN EFI_SYSTEM_TABLE * SystemTable\r
77db1156
KK
1521 )\r
1522{\r
1523 EFI_STATUS Status;\r
1524 Status = DeregisterAcpiTableGenerator (&PpttGenerator.Header);\r
1525 DEBUG ((DEBUG_INFO, "PPTT: Deregister Generator. Status = %r\n", Status));\r
1526 ASSERT_EFI_ERROR (Status);\r
1527 return Status;\r
1528}\r