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