]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c
0e996698887aefca8a7240fc27fe3cb9324fd3e2
[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 UINTN Length;
354
355 ASSERT (Gtdt != NULL);
356 ASSERT (GTBlockInfo != NULL);
357
358 GTBlock = (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE *)((UINT8*)Gtdt +
359 GTBlockOffset);
360
361 while (BlockTimerCount-- != 0) {
362 DEBUG ((DEBUG_INFO, "GTDT: GTBlock = 0x%p\n", GTBlock));
363
364 Status = GetEArmObjGTBlockTimerFrameInfo (
365 CfgMgrProtocol,
366 GTBlockInfo->GTBlockTimerFrameToken,
367 &GTBlockTimerFrameList,
368 &GTBlockTimerFrameCount
369 );
370 if (EFI_ERROR (Status) ||
371 (GTBlockTimerFrameCount != GTBlockInfo->GTBlockTimerFrameCount)) {
372 DEBUG ((
373 DEBUG_ERROR,
374 "ERROR: GTDT: Failed to get Generic Timer Frames. Status = %r\n",
375 Status
376 ));
377 return Status;
378 }
379
380 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 // Check that the length of the GT block does not
385 // exceed MAX_UINT16
386 if (Length > MAX_UINT16) {
387 Status = EFI_INVALID_PARAMETER;
388 DEBUG ((
389 DEBUG_ERROR,
390 "ERROR: GTDT: Too many GT Frames. Count = %d. " \
391 "Maximum supported GT Block size exceeded. " \
392 "Status = %r\n",
393 GTBlockInfo->GTBlockTimerFrameCount,
394 Status
395 ));
396 return Status;
397 }
398
399 GTBlock->Type = EFI_ACPI_6_3_GTDT_GT_BLOCK;
400 GTBlock->Length = (UINT16)Length;
401 GTBlock->Reserved = EFI_ACPI_RESERVED_BYTE;
402 GTBlock->CntCtlBase = GTBlockInfo->GTBlockPhysicalAddress;
403 GTBlock->GTBlockTimerCount = GTBlockInfo->GTBlockTimerFrameCount;
404 GTBlock->GTBlockTimerOffset =
405 sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE);
406
407 GtBlockFrame = (EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_STRUCTURE*)
408 ((UINT8*)GTBlock + GTBlock->GTBlockTimerOffset);
409
410 // Add GT Block Timer frames
411 Status = AddGTBlockTimerFrames (
412 GtBlockFrame,
413 GTBlockTimerFrameList,
414 GTBlockTimerFrameCount
415 );
416 if (EFI_ERROR (Status)) {
417 DEBUG ((
418 DEBUG_ERROR,
419 "ERROR: GTDT: Failed to add Generic Timer Frames. Status = %r\n",
420 Status
421 ));
422 return Status;
423 }
424
425 // Next GTBlock
426 GTBlock = (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE *)((UINT8*)GTBlock +
427 GTBlock->Length);
428 GTBlockInfo++;
429 }// for
430 return EFI_SUCCESS;
431 }
432
433 /** Construct the GTDT ACPI table.
434
435 Called by the Dynamic Table Manager, this function invokes the
436 Configuration Manager protocol interface to get the required hardware
437 information for generating the ACPI table.
438
439 If this function allocates any resources then they must be freed
440 in the FreeXXXXTableResources function.
441
442 @param [in] This Pointer to the table generator.
443 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
444 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
445 Protocol Interface.
446 @param [out] Table Pointer to the constructed ACPI Table.
447
448 @retval EFI_SUCCESS Table generated successfully.
449 @retval EFI_INVALID_PARAMETER A parameter is invalid.
450 @retval EFI_NOT_FOUND The required object was not found.
451 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
452 Manager is less than the Object size for the
453 requested object.
454 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
455 **/
456 STATIC
457 EFI_STATUS
458 EFIAPI
459 BuildGtdtTable (
460 IN CONST ACPI_TABLE_GENERATOR * CONST This,
461 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
462 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
463 OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table
464 )
465 {
466 EFI_STATUS Status;
467 UINT32 TableSize;
468 UINT32 PlatformTimerCount;
469 UINT32 WatchdogCount;
470 UINT32 BlockTimerCount;
471 CM_ARM_GENERIC_WATCHDOG_INFO * WatchdogInfoList;
472 CM_ARM_GTBLOCK_INFO * GTBlockInfo;
473 EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE * Gtdt;
474 UINT32 Idx;
475 UINT32 GTBlockOffset;
476 UINT32 WatchdogOffset;
477
478 ASSERT (This != NULL);
479 ASSERT (AcpiTableInfo != NULL);
480 ASSERT (CfgMgrProtocol != NULL);
481 ASSERT (Table != NULL);
482 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
483 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
484
485 if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
486 (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
487 DEBUG ((
488 DEBUG_ERROR,
489 "ERROR: GTDT: Requested table revision = %d, is not supported."
490 "Supported table revision: Minimum = %d, Maximum = %d\n",
491 AcpiTableInfo->AcpiTableRevision,
492 This->MinAcpiTableRevision,
493 This->AcpiTableRevision
494 ));
495 return EFI_INVALID_PARAMETER;
496 }
497
498 *Table = NULL;
499 Status = GetEArmObjPlatformGTBlockInfo (
500 CfgMgrProtocol,
501 CM_NULL_TOKEN,
502 &GTBlockInfo,
503 &BlockTimerCount
504 );
505 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
506 DEBUG ((
507 DEBUG_ERROR,
508 "ERROR: GTDT: Failed to Get Platform GT Block Information." \
509 " Status = %r\n",
510 Status
511 ));
512 goto error_handler;
513 }
514
515 Status = GetEArmObjPlatformGenericWatchdogInfo (
516 CfgMgrProtocol,
517 CM_NULL_TOKEN,
518 &WatchdogInfoList,
519 &WatchdogCount
520 );
521 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
522 DEBUG ((
523 DEBUG_ERROR,
524 "ERROR: GTDT: Failed to Get Platform Generic Watchdog Information." \
525 " Status = %r\n",
526 Status
527 ));
528 goto error_handler;
529 }
530
531 DEBUG ((
532 DEBUG_INFO,
533 "GTDT: BlockTimerCount = %d, WatchdogCount = %d\n",
534 BlockTimerCount,
535 WatchdogCount
536 ));
537
538 // Calculate the GTDT Table Size
539 PlatformTimerCount = 0;
540 TableSize = sizeof (EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE);
541 if (BlockTimerCount != 0) {
542 GTBlockOffset = TableSize;
543 PlatformTimerCount += BlockTimerCount;
544 TableSize += (sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE) *
545 BlockTimerCount);
546
547 for (Idx = 0; Idx < BlockTimerCount; Idx++) {
548 if (GTBlockInfo[Idx].GTBlockTimerFrameCount > 8) {
549 Status = EFI_INVALID_PARAMETER;
550 DEBUG ((
551 DEBUG_ERROR,
552 "GTDT: GTBockFrameCount cannot be more than 8." \
553 " GTBockFrameCount = %d, Status = %r\n",
554 GTBlockInfo[Idx].GTBlockTimerFrameCount,
555 Status
556 ));
557 goto error_handler;
558 }
559 TableSize += (sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_STRUCTURE) *
560 GTBlockInfo[Idx].GTBlockTimerFrameCount);
561 }
562
563 DEBUG ((
564 DEBUG_INFO,
565 "GTDT: GTBockOffset = 0x%x, PLATFORM_TIMER_COUNT = %d\n",
566 GTBlockOffset,
567 PlatformTimerCount
568 ));
569 }
570
571 WatchdogOffset = 0;
572 if (WatchdogCount != 0) {
573 WatchdogOffset = TableSize;
574 PlatformTimerCount += WatchdogCount;
575 TableSize += (sizeof (EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE) *
576 WatchdogCount);
577 DEBUG ((
578 DEBUG_INFO,
579 "GTDT: WatchdogOffset = 0x%x, PLATFORM_TIMER_COUNT = %d\n",
580 WatchdogOffset,
581 PlatformTimerCount
582 ));
583 }
584
585 *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);
586 if (*Table == NULL) {
587 Status = EFI_OUT_OF_RESOURCES;
588 DEBUG ((
589 DEBUG_ERROR,
590 "ERROR: GTDT: Failed to allocate memory for GTDT Table, Size = %d," \
591 " Status = %r\n",
592 TableSize,
593 Status
594 ));
595 goto error_handler;
596 }
597
598 Gtdt = (EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE*)*Table;
599 DEBUG ((
600 DEBUG_INFO,
601 "GTDT: Gtdt = 0x%p TableSize = 0x%x\n",
602 Gtdt,
603 TableSize
604 ));
605
606 Status = AddAcpiHeader (
607 CfgMgrProtocol,
608 This,
609 &Gtdt->Header,
610 AcpiTableInfo,
611 TableSize
612 );
613 if (EFI_ERROR (Status)) {
614 DEBUG ((
615 DEBUG_ERROR,
616 "ERROR: GTDT: Failed to add ACPI header. Status = %r\n",
617 Status
618 ));
619 goto error_handler;
620 }
621
622 Status = AddGenericTimerInfo (
623 CfgMgrProtocol,
624 Gtdt,
625 PlatformTimerCount,
626 AcpiTableInfo->AcpiTableRevision
627 );
628 if (EFI_ERROR (Status)) {
629 DEBUG ((
630 DEBUG_ERROR,
631 "ERROR: GTDT: Failed to add Generic Timer Info. Status = %r\n",
632 Status
633 ));
634 goto error_handler;
635 }
636
637 if (BlockTimerCount != 0) {
638 Status = AddGTBlockList (
639 CfgMgrProtocol,
640 Gtdt,
641 GTBlockOffset,
642 GTBlockInfo,
643 BlockTimerCount
644 );
645 if (EFI_ERROR (Status)) {
646 DEBUG ((
647 DEBUG_ERROR,
648 "ERROR: GTDT: Failed to add GT Block timers. Status = %r\n",
649 Status
650 ));
651 goto error_handler;
652 }
653 }
654
655 if (WatchdogCount != 0) {
656 AddGenericWatchdogList (
657 Gtdt,
658 WatchdogOffset,
659 WatchdogInfoList,
660 WatchdogCount
661 );
662 }
663
664 return Status;
665
666 error_handler:
667 if (*Table != NULL) {
668 FreePool (*Table);
669 *Table = NULL;
670 }
671 return Status;
672 }
673
674 /** Free any resources allocated for constructing the GTDT.
675
676 @param [in] This Pointer to the table generator.
677 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
678 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
679 Protocol Interface.
680 @param [in, out] Table Pointer to the ACPI Table.
681
682 @retval EFI_SUCCESS The resources were freed successfully.
683 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
684 **/
685 STATIC
686 EFI_STATUS
687 FreeGtdtTableResources (
688 IN CONST ACPI_TABLE_GENERATOR * CONST This,
689 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
690 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
691 IN OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table
692 )
693 {
694 ASSERT (This != NULL);
695 ASSERT (AcpiTableInfo != NULL);
696 ASSERT (CfgMgrProtocol != NULL);
697 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
698 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
699
700 if ((Table == NULL) || (*Table == NULL)) {
701 DEBUG ((DEBUG_ERROR, "ERROR: GTDT: Invalid Table Pointer\n"));
702 ASSERT ((Table != NULL) && (*Table != NULL));
703 return EFI_INVALID_PARAMETER;
704 }
705
706 FreePool (*Table);
707 *Table = NULL;
708 return EFI_SUCCESS;
709 }
710
711 /** This macro defines the GTDT Table Generator revision.
712 */
713 #define GTDT_GENERATOR_REVISION CREATE_REVISION (1, 0)
714
715 /** The interface for the GTDT Table Generator.
716 */
717 STATIC
718 CONST
719 ACPI_TABLE_GENERATOR GtdtGenerator = {
720 // Generator ID
721 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdGtdt),
722 // Generator Description
723 L"ACPI.STD.GTDT.GENERATOR",
724 // ACPI Table Signature
725 EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE,
726 // ACPI Table Revision supported by this Generator
727 EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION,
728 // Minimum ACPI Table Revision supported by this Generator
729 EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION,
730 // Creator ID
731 TABLE_GENERATOR_CREATOR_ID_ARM,
732 // Creator Revision
733 GTDT_GENERATOR_REVISION,
734 // Build Table function
735 BuildGtdtTable,
736 // Free Resource function
737 FreeGtdtTableResources,
738 // Extended build function not needed
739 NULL,
740 // Extended build function not implemented by the generator.
741 // Hence extended free resource function is not required.
742 NULL
743 };
744
745 /** Register the Generator with the ACPI Table Factory.
746
747 @param [in] ImageHandle The handle to the image.
748 @param [in] SystemTable Pointer to the System Table.
749
750 @retval EFI_SUCCESS The Generator is registered.
751 @retval EFI_INVALID_PARAMETER A parameter is invalid.
752 @retval EFI_ALREADY_STARTED The Generator for the Table ID
753 is already registered.
754 **/
755 EFI_STATUS
756 EFIAPI
757 AcpiGtdtLibConstructor (
758 IN EFI_HANDLE ImageHandle,
759 IN EFI_SYSTEM_TABLE * SystemTable
760 )
761 {
762 EFI_STATUS Status;
763 Status = RegisterAcpiTableGenerator (&GtdtGenerator);
764 DEBUG ((DEBUG_INFO, "GTDT: Register Generator. Status = %r\n", Status));
765 ASSERT_EFI_ERROR (Status);
766 return Status;
767 }
768
769 /** Deregister the Generator from the ACPI Table Factory.
770
771 @param [in] ImageHandle The handle to the image.
772 @param [in] SystemTable Pointer to the System Table.
773
774 @retval EFI_SUCCESS The Generator is deregistered.
775 @retval EFI_INVALID_PARAMETER A parameter is invalid.
776 @retval EFI_NOT_FOUND The Generator is not registered.
777 **/
778 EFI_STATUS
779 EFIAPI
780 AcpiGtdtLibDestructor (
781 IN EFI_HANDLE ImageHandle,
782 IN EFI_SYSTEM_TABLE * SystemTable
783 )
784 {
785 EFI_STATUS Status;
786 Status = DeregisterAcpiTableGenerator (&GtdtGenerator);
787 DEBUG ((DEBUG_INFO, "GTDT: Deregister Generator. Status = %r\n", Status));
788 ASSERT_EFI_ERROR (Status);
789 return Status;
790 }