]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiGtdtLibArm / GtdtGenerator.c
1 /** @file
2 GTDT Table Generator
3
4 Copyright (c) 2017 - 2021, ARM Limited. All rights reserved.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 @par Reference(s):
8 - ACPI 6.4 Specification - January 2021
9
10 **/
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 Arm 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_4_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_4_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 Arm 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_4_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_4_GTDT_ARM_GENERIC_WATCHDOG_STRUCTURE *Watchdog;
164
165 ASSERT (Gtdt != NULL);
166 ASSERT (WatchdogInfoList != NULL);
167
168 Watchdog = (EFI_ACPI_6_4_GTDT_ARM_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_4_GTDT_ARM_GENERIC_WATCHDOG;
175 Watchdog->Length =
176 sizeof (EFI_ACPI_6_4_GTDT_ARM_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_4_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 IsFrameNumberDuplicated = FindDuplicateValue (
263 GTBlockTimerFrameList,
264 GTBlockFrameCount,
265 sizeof (CM_ARM_GTBLOCK_TIMER_FRAME_INFO),
266 IsGtFrameNumberEqual
267 );
268 // Duplicate entry was found so timer frame numbers provided are invalid
269 if (IsFrameNumberDuplicated) {
270 return EFI_INVALID_PARAMETER;
271 }
272
273 while (GTBlockFrameCount-- != 0) {
274 DEBUG ((
275 DEBUG_INFO,
276 "GTDT: GtBlockFrame = 0x%p\n",
277 GtBlockFrame
278 ));
279
280 if (GTBlockTimerFrameList->FrameNumber >= 8) {
281 DEBUG ((
282 DEBUG_ERROR,
283 "ERROR: GTDT: Frame number %d is not in the range 0-7\n",
284 GTBlockTimerFrameList->FrameNumber
285 ));
286 return EFI_INVALID_PARAMETER;
287 }
288
289 GtBlockFrame->GTFrameNumber = GTBlockTimerFrameList->FrameNumber;
290 GtBlockFrame->Reserved[0] = EFI_ACPI_RESERVED_BYTE;
291 GtBlockFrame->Reserved[1] = EFI_ACPI_RESERVED_BYTE;
292 GtBlockFrame->Reserved[2] = EFI_ACPI_RESERVED_BYTE;
293
294 GtBlockFrame->CntBaseX = GTBlockTimerFrameList->PhysicalAddressCntBase;
295 GtBlockFrame->CntEL0BaseX =
296 GTBlockTimerFrameList->PhysicalAddressCntEL0Base;
297
298 GtBlockFrame->GTxPhysicalTimerGSIV =
299 GTBlockTimerFrameList->PhysicalTimerGSIV;
300 GtBlockFrame->GTxPhysicalTimerFlags =
301 GTBlockTimerFrameList->PhysicalTimerFlags;
302
303 GtBlockFrame->GTxVirtualTimerGSIV = GTBlockTimerFrameList->VirtualTimerGSIV;
304 GtBlockFrame->GTxVirtualTimerFlags =
305 GTBlockTimerFrameList->VirtualTimerFlags;
306
307 GtBlockFrame->GTxCommonFlags = GTBlockTimerFrameList->CommonFlags;
308 GtBlockFrame++;
309 GTBlockTimerFrameList++;
310 } // for
311
312 return EFI_SUCCESS;
313 }
314
315 /** Add the GT Block Timers in the GTDT Table.
316
317 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
318 Protocol Interface.
319 @param [in] Gtdt Pointer to the GTDT Table.
320 @param [in] GTBlockOffset Offset of the GT Block
321 information in the GTDT Table.
322 @param [in] GTBlockInfo Pointer to the GT Block
323 Information List.
324 @param [in] BlockTimerCount Number of GT Block Timers.
325
326 @retval EFI_SUCCESS Table generated successfully.
327 @retval EFI_INVALID_PARAMETER A parameter is invalid.
328 **/
329 STATIC
330 EFI_STATUS
331 AddGTBlockList (
332 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
333 IN EFI_ACPI_6_4_GENERIC_TIMER_DESCRIPTION_TABLE *CONST Gtdt,
334 IN CONST UINT32 GTBlockOffset,
335 IN CONST CM_ARM_GTBLOCK_INFO *GTBlockInfo,
336 IN UINT32 BlockTimerCount
337 )
338 {
339 EFI_STATUS Status;
340 EFI_ACPI_6_4_GTDT_GT_BLOCK_STRUCTURE *GTBlock;
341 EFI_ACPI_6_4_GTDT_GT_BLOCK_TIMER_STRUCTURE *GtBlockFrame;
342 CM_ARM_GTBLOCK_TIMER_FRAME_INFO *GTBlockTimerFrameList;
343 UINT32 GTBlockTimerFrameCount;
344 UINTN Length;
345
346 ASSERT (Gtdt != NULL);
347 ASSERT (GTBlockInfo != NULL);
348
349 GTBlock = (EFI_ACPI_6_4_GTDT_GT_BLOCK_STRUCTURE *)((UINT8 *)Gtdt +
350 GTBlockOffset);
351
352 while (BlockTimerCount-- != 0) {
353 DEBUG ((DEBUG_INFO, "GTDT: GTBlock = 0x%p\n", GTBlock));
354
355 Status = GetEArmObjGTBlockTimerFrameInfo (
356 CfgMgrProtocol,
357 GTBlockInfo->GTBlockTimerFrameToken,
358 &GTBlockTimerFrameList,
359 &GTBlockTimerFrameCount
360 );
361 if (EFI_ERROR (Status) ||
362 (GTBlockTimerFrameCount != GTBlockInfo->GTBlockTimerFrameCount))
363 {
364 DEBUG ((
365 DEBUG_ERROR,
366 "ERROR: GTDT: Failed to get Generic Timer Frames. Status = %r\n",
367 Status
368 ));
369 return Status;
370 }
371
372 Length = sizeof (EFI_ACPI_6_4_GTDT_GT_BLOCK_STRUCTURE) +
373 (sizeof (EFI_ACPI_6_4_GTDT_GT_BLOCK_TIMER_STRUCTURE) *
374 GTBlockInfo->GTBlockTimerFrameCount);
375
376 // Check that the length of the GT block does not
377 // exceed MAX_UINT16
378 if (Length > MAX_UINT16) {
379 Status = EFI_INVALID_PARAMETER;
380 DEBUG ((
381 DEBUG_ERROR,
382 "ERROR: GTDT: Too many GT Frames. Count = %d. " \
383 "Maximum supported GT Block size exceeded. " \
384 "Status = %r\n",
385 GTBlockInfo->GTBlockTimerFrameCount,
386 Status
387 ));
388 return Status;
389 }
390
391 GTBlock->Type = EFI_ACPI_6_4_GTDT_GT_BLOCK;
392 GTBlock->Length = (UINT16)Length;
393 GTBlock->Reserved = EFI_ACPI_RESERVED_BYTE;
394 GTBlock->CntCtlBase = GTBlockInfo->GTBlockPhysicalAddress;
395 GTBlock->GTBlockTimerCount = GTBlockInfo->GTBlockTimerFrameCount;
396 GTBlock->GTBlockTimerOffset =
397 sizeof (EFI_ACPI_6_4_GTDT_GT_BLOCK_STRUCTURE);
398
399 GtBlockFrame = (EFI_ACPI_6_4_GTDT_GT_BLOCK_TIMER_STRUCTURE *)
400 ((UINT8 *)GTBlock + GTBlock->GTBlockTimerOffset);
401
402 // Add GT Block Timer frames
403 Status = AddGTBlockTimerFrames (
404 GtBlockFrame,
405 GTBlockTimerFrameList,
406 GTBlockTimerFrameCount
407 );
408 if (EFI_ERROR (Status)) {
409 DEBUG ((
410 DEBUG_ERROR,
411 "ERROR: GTDT: Failed to add Generic Timer Frames. Status = %r\n",
412 Status
413 ));
414 return Status;
415 }
416
417 // Next GTBlock
418 GTBlock = (EFI_ACPI_6_4_GTDT_GT_BLOCK_STRUCTURE *)((UINT8 *)GTBlock +
419 GTBlock->Length);
420 GTBlockInfo++;
421 }// for
422
423 return EFI_SUCCESS;
424 }
425
426 /** Construct the GTDT ACPI table.
427
428 Called by the Dynamic Table Manager, this function invokes the
429 Configuration Manager protocol interface to get the required hardware
430 information for generating the ACPI table.
431
432 If this function allocates any resources then they must be freed
433 in the FreeXXXXTableResources function.
434
435 @param [in] This Pointer to the table generator.
436 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
437 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
438 Protocol Interface.
439 @param [out] Table Pointer to the constructed ACPI Table.
440
441 @retval EFI_SUCCESS Table generated successfully.
442 @retval EFI_INVALID_PARAMETER A parameter is invalid.
443 @retval EFI_NOT_FOUND The required object was not found.
444 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
445 Manager is less than the Object size for the
446 requested object.
447 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
448 **/
449 STATIC
450 EFI_STATUS
451 EFIAPI
452 BuildGtdtTable (
453 IN CONST ACPI_TABLE_GENERATOR *CONST This,
454 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
455 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
456 OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table
457 )
458 {
459 EFI_STATUS Status;
460 UINT32 TableSize;
461 UINT32 PlatformTimerCount;
462 UINT32 WatchdogCount;
463 UINT32 BlockTimerCount;
464 CM_ARM_GENERIC_WATCHDOG_INFO *WatchdogInfoList;
465 CM_ARM_GTBLOCK_INFO *GTBlockInfo;
466 EFI_ACPI_6_4_GENERIC_TIMER_DESCRIPTION_TABLE *Gtdt;
467 UINT32 Idx;
468 UINT32 GTBlockOffset;
469 UINT32 WatchdogOffset;
470
471 ASSERT (This != NULL);
472 ASSERT (AcpiTableInfo != NULL);
473 ASSERT (CfgMgrProtocol != NULL);
474 ASSERT (Table != NULL);
475 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
476 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
477
478 if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
479 (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision))
480 {
481 DEBUG ((
482 DEBUG_ERROR,
483 "ERROR: GTDT: Requested table revision = %d, is not supported."
484 "Supported table revision: Minimum = %d, Maximum = %d\n",
485 AcpiTableInfo->AcpiTableRevision,
486 This->MinAcpiTableRevision,
487 This->AcpiTableRevision
488 ));
489 return EFI_INVALID_PARAMETER;
490 }
491
492 *Table = NULL;
493 Status = GetEArmObjPlatformGTBlockInfo (
494 CfgMgrProtocol,
495 CM_NULL_TOKEN,
496 &GTBlockInfo,
497 &BlockTimerCount
498 );
499 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
500 DEBUG ((
501 DEBUG_ERROR,
502 "ERROR: GTDT: Failed to Get Platform GT Block Information." \
503 " Status = %r\n",
504 Status
505 ));
506 goto error_handler;
507 }
508
509 Status = GetEArmObjPlatformGenericWatchdogInfo (
510 CfgMgrProtocol,
511 CM_NULL_TOKEN,
512 &WatchdogInfoList,
513 &WatchdogCount
514 );
515 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
516 DEBUG ((
517 DEBUG_ERROR,
518 "ERROR: GTDT: Failed to Get Platform Generic Watchdog Information." \
519 " Status = %r\n",
520 Status
521 ));
522 goto error_handler;
523 }
524
525 DEBUG ((
526 DEBUG_INFO,
527 "GTDT: BlockTimerCount = %d, WatchdogCount = %d\n",
528 BlockTimerCount,
529 WatchdogCount
530 ));
531
532 // Calculate the GTDT Table Size
533 PlatformTimerCount = 0;
534 TableSize = sizeof (EFI_ACPI_6_4_GENERIC_TIMER_DESCRIPTION_TABLE);
535 if (BlockTimerCount != 0) {
536 GTBlockOffset = TableSize;
537 PlatformTimerCount += BlockTimerCount;
538 TableSize += (sizeof (EFI_ACPI_6_4_GTDT_GT_BLOCK_STRUCTURE) *
539 BlockTimerCount);
540
541 for (Idx = 0; Idx < BlockTimerCount; Idx++) {
542 if (GTBlockInfo[Idx].GTBlockTimerFrameCount > 8) {
543 Status = EFI_INVALID_PARAMETER;
544 DEBUG ((
545 DEBUG_ERROR,
546 "GTDT: GTBockFrameCount cannot be more than 8." \
547 " GTBockFrameCount = %d, Status = %r\n",
548 GTBlockInfo[Idx].GTBlockTimerFrameCount,
549 Status
550 ));
551 goto error_handler;
552 }
553
554 TableSize += (sizeof (EFI_ACPI_6_4_GTDT_GT_BLOCK_TIMER_STRUCTURE) *
555 GTBlockInfo[Idx].GTBlockTimerFrameCount);
556 }
557
558 DEBUG ((
559 DEBUG_INFO,
560 "GTDT: GTBockOffset = 0x%x, PLATFORM_TIMER_COUNT = %d\n",
561 GTBlockOffset,
562 PlatformTimerCount
563 ));
564 }
565
566 WatchdogOffset = 0;
567 if (WatchdogCount != 0) {
568 WatchdogOffset = TableSize;
569 PlatformTimerCount += WatchdogCount;
570 TableSize += (sizeof (EFI_ACPI_6_4_GTDT_ARM_GENERIC_WATCHDOG_STRUCTURE) *
571 WatchdogCount);
572 DEBUG ((
573 DEBUG_INFO,
574 "GTDT: WatchdogOffset = 0x%x, PLATFORM_TIMER_COUNT = %d\n",
575 WatchdogOffset,
576 PlatformTimerCount
577 ));
578 }
579
580 *Table = (EFI_ACPI_DESCRIPTION_HEADER *)AllocateZeroPool (TableSize);
581 if (*Table == NULL) {
582 Status = EFI_OUT_OF_RESOURCES;
583 DEBUG ((
584 DEBUG_ERROR,
585 "ERROR: GTDT: Failed to allocate memory for GTDT Table, Size = %d," \
586 " Status = %r\n",
587 TableSize,
588 Status
589 ));
590 goto error_handler;
591 }
592
593 Gtdt = (EFI_ACPI_6_4_GENERIC_TIMER_DESCRIPTION_TABLE *)*Table;
594 DEBUG ((
595 DEBUG_INFO,
596 "GTDT: Gtdt = 0x%p TableSize = 0x%x\n",
597 Gtdt,
598 TableSize
599 ));
600
601 Status = AddAcpiHeader (
602 CfgMgrProtocol,
603 This,
604 &Gtdt->Header,
605 AcpiTableInfo,
606 TableSize
607 );
608 if (EFI_ERROR (Status)) {
609 DEBUG ((
610 DEBUG_ERROR,
611 "ERROR: GTDT: Failed to add ACPI header. Status = %r\n",
612 Status
613 ));
614 goto error_handler;
615 }
616
617 Status = AddGenericTimerInfo (
618 CfgMgrProtocol,
619 Gtdt,
620 PlatformTimerCount,
621 AcpiTableInfo->AcpiTableRevision
622 );
623 if (EFI_ERROR (Status)) {
624 DEBUG ((
625 DEBUG_ERROR,
626 "ERROR: GTDT: Failed to add Generic Timer Info. Status = %r\n",
627 Status
628 ));
629 goto error_handler;
630 }
631
632 if (BlockTimerCount != 0) {
633 Status = AddGTBlockList (
634 CfgMgrProtocol,
635 Gtdt,
636 GTBlockOffset,
637 GTBlockInfo,
638 BlockTimerCount
639 );
640 if (EFI_ERROR (Status)) {
641 DEBUG ((
642 DEBUG_ERROR,
643 "ERROR: GTDT: Failed to add GT Block timers. Status = %r\n",
644 Status
645 ));
646 goto error_handler;
647 }
648 }
649
650 if (WatchdogCount != 0) {
651 AddGenericWatchdogList (
652 Gtdt,
653 WatchdogOffset,
654 WatchdogInfoList,
655 WatchdogCount
656 );
657 }
658
659 return Status;
660
661 error_handler:
662 if (*Table != NULL) {
663 FreePool (*Table);
664 *Table = NULL;
665 }
666
667 return Status;
668 }
669
670 /** Free any resources allocated for constructing the GTDT.
671
672 @param [in] This Pointer to the table generator.
673 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
674 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
675 Protocol Interface.
676 @param [in, out] Table Pointer to the ACPI Table.
677
678 @retval EFI_SUCCESS The resources were freed successfully.
679 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
680 **/
681 STATIC
682 EFI_STATUS
683 FreeGtdtTableResources (
684 IN CONST ACPI_TABLE_GENERATOR *CONST This,
685 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
686 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
687 IN OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table
688 )
689 {
690 ASSERT (This != NULL);
691 ASSERT (AcpiTableInfo != NULL);
692 ASSERT (CfgMgrProtocol != NULL);
693 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
694 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
695
696 if ((Table == NULL) || (*Table == NULL)) {
697 DEBUG ((DEBUG_ERROR, "ERROR: GTDT: Invalid Table Pointer\n"));
698 ASSERT ((Table != NULL) && (*Table != NULL));
699 return EFI_INVALID_PARAMETER;
700 }
701
702 FreePool (*Table);
703 *Table = NULL;
704 return EFI_SUCCESS;
705 }
706
707 /** This macro defines the GTDT Table Generator revision.
708 */
709 #define GTDT_GENERATOR_REVISION CREATE_REVISION (1, 0)
710
711 /** The interface for the GTDT Table Generator.
712 */
713 STATIC
714 CONST
715 ACPI_TABLE_GENERATOR GtdtGenerator = {
716 // Generator ID
717 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdGtdt),
718 // Generator Description
719 L"ACPI.STD.GTDT.GENERATOR",
720 // ACPI Table Signature
721 EFI_ACPI_6_4_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE,
722 // ACPI Table Revision supported by this Generator
723 EFI_ACPI_6_4_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION,
724 // Minimum ACPI Table Revision supported by this Generator
725 EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION,
726 // Creator ID
727 TABLE_GENERATOR_CREATOR_ID_ARM,
728 // Creator Revision
729 GTDT_GENERATOR_REVISION,
730 // Build Table function
731 BuildGtdtTable,
732 // Free Resource function
733 FreeGtdtTableResources,
734 // Extended build function not needed
735 NULL,
736 // Extended build function not implemented by the generator.
737 // Hence extended free resource function is not required.
738 NULL
739 };
740
741 /** Register the Generator with the ACPI Table Factory.
742
743 @param [in] ImageHandle The handle to the image.
744 @param [in] SystemTable Pointer to the System Table.
745
746 @retval EFI_SUCCESS The Generator is registered.
747 @retval EFI_INVALID_PARAMETER A parameter is invalid.
748 @retval EFI_ALREADY_STARTED The Generator for the Table ID
749 is already registered.
750 **/
751 EFI_STATUS
752 EFIAPI
753 AcpiGtdtLibConstructor (
754 IN EFI_HANDLE ImageHandle,
755 IN EFI_SYSTEM_TABLE *SystemTable
756 )
757 {
758 EFI_STATUS Status;
759
760 Status = RegisterAcpiTableGenerator (&GtdtGenerator);
761 DEBUG ((DEBUG_INFO, "GTDT: Register Generator. Status = %r\n", Status));
762 ASSERT_EFI_ERROR (Status);
763 return Status;
764 }
765
766 /** Deregister the Generator from the ACPI Table Factory.
767
768 @param [in] ImageHandle The handle to the image.
769 @param [in] SystemTable Pointer to the System Table.
770
771 @retval EFI_SUCCESS The Generator is deregistered.
772 @retval EFI_INVALID_PARAMETER A parameter is invalid.
773 @retval EFI_NOT_FOUND The Generator is not registered.
774 **/
775 EFI_STATUS
776 EFIAPI
777 AcpiGtdtLibDestructor (
778 IN EFI_HANDLE ImageHandle,
779 IN EFI_SYSTEM_TABLE *SystemTable
780 )
781 {
782 EFI_STATUS Status;
783
784 Status = DeregisterAcpiTableGenerator (&GtdtGenerator);
785 DEBUG ((DEBUG_INFO, "GTDT: Deregister Generator. Status = %r\n", Status));
786 ASSERT_EFI_ERROR (Status);
787 return Status;
788 }