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