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