]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c
DynamicTablesPkg: GTDT updates for ACPI 6.3
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiGtdtLibArm / GtdtGenerator.c
1 /** @file
2 GTDT Table Generator
3
4 Copyright (c) 2017 - 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 **/
11
12 #include <Library/AcpiLib.h>
13 #include <Library/DebugLib.h>
14 #include <Library/MemoryAllocationLib.h>
15 #include <Protocol/AcpiTable.h>
16
17 // Module specific include files.
18 #include <AcpiTableGenerator.h>
19 #include <ConfigurationManagerObject.h>
20 #include <ConfigurationManagerHelper.h>
21 #include <Library/TableHelperLib.h>
22 #include <Protocol/ConfigurationManagerProtocol.h>
23
24 /** ARM standard GTDT Generator
25
26 Requirements:
27 The following Configuration Manager Object(s) are required by
28 this Generator:
29 - EArmObjGenericTimerInfo
30 - EArmObjPlatformGenericWatchdogInfo (OPTIONAL)
31 - EArmObjPlatformGTBlockInfo (OPTIONAL)
32 - EArmObjGTBlockTimerFrameInfo (OPTIONAL)
33 */
34
35 /** This macro expands to a function that retrieves the Generic
36 Timer Information from the Configuration Manager.
37 */
38 GET_OBJECT_LIST (
39 EObjNameSpaceArm,
40 EArmObjGenericTimerInfo,
41 CM_ARM_GENERIC_TIMER_INFO
42 );
43
44 /** This macro expands to a function that retrieves the SBSA Generic
45 Watchdog Timer Information from the Configuration Manager.
46 */
47 GET_OBJECT_LIST (
48 EObjNameSpaceArm,
49 EArmObjPlatformGenericWatchdogInfo,
50 CM_ARM_GENERIC_WATCHDOG_INFO
51 );
52
53 /** This macro expands to a function that retrieves the Platform Generic
54 Timer Block Information from the Configuration Manager.
55 */
56 GET_OBJECT_LIST (
57 EObjNameSpaceArm,
58 EArmObjPlatformGTBlockInfo,
59 CM_ARM_GTBLOCK_INFO
60 );
61
62 /** This macro expands to a function that retrieves the Generic
63 Timer Block Timer Frame Information from the Configuration Manager.
64 */
65 GET_OBJECT_LIST (
66 EObjNameSpaceArm,
67 EArmObjGTBlockTimerFrameInfo,
68 CM_ARM_GTBLOCK_TIMER_FRAME_INFO
69 );
70
71 /** Add the Generic Timer Information to the GTDT table.
72
73 Also update the Platform Timer offset information if the platform
74 implements platform timers.
75
76 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
77 Protocol Interface.
78 @param [in] Gtdt Pointer to the GTDT Table.
79 @param [in] PlatformTimerCount Platform timer count.
80 @param [in] AcpiTableRevision Acpi Revision targeted by the platform.
81
82 @retval EFI_SUCCESS Success.
83 @retval EFI_INVALID_PARAMETER A parameter is invalid.
84 @retval EFI_NOT_FOUND The required object was not found.
85 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
86 Manager is less than the Object size for the
87 requested object.
88 **/
89 STATIC
90 EFI_STATUS
91 EFIAPI
92 AddGenericTimerInfo (
93 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
94 IN EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE * CONST Gtdt,
95 IN CONST UINT32 PlatformTimerCount,
96 IN CONST UINT32 AcpiTableRevision
97 )
98 {
99 EFI_STATUS Status;
100 CM_ARM_GENERIC_TIMER_INFO * GenericTimerInfo;
101
102 ASSERT (CfgMgrProtocol != NULL);
103 ASSERT (Gtdt != NULL);
104
105 Status = GetEArmObjGenericTimerInfo (
106 CfgMgrProtocol,
107 CM_NULL_TOKEN,
108 &GenericTimerInfo,
109 NULL
110 );
111
112 if (EFI_ERROR (Status)) {
113 DEBUG ((
114 DEBUG_ERROR,
115 "ERROR: GTDT: Failed to get GenericTimerInfo. Status = %r\n",
116 Status
117 ));
118 return Status;
119 }
120
121 Gtdt->CntControlBasePhysicalAddress =
122 GenericTimerInfo->CounterControlBaseAddress;
123 Gtdt->Reserved = EFI_ACPI_RESERVED_DWORD;
124 Gtdt->SecurePL1TimerGSIV = GenericTimerInfo->SecurePL1TimerGSIV;
125 Gtdt->SecurePL1TimerFlags = GenericTimerInfo->SecurePL1TimerFlags;
126 Gtdt->NonSecurePL1TimerGSIV = GenericTimerInfo->NonSecurePL1TimerGSIV;
127 Gtdt->NonSecurePL1TimerFlags = GenericTimerInfo->NonSecurePL1TimerFlags;
128 Gtdt->VirtualTimerGSIV = GenericTimerInfo->VirtualTimerGSIV;
129 Gtdt->VirtualTimerFlags = GenericTimerInfo->VirtualTimerFlags;
130 Gtdt->NonSecurePL2TimerGSIV = GenericTimerInfo->NonSecurePL2TimerGSIV;
131 Gtdt->NonSecurePL2TimerFlags = GenericTimerInfo->NonSecurePL2TimerFlags;
132 Gtdt->CntReadBasePhysicalAddress =
133 GenericTimerInfo->CounterReadBaseAddress;
134 Gtdt->PlatformTimerCount = PlatformTimerCount;
135 Gtdt->PlatformTimerOffset = (PlatformTimerCount == 0) ? 0 :
136 sizeof (EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE);
137
138 if (AcpiTableRevision > EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION) {
139 Gtdt->VirtualPL2TimerGSIV = GenericTimerInfo->VirtualPL2TimerGSIV;
140 Gtdt->VirtualPL2TimerFlags = GenericTimerInfo->VirtualPL2TimerFlags;
141 }
142
143 return Status;
144 }
145
146 /** Add the SBSA Generic Watchdog Timers to the GTDT table.
147
148 @param [in] Gtdt Pointer to the GTDT Table.
149 @param [in] WatchdogOffset Offset to the watchdog information in the
150 GTDT Table.
151 @param [in] WatchdogInfoList Pointer to the watchdog information list.
152 @param [in] WatchdogCount Platform timer count.
153 **/
154 STATIC
155 VOID
156 AddGenericWatchdogList (
157 IN EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE * CONST Gtdt,
158 IN CONST UINT32 WatchdogOffset,
159 IN CONST CM_ARM_GENERIC_WATCHDOG_INFO * WatchdogInfoList,
160 IN UINT32 WatchdogCount
161 )
162 {
163 EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE * Watchdog;
164
165 ASSERT (Gtdt != NULL);
166 ASSERT (WatchdogInfoList != NULL);
167
168 Watchdog = (EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE *)
169 ((UINT8*)Gtdt + WatchdogOffset);
170
171 while (WatchdogCount-- != 0) {
172 // Add watchdog entry
173 DEBUG ((DEBUG_INFO, "GTDT: Watchdog = 0x%p\n", Watchdog));
174 Watchdog->Type = EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG;
175 Watchdog->Length =
176 sizeof (EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE);
177 Watchdog->Reserved = EFI_ACPI_RESERVED_BYTE;
178 Watchdog->RefreshFramePhysicalAddress =
179 WatchdogInfoList->RefreshFrameAddress;
180 Watchdog->WatchdogControlFramePhysicalAddress =
181 WatchdogInfoList->ControlFrameAddress;
182 Watchdog->WatchdogTimerGSIV = WatchdogInfoList->TimerGSIV;
183 Watchdog->WatchdogTimerFlags = WatchdogInfoList->Flags;
184 Watchdog++;
185 WatchdogInfoList++;
186 } // for
187 }
188
189 /**
190 Function to test if two Generic Timer Block Frame Info structures have the
191 same frame number.
192
193 @param [in] Frame1 Pointer to the first GT Block Frame Info
194 structure.
195 @param [in] Frame2 Pointer to the second GT Block Frame Info
196 structure.
197 @param [in] Index1 Index of Frame1 in the shared GT Block Frame
198 Information List.
199 @param [in] Index2 Index of Frame2 in the shared GT Block Frame
200 Information List.
201
202 @retval TRUE Frame1 and Frame2 have the same frame number.
203 @return FALSE Frame1 and Frame2 have different frame numbers.
204
205 **/
206 BOOLEAN
207 EFIAPI
208 IsGtFrameNumberEqual (
209 IN CONST VOID * Frame1,
210 IN CONST VOID * Frame2,
211 IN UINTN Index1,
212 IN UINTN Index2
213 )
214 {
215 UINT8 FrameNumber1;
216 UINT8 FrameNumber2;
217
218 ASSERT ((Frame1 != NULL) && (Frame2 != NULL));
219
220 FrameNumber1 = ((CM_ARM_GTBLOCK_TIMER_FRAME_INFO*)Frame1)->FrameNumber;
221 FrameNumber2 = ((CM_ARM_GTBLOCK_TIMER_FRAME_INFO*)Frame2)->FrameNumber;
222
223 if (FrameNumber1 == FrameNumber2) {
224 DEBUG ((
225 DEBUG_ERROR,
226 "ERROR: GTDT: GT Block Frame Info Structures %d and %d have the same " \
227 "frame number: 0x%x.\n",
228 Index1,
229 Index2,
230 FrameNumber1
231 ));
232 return TRUE;
233 }
234
235 return FALSE;
236 }
237
238 /** Update the GT Block Timer Frame lists in the GTDT Table.
239
240 @param [in] GtBlockFrame Pointer to the GT Block Frames
241 list to be updated.
242 @param [in] GTBlockTimerFrameList Pointer to the GT Block Frame
243 Information List.
244 @param [in] GTBlockFrameCount Number of GT Block Frames.
245
246 @retval EFI_SUCCESS Table generated successfully.
247 @retval EFI_INVALID_PARAMETER A parameter is invalid.
248 **/
249 STATIC
250 EFI_STATUS
251 AddGTBlockTimerFrames (
252 IN EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_STRUCTURE * GtBlockFrame,
253 IN CONST CM_ARM_GTBLOCK_TIMER_FRAME_INFO * GTBlockTimerFrameList,
254 IN UINT32 GTBlockFrameCount
255 )
256 {
257 BOOLEAN IsFrameNumberDuplicated;
258
259 ASSERT (GtBlockFrame != NULL);
260 ASSERT (GTBlockTimerFrameList != NULL);
261
262 if (GTBlockFrameCount > 8) {
263 DEBUG ((
264 DEBUG_ERROR,
265 "ERROR: GTDT: GT Block Frame Count %d is greater than 8\n",
266 GTBlockFrameCount
267 ));
268 ASSERT (GTBlockFrameCount <= 8);
269 return EFI_INVALID_PARAMETER;
270 }
271
272 IsFrameNumberDuplicated = FindDuplicateValue (
273 GTBlockTimerFrameList,
274 GTBlockFrameCount,
275 sizeof (CM_ARM_GTBLOCK_TIMER_FRAME_INFO),
276 IsGtFrameNumberEqual
277 );
278 // Duplicate entry was found so timer frame numbers provided are invalid
279 if (IsFrameNumberDuplicated) {
280 return EFI_INVALID_PARAMETER;
281 }
282
283 while (GTBlockFrameCount-- != 0) {
284 DEBUG ((
285 DEBUG_INFO,
286 "GTDT: GtBlockFrame = 0x%p\n",
287 GtBlockFrame
288 ));
289
290 if (GTBlockTimerFrameList->FrameNumber >= 8) {
291 DEBUG ((
292 DEBUG_ERROR,
293 "ERROR: GTDT: Frame number %d is not in the range 0-7\n",
294 GTBlockTimerFrameList->FrameNumber
295 ));
296 return EFI_INVALID_PARAMETER;
297 }
298
299 GtBlockFrame->GTFrameNumber = GTBlockTimerFrameList->FrameNumber;
300 GtBlockFrame->Reserved[0] = EFI_ACPI_RESERVED_BYTE;
301 GtBlockFrame->Reserved[1] = EFI_ACPI_RESERVED_BYTE;
302 GtBlockFrame->Reserved[2] = EFI_ACPI_RESERVED_BYTE;
303
304 GtBlockFrame->CntBaseX = GTBlockTimerFrameList->PhysicalAddressCntBase;
305 GtBlockFrame->CntEL0BaseX =
306 GTBlockTimerFrameList->PhysicalAddressCntEL0Base;
307
308 GtBlockFrame->GTxPhysicalTimerGSIV =
309 GTBlockTimerFrameList->PhysicalTimerGSIV;
310 GtBlockFrame->GTxPhysicalTimerFlags =
311 GTBlockTimerFrameList->PhysicalTimerFlags;
312
313 GtBlockFrame->GTxVirtualTimerGSIV = GTBlockTimerFrameList->VirtualTimerGSIV;
314 GtBlockFrame->GTxVirtualTimerFlags =
315 GTBlockTimerFrameList->VirtualTimerFlags;
316
317 GtBlockFrame->GTxCommonFlags = GTBlockTimerFrameList->CommonFlags;
318 GtBlockFrame++;
319 GTBlockTimerFrameList++;
320 } // for
321 return EFI_SUCCESS;
322 }
323
324 /** Add the GT Block Timers in the GTDT Table.
325
326 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
327 Protocol Interface.
328 @param [in] Gtdt Pointer to the GTDT Table.
329 @param [in] GTBlockOffset Offset of the GT Block
330 information in the GTDT Table.
331 @param [in] GTBlockInfo Pointer to the GT Block
332 Information List.
333 @param [in] BlockTimerCount Number of GT Block Timers.
334
335 @retval EFI_SUCCESS Table generated successfully.
336 @retval EFI_INVALID_PARAMETER A parameter is invalid.
337 **/
338 STATIC
339 EFI_STATUS
340 AddGTBlockList (
341 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
342 IN EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE * CONST Gtdt,
343 IN CONST UINT32 GTBlockOffset,
344 IN CONST CM_ARM_GTBLOCK_INFO * GTBlockInfo,
345 IN UINT32 BlockTimerCount
346 )
347 {
348 EFI_STATUS Status;
349 EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE * GTBlock;
350 EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_STRUCTURE * GtBlockFrame;
351 CM_ARM_GTBLOCK_TIMER_FRAME_INFO * GTBlockTimerFrameList;
352 UINT32 GTBlockTimerFrameCount;
353
354 ASSERT (Gtdt != NULL);
355 ASSERT (GTBlockInfo != NULL);
356
357 GTBlock = (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE *)((UINT8*)Gtdt +
358 GTBlockOffset);
359
360 while (BlockTimerCount-- != 0) {
361 DEBUG ((DEBUG_INFO, "GTDT: GTBlock = 0x%p\n", GTBlock));
362
363 Status = GetEArmObjGTBlockTimerFrameInfo (
364 CfgMgrProtocol,
365 GTBlockInfo->GTBlockTimerFrameToken,
366 &GTBlockTimerFrameList,
367 &GTBlockTimerFrameCount
368 );
369 if (EFI_ERROR (Status) ||
370 (GTBlockTimerFrameCount != GTBlockInfo->GTBlockTimerFrameCount)) {
371 DEBUG ((
372 DEBUG_ERROR,
373 "ERROR: GTDT: Failed to get Generic Timer Frames. Status = %r\n",
374 Status
375 ));
376 return Status;
377 }
378
379 GTBlock->Type = EFI_ACPI_6_3_GTDT_GT_BLOCK;
380 GTBlock->Length = sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE) +
381 (sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_STRUCTURE) *
382 GTBlockInfo->GTBlockTimerFrameCount);
383
384 GTBlock->Reserved = EFI_ACPI_RESERVED_BYTE;
385 GTBlock->CntCtlBase = GTBlockInfo->GTBlockPhysicalAddress;
386 GTBlock->GTBlockTimerCount = GTBlockInfo->GTBlockTimerFrameCount;
387 GTBlock->GTBlockTimerOffset =
388 sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE);
389
390 GtBlockFrame = (EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_STRUCTURE*)
391 ((UINT8*)GTBlock + GTBlock->GTBlockTimerOffset);
392
393 // Add GT Block Timer frames
394 Status = AddGTBlockTimerFrames (
395 GtBlockFrame,
396 GTBlockTimerFrameList,
397 GTBlockTimerFrameCount
398 );
399 if (EFI_ERROR (Status)) {
400 DEBUG ((
401 DEBUG_ERROR,
402 "ERROR: GTDT: Failed to add Generic Timer Frames. Status = %r\n",
403 Status
404 ));
405 return Status;
406 }
407
408 // Next GTBlock
409 GTBlock = (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE *)((UINT8*)GTBlock +
410 GTBlock->Length);
411 GTBlockInfo++;
412 }// for
413 return EFI_SUCCESS;
414 }
415
416 /** Construct the GTDT ACPI table.
417
418 Called by the Dynamic Table Manager, this function invokes the
419 Configuration Manager protocol interface to get the required hardware
420 information for generating the ACPI table.
421
422 If this function allocates any resources then they must be freed
423 in the FreeXXXXTableResources function.
424
425 @param [in] This Pointer to the table generator.
426 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
427 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
428 Protocol Interface.
429 @param [out] Table Pointer to the constructed ACPI Table.
430
431 @retval EFI_SUCCESS Table generated successfully.
432 @retval EFI_INVALID_PARAMETER A parameter is invalid.
433 @retval EFI_NOT_FOUND The required object was not found.
434 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
435 Manager is less than the Object size for the
436 requested object.
437 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
438 **/
439 STATIC
440 EFI_STATUS
441 EFIAPI
442 BuildGtdtTable (
443 IN CONST ACPI_TABLE_GENERATOR * CONST This,
444 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
445 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
446 OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table
447 )
448 {
449 EFI_STATUS Status;
450 UINT32 TableSize;
451 UINT32 PlatformTimerCount;
452 UINT32 WatchdogCount;
453 UINT32 BlockTimerCount;
454 CM_ARM_GENERIC_WATCHDOG_INFO * WatchdogInfoList;
455 CM_ARM_GTBLOCK_INFO * GTBlockInfo;
456 EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE * Gtdt;
457 UINT32 Idx;
458 UINT32 GTBlockOffset;
459 UINT32 WatchdogOffset;
460
461 ASSERT (This != NULL);
462 ASSERT (AcpiTableInfo != NULL);
463 ASSERT (CfgMgrProtocol != NULL);
464 ASSERT (Table != NULL);
465 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
466 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
467
468 if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
469 (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
470 DEBUG ((
471 DEBUG_ERROR,
472 "ERROR: GTDT: Requested table revision = %d, is not supported."
473 "Supported table revision: Minimum = %d, Maximum = %d\n",
474 AcpiTableInfo->AcpiTableRevision,
475 This->MinAcpiTableRevision,
476 This->AcpiTableRevision
477 ));
478 return EFI_INVALID_PARAMETER;
479 }
480
481 *Table = NULL;
482 Status = GetEArmObjPlatformGTBlockInfo (
483 CfgMgrProtocol,
484 CM_NULL_TOKEN,
485 &GTBlockInfo,
486 &BlockTimerCount
487 );
488 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
489 DEBUG ((
490 DEBUG_ERROR,
491 "ERROR: GTDT: Failed to Get Platform GT Block Information." \
492 " Status = %r\n",
493 Status
494 ));
495 goto error_handler;
496 }
497
498 Status = GetEArmObjPlatformGenericWatchdogInfo (
499 CfgMgrProtocol,
500 CM_NULL_TOKEN,
501 &WatchdogInfoList,
502 &WatchdogCount
503 );
504 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
505 DEBUG ((
506 DEBUG_ERROR,
507 "ERROR: GTDT: Failed to Get Platform Generic Watchdog Information." \
508 " Status = %r\n",
509 Status
510 ));
511 goto error_handler;
512 }
513
514 DEBUG ((
515 DEBUG_INFO,
516 "GTDT: BlockTimerCount = %d, WatchdogCount = %d\n",
517 BlockTimerCount,
518 WatchdogCount
519 ));
520
521 // Calculate the GTDT Table Size
522 PlatformTimerCount = 0;
523 TableSize = sizeof (EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE);
524 if (BlockTimerCount != 0) {
525 GTBlockOffset = TableSize;
526 PlatformTimerCount += BlockTimerCount;
527 TableSize += (sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE) *
528 BlockTimerCount);
529
530 for (Idx = 0; Idx < BlockTimerCount; Idx++) {
531 if (GTBlockInfo[Idx].GTBlockTimerFrameCount > 8) {
532 Status = EFI_INVALID_PARAMETER;
533 DEBUG ((
534 DEBUG_ERROR,
535 "GTDT: GTBockFrameCount cannot be more than 8." \
536 " GTBockFrameCount = %d, Status = %r\n",
537 GTBlockInfo[Idx].GTBlockTimerFrameCount,
538 Status
539 ));
540 goto error_handler;
541 }
542 TableSize += (sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_STRUCTURE) *
543 GTBlockInfo[Idx].GTBlockTimerFrameCount);
544 }
545
546 DEBUG ((
547 DEBUG_INFO,
548 "GTDT: GTBockOffset = 0x%x, PLATFORM_TIMER_COUNT = %d\n",
549 GTBlockOffset,
550 PlatformTimerCount
551 ));
552 }
553
554 WatchdogOffset = 0;
555 if (WatchdogCount != 0) {
556 WatchdogOffset = TableSize;
557 PlatformTimerCount += WatchdogCount;
558 TableSize += (sizeof (EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE) *
559 WatchdogCount);
560 DEBUG ((
561 DEBUG_INFO,
562 "GTDT: WatchdogOffset = 0x%x, PLATFORM_TIMER_COUNT = %d\n",
563 WatchdogOffset,
564 PlatformTimerCount
565 ));
566 }
567
568 *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);
569 if (*Table == NULL) {
570 Status = EFI_OUT_OF_RESOURCES;
571 DEBUG ((
572 DEBUG_ERROR,
573 "ERROR: GTDT: Failed to allocate memory for GTDT Table, Size = %d," \
574 " Status = %r\n",
575 TableSize,
576 Status
577 ));
578 goto error_handler;
579 }
580
581 Gtdt = (EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE*)*Table;
582 DEBUG ((
583 DEBUG_INFO,
584 "GTDT: Gtdt = 0x%p TableSize = 0x%x\n",
585 Gtdt,
586 TableSize
587 ));
588
589 Status = AddAcpiHeader (
590 CfgMgrProtocol,
591 This,
592 &Gtdt->Header,
593 AcpiTableInfo,
594 TableSize
595 );
596 if (EFI_ERROR (Status)) {
597 DEBUG ((
598 DEBUG_ERROR,
599 "ERROR: GTDT: Failed to add ACPI header. Status = %r\n",
600 Status
601 ));
602 goto error_handler;
603 }
604
605 Status = AddGenericTimerInfo (
606 CfgMgrProtocol,
607 Gtdt,
608 PlatformTimerCount,
609 AcpiTableInfo->AcpiTableRevision
610 );
611 if (EFI_ERROR (Status)) {
612 DEBUG ((
613 DEBUG_ERROR,
614 "ERROR: GTDT: Failed to add Generic Timer Info. Status = %r\n",
615 Status
616 ));
617 goto error_handler;
618 }
619
620 if (BlockTimerCount != 0) {
621 Status = AddGTBlockList (
622 CfgMgrProtocol,
623 Gtdt,
624 GTBlockOffset,
625 GTBlockInfo,
626 BlockTimerCount
627 );
628 if (EFI_ERROR (Status)) {
629 DEBUG ((
630 DEBUG_ERROR,
631 "ERROR: GTDT: Failed to add GT Block timers. Status = %r\n",
632 Status
633 ));
634 goto error_handler;
635 }
636 }
637
638 if (WatchdogCount != 0) {
639 AddGenericWatchdogList (
640 Gtdt,
641 WatchdogOffset,
642 WatchdogInfoList,
643 WatchdogCount
644 );
645 }
646
647 return Status;
648
649 error_handler:
650 if (*Table != NULL) {
651 FreePool (*Table);
652 *Table = NULL;
653 }
654 return Status;
655 }
656
657 /** Free any resources allocated for constructing the GTDT.
658
659 @param [in] This Pointer to the table generator.
660 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
661 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
662 Protocol Interface.
663 @param [in, out] Table Pointer to the ACPI Table.
664
665 @retval EFI_SUCCESS The resources were freed successfully.
666 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
667 **/
668 STATIC
669 EFI_STATUS
670 FreeGtdtTableResources (
671 IN CONST ACPI_TABLE_GENERATOR * CONST This,
672 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
673 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
674 IN OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table
675 )
676 {
677 ASSERT (This != NULL);
678 ASSERT (AcpiTableInfo != NULL);
679 ASSERT (CfgMgrProtocol != NULL);
680 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
681 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
682
683 if ((Table == NULL) || (*Table == NULL)) {
684 DEBUG ((DEBUG_ERROR, "ERROR: GTDT: Invalid Table Pointer\n"));
685 ASSERT ((Table != NULL) && (*Table != NULL));
686 return EFI_INVALID_PARAMETER;
687 }
688
689 FreePool (*Table);
690 *Table = NULL;
691 return EFI_SUCCESS;
692 }
693
694 /** This macro defines the GTDT Table Generator revision.
695 */
696 #define GTDT_GENERATOR_REVISION CREATE_REVISION (1, 0)
697
698 /** The interface for the GTDT Table Generator.
699 */
700 STATIC
701 CONST
702 ACPI_TABLE_GENERATOR GtdtGenerator = {
703 // Generator ID
704 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdGtdt),
705 // Generator Description
706 L"ACPI.STD.GTDT.GENERATOR",
707 // ACPI Table Signature
708 EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE,
709 // ACPI Table Revision supported by this Generator
710 EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION,
711 // Minimum ACPI Table Revision supported by this Generator
712 EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION,
713 // Creator ID
714 TABLE_GENERATOR_CREATOR_ID_ARM,
715 // Creator Revision
716 GTDT_GENERATOR_REVISION,
717 // Build Table function
718 BuildGtdtTable,
719 // Free Resource function
720 FreeGtdtTableResources,
721 // Extended build function not needed
722 NULL,
723 // Extended build function not implemented by the generator.
724 // Hence extended free resource function is not required.
725 NULL
726 };
727
728 /** Register the Generator with the ACPI Table Factory.
729
730 @param [in] ImageHandle The handle to the image.
731 @param [in] SystemTable Pointer to the System Table.
732
733 @retval EFI_SUCCESS The Generator is registered.
734 @retval EFI_INVALID_PARAMETER A parameter is invalid.
735 @retval EFI_ALREADY_STARTED The Generator for the Table ID
736 is already registered.
737 **/
738 EFI_STATUS
739 EFIAPI
740 AcpiGtdtLibConstructor (
741 IN CONST EFI_HANDLE ImageHandle,
742 IN EFI_SYSTEM_TABLE * CONST SystemTable
743 )
744 {
745 EFI_STATUS Status;
746 Status = RegisterAcpiTableGenerator (&GtdtGenerator);
747 DEBUG ((DEBUG_INFO, "GTDT: Register Generator. Status = %r\n", Status));
748 ASSERT_EFI_ERROR (Status);
749 return Status;
750 }
751
752 /** Deregister the Generator from the ACPI Table Factory.
753
754 @param [in] ImageHandle The handle to the image.
755 @param [in] SystemTable Pointer to the System Table.
756
757 @retval EFI_SUCCESS The Generator is deregistered.
758 @retval EFI_INVALID_PARAMETER A parameter is invalid.
759 @retval EFI_NOT_FOUND The Generator is not registered.
760 **/
761 EFI_STATUS
762 EFIAPI
763 AcpiGtdtLibDestructor (
764 IN CONST EFI_HANDLE ImageHandle,
765 IN EFI_SYSTEM_TABLE * CONST SystemTable
766 )
767 {
768 EFI_STATUS Status;
769 Status = DeregisterAcpiTableGenerator (&GtdtGenerator);
770 DEBUG ((DEBUG_INFO, "GTDT: Deregister Generator. Status = %r\n", Status));
771 ASSERT_EFI_ERROR (Status);
772 return Status;
773 }