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 MADT Generator
33 The following Configuration Manager Object(s) are required by
37 - EArmObjGicMsiFrameInfo (OPTIONAL)
38 - EArmObjGicRedistributorInfo (OPTIONAL)
39 - EArmObjGicItsInfo (OPTIONAL)
42 /** This macro expands to a function that retrieves the GIC
43 CPU interface Information from the Configuration Manager.
51 /** This macro expands to a function that retrieves the GIC
52 Distributor Information from the Configuration Manager.
61 /** This macro expands to a function that retrieves the GIC
62 MSI Frame Information from the Configuration Manager.
66 EArmObjGicMsiFrameInfo
,
67 CM_ARM_GIC_MSI_FRAME_INFO
70 /** This macro expands to a function that retrieves the GIC
71 Redistributor Information from the Configuration Manager.
76 EArmObjGicRedistributorInfo
,
77 CM_ARM_GIC_REDIST_INFO
80 /** This macro expands to a function that retrieves the GIC
81 Interrupt Translation Service Information from the
82 Configuration Manager.
90 /** This function updates the GIC CPU Interface Information in the
91 EFI_ACPI_6_2_GIC_STRUCTURE structure.
93 @param [in] Gicc Pointer to GIC CPU Interface structure.
94 @param [in] GicCInfo Pointer to the GIC CPU Interface Information.
99 IN EFI_ACPI_6_2_GIC_STRUCTURE
* CONST Gicc
,
100 IN CONST CM_ARM_GICC_INFO
* CONST GicCInfo
103 ASSERT (Gicc
!= NULL
);
104 ASSERT (GicCInfo
!= NULL
);
107 Gicc
->Type
= EFI_ACPI_6_2_GIC
;
109 Gicc
->Length
= sizeof (EFI_ACPI_6_2_GIC_STRUCTURE
);
111 Gicc
->Reserved
= EFI_ACPI_RESERVED_WORD
;
113 // UINT32 CPUInterfaceNumber
114 Gicc
->CPUInterfaceNumber
= GicCInfo
->CPUInterfaceNumber
;
115 // UINT32 AcpiProcessorUid
116 Gicc
->AcpiProcessorUid
= GicCInfo
->AcpiProcessorUid
;
118 Gicc
->Flags
= GicCInfo
->Flags
;
119 // UINT32 ParkingProtocolVersion
120 Gicc
->ParkingProtocolVersion
= GicCInfo
->ParkingProtocolVersion
;
121 // UINT32 PerformanceInterruptGsiv
122 Gicc
->PerformanceInterruptGsiv
= GicCInfo
->PerformanceInterruptGsiv
;
123 // UINT64 ParkedAddress
124 Gicc
->ParkedAddress
= GicCInfo
->ParkedAddress
;
126 // UINT64 PhysicalBaseAddress
127 Gicc
->PhysicalBaseAddress
= GicCInfo
->PhysicalBaseAddress
;
129 Gicc
->GICV
= GicCInfo
->GICV
;
131 Gicc
->GICH
= GicCInfo
->GICH
;
133 // UINT32 VGICMaintenanceInterrupt
134 Gicc
->VGICMaintenanceInterrupt
= GicCInfo
->VGICMaintenanceInterrupt
;
135 // UINT64 GICRBaseAddress
136 Gicc
->GICRBaseAddress
= GicCInfo
->GICRBaseAddress
;
139 Gicc
->MPIDR
= GicCInfo
->MPIDR
;
140 // UINT8 ProcessorPowerEfficiencyClass
141 Gicc
->ProcessorPowerEfficiencyClass
=
142 GicCInfo
->ProcessorPowerEfficiencyClass
;
143 // UINT8 Reserved2[3]
144 Gicc
->Reserved2
[0] = EFI_ACPI_RESERVED_BYTE
;
145 Gicc
->Reserved2
[1] = EFI_ACPI_RESERVED_BYTE
;
146 Gicc
->Reserved2
[2] = EFI_ACPI_RESERVED_BYTE
;
149 /** Add the GIC CPU Interface Information to the MADT Table.
151 @param [in] Gicc Pointer to GIC CPU Interface
153 @param [in] GicCInfo Pointer to the GIC CPU
155 @param [in] GicCCount Count of GIC CPU Interfaces.
160 IN EFI_ACPI_6_2_GIC_STRUCTURE
* Gicc
,
161 IN CONST CM_ARM_GICC_INFO
* GicCInfo
,
165 ASSERT (Gicc
!= NULL
);
166 ASSERT (GicCInfo
!= NULL
);
168 while (GicCCount
-- != 0) {
169 AddGICC (Gicc
++, GicCInfo
++);
173 /** Update the GIC Distributor Information in the MADT Table.
175 @param [in] Gicd Pointer to GIC Distributor structure.
176 @param [in] GicDInfo Pointer to the GIC Distributor Information.
181 EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE
* CONST Gicd
,
182 CONST CM_ARM_GICD_INFO
* CONST GicDInfo
185 ASSERT (Gicd
!= NULL
);
186 ASSERT (GicDInfo
!= NULL
);
189 Gicd
->Type
= EFI_ACPI_6_2_GICD
;
191 Gicd
->Length
= sizeof (EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE
);
193 Gicd
->Reserved1
= EFI_ACPI_RESERVED_WORD
;
195 // One, and only one, GIC distributor structure must be present
196 // in the MADT for an ARM based system
198 // UINT64 PhysicalBaseAddress
199 Gicd
->PhysicalBaseAddress
= GicDInfo
->PhysicalBaseAddress
;
201 Gicd
->SystemVectorBase
= EFI_ACPI_RESERVED_DWORD
;
203 Gicd
->GicVersion
= GicDInfo
->GicVersion
;
204 // UINT8 Reserved2[3]
205 Gicd
->Reserved2
[0] = EFI_ACPI_RESERVED_BYTE
;
206 Gicd
->Reserved2
[1] = EFI_ACPI_RESERVED_BYTE
;
207 Gicd
->Reserved2
[2] = EFI_ACPI_RESERVED_BYTE
;
210 /** Update the GIC MSI Frame Information.
212 @param [in] GicMsiFrame Pointer to GIC MSI Frame structure.
213 @param [in] GicMsiFrameInfo Pointer to the GIC MSI Frame Information.
218 IN EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE
* CONST GicMsiFrame
,
219 IN CONST CM_ARM_GIC_MSI_FRAME_INFO
* CONST GicMsiFrameInfo
222 ASSERT (GicMsiFrame
!= NULL
);
223 ASSERT (GicMsiFrameInfo
!= NULL
);
225 GicMsiFrame
->Type
= EFI_ACPI_6_2_GIC_MSI_FRAME
;
226 GicMsiFrame
->Length
= sizeof (EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE
);
227 GicMsiFrame
->Reserved1
= EFI_ACPI_RESERVED_WORD
;
228 GicMsiFrame
->GicMsiFrameId
= GicMsiFrameInfo
->GicMsiFrameId
;
229 GicMsiFrame
->PhysicalBaseAddress
= GicMsiFrameInfo
->PhysicalBaseAddress
;
231 GicMsiFrame
->Flags
= GicMsiFrameInfo
->Flags
;
232 GicMsiFrame
->SPICount
= GicMsiFrameInfo
->SPICount
;
233 GicMsiFrame
->SPIBase
= GicMsiFrameInfo
->SPIBase
;
236 /** Add the GIC MSI Frame Information to the MADT Table.
238 @param [in] GicMsiFrame Pointer to GIC MSI Frame structure list.
239 @param [in] GicMsiFrameInfo Pointer to the GIC MSI Frame info list.
240 @param [in] GicMsiFrameCount Count of GIC MSI Frames.
244 AddGICMsiFrameInfoList (
245 IN EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE
* GicMsiFrame
,
246 IN CONST CM_ARM_GIC_MSI_FRAME_INFO
* GicMsiFrameInfo
,
247 IN UINT32 GicMsiFrameCount
250 ASSERT (GicMsiFrame
!= NULL
);
251 ASSERT (GicMsiFrameInfo
!= NULL
);
253 while (GicMsiFrameCount
-- != 0) {
254 AddGICMsiFrame (GicMsiFrame
++, GicMsiFrameInfo
++);
258 /** Update the GIC Redistributor Information.
260 @param [in] Gicr Pointer to GIC Redistributor structure.
261 @param [in] GicRedisributorInfo Pointer to the GIC Redistributor Info.
265 AddGICRedistributor (
266 IN EFI_ACPI_6_2_GICR_STRUCTURE
* CONST Gicr
,
267 IN CONST CM_ARM_GIC_REDIST_INFO
* CONST GicRedisributorInfo
270 ASSERT (Gicr
!= NULL
);
271 ASSERT (GicRedisributorInfo
!= NULL
);
273 Gicr
->Type
= EFI_ACPI_6_2_GICR
;
274 Gicr
->Length
= sizeof (EFI_ACPI_6_2_GICR_STRUCTURE
);
275 Gicr
->Reserved
= EFI_ACPI_RESERVED_WORD
;
276 Gicr
->DiscoveryRangeBaseAddress
=
277 GicRedisributorInfo
->DiscoveryRangeBaseAddress
;
278 Gicr
->DiscoveryRangeLength
= GicRedisributorInfo
->DiscoveryRangeLength
;
281 /** Add the GIC Redistributor Information to the MADT Table.
283 @param [in] Gicr Pointer to GIC Redistributor structure list.
284 @param [in] GicRInfo Pointer to the GIC Distributor info list.
285 @param [in] GicRCount Count of GIC Distributors.
289 AddGICRedistributorList (
290 IN EFI_ACPI_6_2_GICR_STRUCTURE
* Gicr
,
291 IN CONST CM_ARM_GIC_REDIST_INFO
* GicRInfo
,
295 ASSERT (Gicr
!= NULL
);
296 ASSERT (GicRInfo
!= NULL
);
298 while (GicRCount
-- != 0) {
299 AddGICRedistributor (Gicr
++, GicRInfo
++);
303 /** Update the GIC Interrupt Translation Service Information
305 @param [in] GicIts Pointer to GIC ITS structure.
306 @param [in] GicItsInfo Pointer to the GIC ITS Information.
310 AddGICInterruptTranslationService (
311 IN EFI_ACPI_6_2_GIC_ITS_STRUCTURE
* CONST GicIts
,
312 IN CONST CM_ARM_GIC_ITS_INFO
* CONST GicItsInfo
315 ASSERT (GicIts
!= NULL
);
316 ASSERT (GicItsInfo
!= NULL
);
318 GicIts
->Type
= EFI_ACPI_6_2_GIC_ITS
;
319 GicIts
->Length
= sizeof (EFI_ACPI_6_2_GIC_ITS_STRUCTURE
);
320 GicIts
->Reserved
= EFI_ACPI_RESERVED_WORD
;
321 GicIts
->GicItsId
= GicItsInfo
->GicItsId
;
322 GicIts
->PhysicalBaseAddress
= GicItsInfo
->PhysicalBaseAddress
;
323 GicIts
->Reserved2
= EFI_ACPI_RESERVED_DWORD
;
326 /** Add the GIC Interrupt Translation Service Information
329 @param [in] GicIts Pointer to GIC ITS structure list.
330 @param [in] GicItsInfo Pointer to the GIC ITS list.
331 @param [in] GicItsCount Count of GIC ITS.
336 IN EFI_ACPI_6_2_GIC_ITS_STRUCTURE
* GicIts
,
337 IN CONST CM_ARM_GIC_ITS_INFO
* GicItsInfo
,
338 IN UINT32 GicItsCount
341 ASSERT (GicIts
!= NULL
);
342 ASSERT (GicItsInfo
!= NULL
);
344 while (GicItsCount
-- != 0) {
345 AddGICInterruptTranslationService (GicIts
++, GicItsInfo
++);
349 /** Construct the MADT ACPI table.
351 This function invokes the Configuration Manager protocol interface
352 to get the required hardware information for generating the ACPI
355 If this function allocates any resources then they must be freed
356 in the FreeXXXXTableResources function.
358 @param [in] This Pointer to the table generator.
359 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
360 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
362 @param [out] Table Pointer to the constructed ACPI Table.
364 @retval EFI_SUCCESS Table generated successfully.
365 @retval EFI_INVALID_PARAMETER A parameter is invalid.
366 @retval EFI_NOT_FOUND The required object was not found.
367 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
368 Manager is less than the Object size for the
375 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
376 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
377 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
378 OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
386 UINT32 GicRedistCount
;
388 CM_ARM_GICC_INFO
* GicCInfo
;
389 CM_ARM_GICD_INFO
* GicDInfo
;
390 CM_ARM_GIC_MSI_FRAME_INFO
* GicMSIInfo
;
391 CM_ARM_GIC_REDIST_INFO
* GicRedistInfo
;
392 CM_ARM_GIC_ITS_INFO
* GicItsInfo
;
396 UINT32 GicRedistOffset
;
399 EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
* Madt
;
401 ASSERT (This
!= NULL
);
402 ASSERT (AcpiTableInfo
!= NULL
);
403 ASSERT (CfgMgrProtocol
!= NULL
);
404 ASSERT (Table
!= NULL
);
405 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
406 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
408 if ((AcpiTableInfo
->AcpiTableRevision
< This
->MinAcpiTableRevision
) ||
409 (AcpiTableInfo
->AcpiTableRevision
> This
->AcpiTableRevision
)) {
412 "ERROR: MADT: Requested table revision = %d, is not supported."
413 "Supported table revision: Minimum = %d, Maximum = %d\n",
414 AcpiTableInfo
->AcpiTableRevision
,
415 This
->MinAcpiTableRevision
,
416 This
->AcpiTableRevision
418 return EFI_INVALID_PARAMETER
;
423 Status
= GetEArmObjGicCInfo (
429 if (EFI_ERROR (Status
)) {
432 "ERROR: MADT: Failed to get GICC Info. Status = %r\n",
438 if (GicCCount
== 0) {
441 "ERROR: MADT: GIC CPU Interface information not provided.\n"
443 ASSERT (GicCCount
!= 0);
444 Status
= EFI_INVALID_PARAMETER
;
448 Status
= GetEArmObjGicDInfo (
454 if (EFI_ERROR (Status
)) {
457 "ERROR: MADT: Failed to get GICD Info. Status = %r\n",
463 if (GicDCount
== 0) {
466 "ERROR: MADT: GIC Distributor information not provided.\n"
468 ASSERT (GicDCount
!= 0);
469 Status
= EFI_INVALID_PARAMETER
;
476 "ERROR: MADT: One, and only one, GIC distributor must be present."
480 ASSERT (GicDCount
<= 1);
481 Status
= EFI_INVALID_PARAMETER
;
485 Status
= GetEArmObjGicMsiFrameInfo (
491 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
494 "ERROR: MADT: Failed to get GIC MSI Info. Status = %r\n",
500 Status
= GetEArmObjGicRedistributorInfo (
506 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
509 "ERROR: MADT: Failed to get GIC Redistributor Info. Status = %r\n",
515 Status
= GetEArmObjGicItsInfo (
521 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
524 "ERROR: MADT: Failed to get GIC ITS Info. Status = %r\n",
530 TableSize
= sizeof (EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
);
532 GicCOffset
= TableSize
;
533 TableSize
+= (sizeof (EFI_ACPI_6_2_GIC_STRUCTURE
) * GicCCount
);
535 GicDOffset
= TableSize
;
536 TableSize
+= (sizeof (EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE
) * GicDCount
);
538 GicMSIOffset
= TableSize
;
539 TableSize
+= (sizeof (EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE
) * GicMSICount
);
541 GicRedistOffset
= TableSize
;
542 TableSize
+= (sizeof (EFI_ACPI_6_2_GICR_STRUCTURE
) * GicRedistCount
);
544 GicItsOffset
= TableSize
;
545 TableSize
+= (sizeof (EFI_ACPI_6_2_GIC_ITS_STRUCTURE
) * GicItsCount
);
547 // Allocate the Buffer for MADT table
548 *Table
= (EFI_ACPI_DESCRIPTION_HEADER
*)AllocateZeroPool (TableSize
);
549 if (*Table
== NULL
) {
550 Status
= EFI_OUT_OF_RESOURCES
;
553 "ERROR: MADT: Failed to allocate memory for MADT Table, Size = %d," \
561 Madt
= (EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
*)*Table
;
565 "MADT: Madt = 0x%p TableSize = 0x%x\n",
570 Status
= AddAcpiHeader (
577 if (EFI_ERROR (Status
)) {
580 "ERROR: MADT: Failed to add ACPI header. Status = %r\n",
587 (EFI_ACPI_6_2_GIC_STRUCTURE
*)((UINT8
*)Madt
+ GicCOffset
),
593 (EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE
*)((UINT8
*)Madt
+ GicDOffset
),
597 if (GicMSICount
!= 0) {
598 AddGICMsiFrameInfoList (
599 (EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE
*)((UINT8
*)Madt
+ GicMSIOffset
),
605 if (GicRedistCount
!= 0) {
606 AddGICRedistributorList (
607 (EFI_ACPI_6_2_GICR_STRUCTURE
*)((UINT8
*)Madt
+ GicRedistOffset
),
613 if (GicItsCount
!= 0) {
615 (EFI_ACPI_6_2_GIC_ITS_STRUCTURE
*)((UINT8
*)Madt
+ GicItsOffset
),
624 if (*Table
!= NULL
) {
631 /** Free any resources allocated for constructing the MADT
633 @param [in] This Pointer to the table generator.
634 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
635 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
637 @param [in, out] Table Pointer to the ACPI Table.
639 @retval EFI_SUCCESS The resources were freed successfully.
640 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
644 FreeMadtTableResources (
645 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
646 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
647 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
648 IN OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
651 ASSERT (This
!= NULL
);
652 ASSERT (AcpiTableInfo
!= NULL
);
653 ASSERT (CfgMgrProtocol
!= NULL
);
654 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
655 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
657 if ((Table
== NULL
) || (*Table
== NULL
)) {
658 DEBUG ((DEBUG_ERROR
, "ERROR: MADT: Invalid Table Pointer\n"));
659 ASSERT ((Table
!= NULL
) && (*Table
!= NULL
));
660 return EFI_INVALID_PARAMETER
;
668 /** The MADT Table Generator revision.
670 #define MADT_GENERATOR_REVISION CREATE_REVISION (1, 0)
672 /** The interface for the MADT Table Generator.
676 ACPI_TABLE_GENERATOR MadtGenerator
= {
678 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdMadt
),
679 // Generator Description
680 L
"ACPI.STD.MADT.GENERATOR",
681 // ACPI Table Signature
682 EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE
,
683 // ACPI Table Revision supported by this Generator
684 EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION
,
685 // Minimum supported ACPI Table Revision
686 EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION
,
688 TABLE_GENERATOR_CREATOR_ID_ARM
,
690 MADT_GENERATOR_REVISION
,
691 // Build Table function
693 // Free Resource function
694 FreeMadtTableResources
,
695 // Extended build function not needed
697 // Extended build function not implemented by the generator.
698 // Hence extended free resource function is not required.
702 /** Register the Generator with the ACPI Table Factory.
704 @param [in] ImageHandle The handle to the image.
705 @param [in] SystemTable Pointer to the System Table.
707 @retval EFI_SUCCESS The Generator is registered.
708 @retval EFI_INVALID_PARAMETER A parameter is invalid.
709 @retval EFI_ALREADY_STARTED The Generator for the Table ID
710 is already registered.
714 AcpiMadtLibConstructor (
715 IN CONST EFI_HANDLE ImageHandle
,
716 IN EFI_SYSTEM_TABLE
* CONST SystemTable
720 Status
= RegisterAcpiTableGenerator (&MadtGenerator
);
721 DEBUG ((DEBUG_INFO
, "MADT: Register Generator. Status = %r\n", Status
));
722 ASSERT_EFI_ERROR (Status
);
726 /** Deregister the Generator from the ACPI Table Factory.
728 @param [in] ImageHandle The handle to the image.
729 @param [in] SystemTable Pointer to the System Table.
731 @retval EFI_SUCCESS The Generator is deregistered.
732 @retval EFI_INVALID_PARAMETER A parameter is invalid.
733 @retval EFI_NOT_FOUND The Generator is not registered.
737 AcpiMadtLibDestructor (
738 IN CONST EFI_HANDLE ImageHandle
,
739 IN EFI_SYSTEM_TABLE
* CONST SystemTable
743 Status
= DeregisterAcpiTableGenerator (&MadtGenerator
);
744 DEBUG ((DEBUG_INFO
, "MADT: Deregister Generator. Status = %r\n", Status
));
745 ASSERT_EFI_ERROR (Status
);