4 Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 - ACPI 6.2 Specification - Errata A, September 2017
18 #include <Library/AcpiLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/MemoryAllocationLib.h>
21 #include <Protocol/AcpiTable.h>
23 // Module specific include files.
24 #include <AcpiTableGenerator.h>
25 #include <ConfigurationManagerObject.h>
26 #include <ConfigurationManagerHelper.h>
27 #include <Library/TableHelperLib.h>
28 #include <Protocol/ConfigurationManagerProtocol.h>
30 /** ARM standard GTDT Generator
33 The following Configuration Manager Object(s) are required by
35 - EArmObjGenericTimerInfo
36 - EArmObjPlatformGenericWatchdogInfo (OPTIONAL)
37 - EArmObjPlatformGTBlockInfo (OPTIONAL)
38 - EArmObjGTBlockTimerFrameInfo (OPTIONAL)
41 /** This macro expands to a function that retrieves the Generic
42 Timer Information from the Configuration Manager.
46 EArmObjGenericTimerInfo
,
47 CM_ARM_GENERIC_TIMER_INFO
50 /** This macro expands to a function that retrieves the SBSA Generic
51 Watchdog Timer Information from the Configuration Manager.
55 EArmObjPlatformGenericWatchdogInfo
,
56 CM_ARM_GENERIC_WATCHDOG_INFO
59 /** This macro expands to a function that retrieves the Platform Generic
60 Timer Block Information from the Configuration Manager.
64 EArmObjPlatformGTBlockInfo
,
68 /** This macro expands to a function that retrieves the Generic
69 Timer Block Timer Frame Information from the Configuration Manager.
73 EArmObjGTBlockTimerFrameInfo
,
74 CM_ARM_GTBLOCK_TIMER_FRAME_INFO
77 /** Add the Generic Timer Information to the GTDT table.
79 Also update the Platform Timer offset information if the platform
80 implements platform timers.
82 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
84 @param [in] Gtdt Pointer to the GTDT Table.
85 @param [in] PlatformTimerCount Platform timer count.
87 @retval EFI_SUCCESS Success.
88 @retval EFI_INVALID_PARAMETER A parameter is invalid.
89 @retval EFI_NOT_FOUND The required object was not found.
90 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
91 Manager is less than the Object size for the
98 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
99 IN EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE
* CONST Gtdt
,
100 IN CONST UINT32 PlatformTimerCount
104 CM_ARM_GENERIC_TIMER_INFO
* GenericTimerInfo
;
106 ASSERT (CfgMgrProtocol
!= NULL
);
107 ASSERT (Gtdt
!= NULL
);
109 Status
= GetEArmObjGenericTimerInfo (
116 if (EFI_ERROR (Status
)) {
119 "ERROR: GTDT: Failed to get GenericTimerInfo. Status = %r\n",
125 Gtdt
->CntControlBasePhysicalAddress
=
126 GenericTimerInfo
->CounterControlBaseAddress
;
127 Gtdt
->Reserved
= EFI_ACPI_RESERVED_DWORD
;
128 Gtdt
->SecurePL1TimerGSIV
= GenericTimerInfo
->SecurePL1TimerGSIV
;
129 Gtdt
->SecurePL1TimerFlags
= GenericTimerInfo
->SecurePL1TimerFlags
;
130 Gtdt
->NonSecurePL1TimerGSIV
= GenericTimerInfo
->NonSecurePL1TimerGSIV
;
131 Gtdt
->NonSecurePL1TimerFlags
= GenericTimerInfo
->NonSecurePL1TimerFlags
;
132 Gtdt
->VirtualTimerGSIV
= GenericTimerInfo
->VirtualTimerGSIV
;
133 Gtdt
->VirtualTimerFlags
= GenericTimerInfo
->VirtualTimerFlags
;
134 Gtdt
->NonSecurePL2TimerGSIV
= GenericTimerInfo
->NonSecurePL2TimerGSIV
;
135 Gtdt
->NonSecurePL2TimerFlags
= GenericTimerInfo
->NonSecurePL2TimerFlags
;
136 Gtdt
->CntReadBasePhysicalAddress
=
137 GenericTimerInfo
->CounterReadBaseAddress
;
138 Gtdt
->PlatformTimerCount
= PlatformTimerCount
;
139 Gtdt
->PlatformTimerOffset
= (PlatformTimerCount
== 0) ? 0 :
140 sizeof (EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE
);
145 /** Add the SBSA Generic Watchdog Timers to the GTDT table.
147 @param [in] Gtdt Pointer to the GTDT Table.
148 @param [in] WatchdogOffset Offset to the watchdog information in the
150 @param [in] WatchdogInfoList Pointer to the watchdog information list.
151 @param [in] WatchdogCount Platform timer count.
155 AddGenericWatchdogList (
156 IN EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE
* CONST Gtdt
,
157 IN CONST UINT32 WatchdogOffset
,
158 IN CONST CM_ARM_GENERIC_WATCHDOG_INFO
* WatchdogInfoList
,
159 IN UINT32 WatchdogCount
162 EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE
* Watchdog
;
164 ASSERT (Gtdt
!= NULL
);
165 ASSERT (WatchdogInfoList
!= NULL
);
167 Watchdog
= (EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE
*)
168 ((UINT8
*)Gtdt
+ WatchdogOffset
);
170 while (WatchdogCount
-- != 0) {
171 // Add watchdog entry
172 DEBUG ((DEBUG_INFO
, "GTDT: Watchdog = 0x%p\n", Watchdog
));
173 Watchdog
->Type
= EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG
;
175 sizeof (EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE
);
176 Watchdog
->Reserved
= EFI_ACPI_RESERVED_BYTE
;
177 Watchdog
->RefreshFramePhysicalAddress
=
178 WatchdogInfoList
->RefreshFrameAddress
;
179 Watchdog
->WatchdogControlFramePhysicalAddress
=
180 WatchdogInfoList
->ControlFrameAddress
;
181 Watchdog
->WatchdogTimerGSIV
= WatchdogInfoList
->TimerGSIV
;
182 Watchdog
->WatchdogTimerFlags
= WatchdogInfoList
->Flags
;
188 /** Update the GT Block Timer Frame lists in the GTDT Table.
190 @param [in] GtBlockFrame Pointer to the GT Block Frames
192 @param [in] GTBlockTimerFrameList Pointer to the GT Block Frame
194 @param [in] GTBlockFrameCount Number of GT Block Frames.
196 @retval EFI_SUCCESS Table generated successfully.
197 @retval EFI_INVALID_PARAMETER A parameter is invalid.
201 AddGTBlockTimerFrames (
202 IN EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE
* GtBlockFrame
,
203 IN CONST CM_ARM_GTBLOCK_TIMER_FRAME_INFO
* GTBlockTimerFrameList
,
204 IN UINT32 GTBlockFrameCount
207 ASSERT (GtBlockFrame
!= NULL
);
208 ASSERT (GTBlockTimerFrameList
!= NULL
);
210 if (GTBlockFrameCount
> 8) {
213 "ERROR: GTDT: GT Block Frame Count %d is greater than 8\n",
216 ASSERT (GTBlockFrameCount
<= 8);
217 return EFI_INVALID_PARAMETER
;
220 while (GTBlockFrameCount
-- != 0) {
223 "GTDT: GtBlockFrame = 0x%p\n",
227 GtBlockFrame
->GTFrameNumber
= GTBlockTimerFrameList
->FrameNumber
;
228 GtBlockFrame
->Reserved
[0] = EFI_ACPI_RESERVED_BYTE
;
229 GtBlockFrame
->Reserved
[1] = EFI_ACPI_RESERVED_BYTE
;
230 GtBlockFrame
->Reserved
[2] = EFI_ACPI_RESERVED_BYTE
;
232 GtBlockFrame
->CntBaseX
= GTBlockTimerFrameList
->PhysicalAddressCntBase
;
233 GtBlockFrame
->CntEL0BaseX
=
234 GTBlockTimerFrameList
->PhysicalAddressCntEL0Base
;
236 GtBlockFrame
->GTxPhysicalTimerGSIV
=
237 GTBlockTimerFrameList
->PhysicalTimerGSIV
;
238 GtBlockFrame
->GTxPhysicalTimerFlags
=
239 GTBlockTimerFrameList
->PhysicalTimerFlags
;
241 GtBlockFrame
->GTxVirtualTimerGSIV
= GTBlockTimerFrameList
->VirtualTimerGSIV
;
242 GtBlockFrame
->GTxVirtualTimerFlags
=
243 GTBlockTimerFrameList
->VirtualTimerFlags
;
245 GtBlockFrame
->GTxCommonFlags
= GTBlockTimerFrameList
->CommonFlags
;
247 GTBlockTimerFrameList
++;
252 /** Add the GT Block Timers in the GTDT Table.
254 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
256 @param [in] Gtdt Pointer to the GTDT Table.
257 @param [in] GTBlockOffset Offset of the GT Block
258 information in the GTDT Table.
259 @param [in] GTBlockInfo Pointer to the GT Block
261 @param [in] BlockTimerCount Number of GT Block Timers.
263 @retval EFI_SUCCESS Table generated successfully.
264 @retval EFI_INVALID_PARAMETER A parameter is invalid.
269 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
270 IN EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE
* CONST Gtdt
,
271 IN CONST UINT32 GTBlockOffset
,
272 IN CONST CM_ARM_GTBLOCK_INFO
* GTBlockInfo
,
273 IN UINT32 BlockTimerCount
277 EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE
* GTBlock
;
278 EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE
* GtBlockFrame
;
279 CM_ARM_GTBLOCK_TIMER_FRAME_INFO
* GTBlockTimerFrameList
;
280 UINT32 GTBlockTimerFrameCount
;
282 ASSERT (Gtdt
!= NULL
);
283 ASSERT (GTBlockInfo
!= NULL
);
285 GTBlock
= (EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE
*)((UINT8
*)Gtdt
+
288 while (BlockTimerCount
-- != 0) {
289 DEBUG ((DEBUG_INFO
, "GTDT: GTBlock = 0x%p\n", GTBlock
));
291 Status
= GetEArmObjGTBlockTimerFrameInfo (
293 GTBlockInfo
->GTBlockTimerFrameToken
,
294 >BlockTimerFrameList
,
295 >BlockTimerFrameCount
297 if (EFI_ERROR (Status
) ||
298 (GTBlockTimerFrameCount
!= GTBlockInfo
->GTBlockTimerFrameCount
)) {
301 "ERROR: GTDT: Failed to get Generic Timer Frames. Status = %r\n",
307 GTBlock
->Type
= EFI_ACPI_6_2_GTDT_GT_BLOCK
;
308 GTBlock
->Length
= sizeof (EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE
) +
309 (sizeof (EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE
) *
310 GTBlockInfo
->GTBlockTimerFrameCount
);
312 GTBlock
->Reserved
= EFI_ACPI_RESERVED_BYTE
;
313 GTBlock
->CntCtlBase
= GTBlockInfo
->GTBlockPhysicalAddress
;
314 GTBlock
->GTBlockTimerCount
= GTBlockInfo
->GTBlockTimerFrameCount
;
315 GTBlock
->GTBlockTimerOffset
=
316 sizeof (EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE
);
318 GtBlockFrame
= (EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE
*)
319 ((UINT8
*)GTBlock
+ GTBlock
->GTBlockTimerOffset
);
321 // Add GT Block Timer frames
322 Status
= AddGTBlockTimerFrames (
324 GTBlockTimerFrameList
,
325 GTBlockTimerFrameCount
327 if (EFI_ERROR (Status
)) {
330 "ERROR: GTDT: Failed to add Generic Timer Frames. Status = %r\n",
337 GTBlock
= (EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE
*)((UINT8
*)GTBlock
+
344 /** Construct the GTDT ACPI table.
346 Called by the Dynamic Table Manager, this function invokes the
347 Configuration Manager protocol interface to get the required hardware
348 information for generating the ACPI table.
350 If this function allocates any resources then they must be freed
351 in the FreeXXXXTableResources function.
353 @param [in] This Pointer to the table generator.
354 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
355 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
357 @param [out] Table Pointer to the constructed ACPI Table.
359 @retval EFI_SUCCESS Table generated successfully.
360 @retval EFI_INVALID_PARAMETER A parameter is invalid.
361 @retval EFI_NOT_FOUND The required object was not found.
362 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
363 Manager is less than the Object size for the
365 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
371 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
372 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
373 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
374 OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
379 UINT32 PlatformTimerCount
;
380 UINT32 WatchdogCount
;
381 UINT32 BlockTimerCount
;
382 CM_ARM_GENERIC_WATCHDOG_INFO
* WatchdogInfoList
;
383 CM_ARM_GTBLOCK_INFO
* GTBlockInfo
;
384 EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE
* Gtdt
;
386 UINT32 GTBlockOffset
;
387 UINT32 WatchdogOffset
;
389 ASSERT (This
!= NULL
);
390 ASSERT (AcpiTableInfo
!= NULL
);
391 ASSERT (CfgMgrProtocol
!= NULL
);
392 ASSERT (Table
!= NULL
);
393 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
394 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
396 if ((AcpiTableInfo
->AcpiTableRevision
< This
->MinAcpiTableRevision
) ||
397 (AcpiTableInfo
->AcpiTableRevision
> This
->AcpiTableRevision
)) {
400 "ERROR: GTDT: Requested table revision = %d, is not supported."
401 "Supported table revision: Minimum = %d, Maximum = %d\n",
402 AcpiTableInfo
->AcpiTableRevision
,
403 This
->MinAcpiTableRevision
,
404 This
->AcpiTableRevision
406 return EFI_INVALID_PARAMETER
;
410 Status
= GetEArmObjPlatformGTBlockInfo (
416 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
419 "ERROR: GTDT: Failed to Get Platform GT Block Information." \
426 Status
= GetEArmObjPlatformGenericWatchdogInfo (
432 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
435 "ERROR: GTDT: Failed to Get Platform Generic Watchdog Information." \
444 "GTDT: BlockTimerCount = %d, WatchdogCount = %d\n",
449 // Calculate the GTDT Table Size
450 PlatformTimerCount
= 0;
451 TableSize
= sizeof (EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE
);
452 if (BlockTimerCount
!= 0) {
453 GTBlockOffset
= TableSize
;
454 PlatformTimerCount
+= BlockTimerCount
;
455 TableSize
+= (sizeof (EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE
) *
458 for (Idx
= 0; Idx
< BlockTimerCount
; Idx
++) {
459 if (GTBlockInfo
[Idx
].GTBlockTimerFrameCount
> 8) {
460 Status
= EFI_INVALID_PARAMETER
;
463 "GTDT: GTBockFrameCount cannot be more than 8." \
464 " GTBockFrameCount = %d, Status = %r\n",
465 GTBlockInfo
[Idx
].GTBlockTimerFrameCount
,
470 TableSize
+= (sizeof (EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE
) *
471 GTBlockInfo
[Idx
].GTBlockTimerFrameCount
);
476 "GTDT: GTBockOffset = 0x%x, PLATFORM_TIMER_COUNT = %d\n",
483 if (WatchdogCount
!= 0) {
484 WatchdogOffset
= TableSize
;
485 PlatformTimerCount
+= WatchdogCount
;
486 TableSize
+= (sizeof (EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE
) *
490 "GTDT: WatchdogOffset = 0x%x, PLATFORM_TIMER_COUNT = %d\n",
496 *Table
= (EFI_ACPI_DESCRIPTION_HEADER
*)AllocateZeroPool (TableSize
);
497 if (*Table
== NULL
) {
498 Status
= EFI_OUT_OF_RESOURCES
;
501 "ERROR: GTDT: Failed to allocate memory for GTDT Table, Size = %d," \
509 Gtdt
= (EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE
*)*Table
;
512 "GTDT: Gtdt = 0x%p TableSize = 0x%x\n",
517 Status
= AddAcpiHeader (
524 if (EFI_ERROR (Status
)) {
527 "ERROR: GTDT: Failed to add ACPI header. Status = %r\n",
533 Status
= AddGenericTimerInfo (
538 if (EFI_ERROR (Status
)) {
541 "ERROR: GTDT: Failed to add Generic Timer Info. Status = %r\n",
547 if (BlockTimerCount
!= 0) {
548 Status
= AddGTBlockList (
555 if (EFI_ERROR (Status
)) {
558 "ERROR: GTDT: Failed to add GT Block timers. Status = %r\n",
565 if (WatchdogCount
!= 0) {
566 AddGenericWatchdogList (
577 if (*Table
!= NULL
) {
584 /** Free any resources allocated for constructing the GTDT.
586 @param [in] This Pointer to the table generator.
587 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
588 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
590 @param [in, out] Table Pointer to the ACPI Table.
592 @retval EFI_SUCCESS The resources were freed successfully.
593 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
597 FreeGtdtTableResources (
598 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
599 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
600 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
601 IN OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
604 ASSERT (This
!= NULL
);
605 ASSERT (AcpiTableInfo
!= NULL
);
606 ASSERT (CfgMgrProtocol
!= NULL
);
607 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
608 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
610 if ((Table
== NULL
) || (*Table
== NULL
)) {
611 DEBUG ((DEBUG_ERROR
, "ERROR: GTDT: Invalid Table Pointer\n"));
612 ASSERT ((Table
!= NULL
) && (*Table
!= NULL
));
613 return EFI_INVALID_PARAMETER
;
621 /** This macro defines the GTDT Table Generator revision.
623 #define GTDT_GENERATOR_REVISION CREATE_REVISION (1, 0)
625 /** The interface for the GTDT Table Generator.
629 ACPI_TABLE_GENERATOR GtdtGenerator
= {
631 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdGtdt
),
632 // Generator Description
633 L
"ACPI.STD.GTDT.GENERATOR",
634 // ACPI Table Signature
635 EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE
,
636 // ACPI Table Revision supported by this Generator
637 EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION
,
638 // Minimum ACPI Table Revision supported by this Generator
639 EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION
,
641 TABLE_GENERATOR_CREATOR_ID_ARM
,
643 GTDT_GENERATOR_REVISION
,
644 // Build Table function
646 // Free Resource function
647 FreeGtdtTableResources
,
648 // Extended build function not needed
650 // Extended build function not implemented by the generator.
651 // Hence extended free resource function is not required.
655 /** Register the Generator with the ACPI Table Factory.
657 @param [in] ImageHandle The handle to the image.
658 @param [in] SystemTable Pointer to the System Table.
660 @retval EFI_SUCCESS The Generator is registered.
661 @retval EFI_INVALID_PARAMETER A parameter is invalid.
662 @retval EFI_ALREADY_STARTED The Generator for the Table ID
663 is already registered.
667 AcpiGtdtLibConstructor (
668 IN CONST EFI_HANDLE ImageHandle
,
669 IN EFI_SYSTEM_TABLE
* CONST SystemTable
673 Status
= RegisterAcpiTableGenerator (&GtdtGenerator
);
674 DEBUG ((DEBUG_INFO
, "GTDT: Register Generator. Status = %r\n", Status
));
675 ASSERT_EFI_ERROR (Status
);
679 /** Deregister the Generator from the ACPI Table Factory.
681 @param [in] ImageHandle The handle to the image.
682 @param [in] SystemTable Pointer to the System Table.
684 @retval EFI_SUCCESS The Generator is deregistered.
685 @retval EFI_INVALID_PARAMETER A parameter is invalid.
686 @retval EFI_NOT_FOUND The Generator is not registered.
690 AcpiGtdtLibDestructor (
691 IN CONST EFI_HANDLE ImageHandle
,
692 IN EFI_SYSTEM_TABLE
* CONST SystemTable
696 Status
= DeregisterAcpiTableGenerator (&GtdtGenerator
);
697 DEBUG ((DEBUG_INFO
, "GTDT: Deregister Generator. Status = %r\n", Status
));
698 ASSERT_EFI_ERROR (Status
);