4 Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
8 - ACPI 6.2 Specification - Errata A, September 2017
12 #include <Library/AcpiLib.h>
13 #include <Library/DebugLib.h>
14 #include <Library/MemoryAllocationLib.h>
15 #include <Protocol/AcpiTable.h>
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>
24 /** ARM standard MADT Generator
27 The following Configuration Manager Object(s) are required by
31 - EArmObjGicMsiFrameInfo (OPTIONAL)
32 - EArmObjGicRedistributorInfo (OPTIONAL)
33 - EArmObjGicItsInfo (OPTIONAL)
36 /** This macro expands to a function that retrieves the GIC
37 CPU interface Information from the Configuration Manager.
45 /** This macro expands to a function that retrieves the GIC
46 Distributor Information from the Configuration Manager.
55 /** This macro expands to a function that retrieves the GIC
56 MSI Frame Information from the Configuration Manager.
60 EArmObjGicMsiFrameInfo
,
61 CM_ARM_GIC_MSI_FRAME_INFO
64 /** This macro expands to a function that retrieves the GIC
65 Redistributor Information from the Configuration Manager.
70 EArmObjGicRedistributorInfo
,
71 CM_ARM_GIC_REDIST_INFO
74 /** This macro expands to a function that retrieves the GIC
75 Interrupt Translation Service Information from the
76 Configuration Manager.
84 /** This function updates the GIC CPU Interface Information in the
85 EFI_ACPI_6_2_GIC_STRUCTURE structure.
87 @param [in] Gicc Pointer to GIC CPU Interface structure.
88 @param [in] GicCInfo Pointer to the GIC CPU Interface Information.
93 IN EFI_ACPI_6_2_GIC_STRUCTURE
* CONST Gicc
,
94 IN CONST CM_ARM_GICC_INFO
* CONST GicCInfo
97 ASSERT (Gicc
!= NULL
);
98 ASSERT (GicCInfo
!= NULL
);
101 Gicc
->Type
= EFI_ACPI_6_2_GIC
;
103 Gicc
->Length
= sizeof (EFI_ACPI_6_2_GIC_STRUCTURE
);
105 Gicc
->Reserved
= EFI_ACPI_RESERVED_WORD
;
107 // UINT32 CPUInterfaceNumber
108 Gicc
->CPUInterfaceNumber
= GicCInfo
->CPUInterfaceNumber
;
109 // UINT32 AcpiProcessorUid
110 Gicc
->AcpiProcessorUid
= GicCInfo
->AcpiProcessorUid
;
112 Gicc
->Flags
= GicCInfo
->Flags
;
113 // UINT32 ParkingProtocolVersion
114 Gicc
->ParkingProtocolVersion
= GicCInfo
->ParkingProtocolVersion
;
115 // UINT32 PerformanceInterruptGsiv
116 Gicc
->PerformanceInterruptGsiv
= GicCInfo
->PerformanceInterruptGsiv
;
117 // UINT64 ParkedAddress
118 Gicc
->ParkedAddress
= GicCInfo
->ParkedAddress
;
120 // UINT64 PhysicalBaseAddress
121 Gicc
->PhysicalBaseAddress
= GicCInfo
->PhysicalBaseAddress
;
123 Gicc
->GICV
= GicCInfo
->GICV
;
125 Gicc
->GICH
= GicCInfo
->GICH
;
127 // UINT32 VGICMaintenanceInterrupt
128 Gicc
->VGICMaintenanceInterrupt
= GicCInfo
->VGICMaintenanceInterrupt
;
129 // UINT64 GICRBaseAddress
130 Gicc
->GICRBaseAddress
= GicCInfo
->GICRBaseAddress
;
133 Gicc
->MPIDR
= GicCInfo
->MPIDR
;
134 // UINT8 ProcessorPowerEfficiencyClass
135 Gicc
->ProcessorPowerEfficiencyClass
=
136 GicCInfo
->ProcessorPowerEfficiencyClass
;
137 // UINT8 Reserved2[3]
138 Gicc
->Reserved2
[0] = EFI_ACPI_RESERVED_BYTE
;
139 Gicc
->Reserved2
[1] = EFI_ACPI_RESERVED_BYTE
;
140 Gicc
->Reserved2
[2] = EFI_ACPI_RESERVED_BYTE
;
143 /** Add the GIC CPU Interface Information to the MADT Table.
145 @param [in] Gicc Pointer to GIC CPU Interface
147 @param [in] GicCInfo Pointer to the GIC CPU
149 @param [in] GicCCount Count of GIC CPU Interfaces.
154 IN EFI_ACPI_6_2_GIC_STRUCTURE
* Gicc
,
155 IN CONST CM_ARM_GICC_INFO
* GicCInfo
,
159 ASSERT (Gicc
!= NULL
);
160 ASSERT (GicCInfo
!= NULL
);
162 while (GicCCount
-- != 0) {
163 AddGICC (Gicc
++, GicCInfo
++);
167 /** Update the GIC Distributor Information in the MADT Table.
169 @param [in] Gicd Pointer to GIC Distributor structure.
170 @param [in] GicDInfo Pointer to the GIC Distributor Information.
175 EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE
* CONST Gicd
,
176 CONST CM_ARM_GICD_INFO
* CONST GicDInfo
179 ASSERT (Gicd
!= NULL
);
180 ASSERT (GicDInfo
!= NULL
);
183 Gicd
->Type
= EFI_ACPI_6_2_GICD
;
185 Gicd
->Length
= sizeof (EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE
);
187 Gicd
->Reserved1
= EFI_ACPI_RESERVED_WORD
;
189 // One, and only one, GIC distributor structure must be present
190 // in the MADT for an ARM based system
192 // UINT64 PhysicalBaseAddress
193 Gicd
->PhysicalBaseAddress
= GicDInfo
->PhysicalBaseAddress
;
195 Gicd
->SystemVectorBase
= EFI_ACPI_RESERVED_DWORD
;
197 Gicd
->GicVersion
= GicDInfo
->GicVersion
;
198 // UINT8 Reserved2[3]
199 Gicd
->Reserved2
[0] = EFI_ACPI_RESERVED_BYTE
;
200 Gicd
->Reserved2
[1] = EFI_ACPI_RESERVED_BYTE
;
201 Gicd
->Reserved2
[2] = EFI_ACPI_RESERVED_BYTE
;
204 /** Update the GIC MSI Frame Information.
206 @param [in] GicMsiFrame Pointer to GIC MSI Frame structure.
207 @param [in] GicMsiFrameInfo Pointer to the GIC MSI Frame Information.
212 IN EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE
* CONST GicMsiFrame
,
213 IN CONST CM_ARM_GIC_MSI_FRAME_INFO
* CONST GicMsiFrameInfo
216 ASSERT (GicMsiFrame
!= NULL
);
217 ASSERT (GicMsiFrameInfo
!= NULL
);
219 GicMsiFrame
->Type
= EFI_ACPI_6_2_GIC_MSI_FRAME
;
220 GicMsiFrame
->Length
= sizeof (EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE
);
221 GicMsiFrame
->Reserved1
= EFI_ACPI_RESERVED_WORD
;
222 GicMsiFrame
->GicMsiFrameId
= GicMsiFrameInfo
->GicMsiFrameId
;
223 GicMsiFrame
->PhysicalBaseAddress
= GicMsiFrameInfo
->PhysicalBaseAddress
;
225 GicMsiFrame
->Flags
= GicMsiFrameInfo
->Flags
;
226 GicMsiFrame
->SPICount
= GicMsiFrameInfo
->SPICount
;
227 GicMsiFrame
->SPIBase
= GicMsiFrameInfo
->SPIBase
;
230 /** Add the GIC MSI Frame Information to the MADT Table.
232 @param [in] GicMsiFrame Pointer to GIC MSI Frame structure list.
233 @param [in] GicMsiFrameInfo Pointer to the GIC MSI Frame info list.
234 @param [in] GicMsiFrameCount Count of GIC MSI Frames.
238 AddGICMsiFrameInfoList (
239 IN EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE
* GicMsiFrame
,
240 IN CONST CM_ARM_GIC_MSI_FRAME_INFO
* GicMsiFrameInfo
,
241 IN UINT32 GicMsiFrameCount
244 ASSERT (GicMsiFrame
!= NULL
);
245 ASSERT (GicMsiFrameInfo
!= NULL
);
247 while (GicMsiFrameCount
-- != 0) {
248 AddGICMsiFrame (GicMsiFrame
++, GicMsiFrameInfo
++);
252 /** Update the GIC Redistributor Information.
254 @param [in] Gicr Pointer to GIC Redistributor structure.
255 @param [in] GicRedisributorInfo Pointer to the GIC Redistributor Info.
259 AddGICRedistributor (
260 IN EFI_ACPI_6_2_GICR_STRUCTURE
* CONST Gicr
,
261 IN CONST CM_ARM_GIC_REDIST_INFO
* CONST GicRedisributorInfo
264 ASSERT (Gicr
!= NULL
);
265 ASSERT (GicRedisributorInfo
!= NULL
);
267 Gicr
->Type
= EFI_ACPI_6_2_GICR
;
268 Gicr
->Length
= sizeof (EFI_ACPI_6_2_GICR_STRUCTURE
);
269 Gicr
->Reserved
= EFI_ACPI_RESERVED_WORD
;
270 Gicr
->DiscoveryRangeBaseAddress
=
271 GicRedisributorInfo
->DiscoveryRangeBaseAddress
;
272 Gicr
->DiscoveryRangeLength
= GicRedisributorInfo
->DiscoveryRangeLength
;
275 /** Add the GIC Redistributor Information to the MADT Table.
277 @param [in] Gicr Pointer to GIC Redistributor structure list.
278 @param [in] GicRInfo Pointer to the GIC Distributor info list.
279 @param [in] GicRCount Count of GIC Distributors.
283 AddGICRedistributorList (
284 IN EFI_ACPI_6_2_GICR_STRUCTURE
* Gicr
,
285 IN CONST CM_ARM_GIC_REDIST_INFO
* GicRInfo
,
289 ASSERT (Gicr
!= NULL
);
290 ASSERT (GicRInfo
!= NULL
);
292 while (GicRCount
-- != 0) {
293 AddGICRedistributor (Gicr
++, GicRInfo
++);
297 /** Update the GIC Interrupt Translation Service Information
299 @param [in] GicIts Pointer to GIC ITS structure.
300 @param [in] GicItsInfo Pointer to the GIC ITS Information.
304 AddGICInterruptTranslationService (
305 IN EFI_ACPI_6_2_GIC_ITS_STRUCTURE
* CONST GicIts
,
306 IN CONST CM_ARM_GIC_ITS_INFO
* CONST GicItsInfo
309 ASSERT (GicIts
!= NULL
);
310 ASSERT (GicItsInfo
!= NULL
);
312 GicIts
->Type
= EFI_ACPI_6_2_GIC_ITS
;
313 GicIts
->Length
= sizeof (EFI_ACPI_6_2_GIC_ITS_STRUCTURE
);
314 GicIts
->Reserved
= EFI_ACPI_RESERVED_WORD
;
315 GicIts
->GicItsId
= GicItsInfo
->GicItsId
;
316 GicIts
->PhysicalBaseAddress
= GicItsInfo
->PhysicalBaseAddress
;
317 GicIts
->Reserved2
= EFI_ACPI_RESERVED_DWORD
;
320 /** Add the GIC Interrupt Translation Service Information
323 @param [in] GicIts Pointer to GIC ITS structure list.
324 @param [in] GicItsInfo Pointer to the GIC ITS list.
325 @param [in] GicItsCount Count of GIC ITS.
330 IN EFI_ACPI_6_2_GIC_ITS_STRUCTURE
* GicIts
,
331 IN CONST CM_ARM_GIC_ITS_INFO
* GicItsInfo
,
332 IN UINT32 GicItsCount
335 ASSERT (GicIts
!= NULL
);
336 ASSERT (GicItsInfo
!= NULL
);
338 while (GicItsCount
-- != 0) {
339 AddGICInterruptTranslationService (GicIts
++, GicItsInfo
++);
343 /** Construct the MADT ACPI table.
345 This function invokes the Configuration Manager protocol interface
346 to get the required hardware information for generating the ACPI
349 If this function allocates any resources then they must be freed
350 in the FreeXXXXTableResources function.
352 @param [in] This Pointer to the table generator.
353 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
354 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
356 @param [out] Table Pointer to the constructed ACPI Table.
358 @retval EFI_SUCCESS Table generated successfully.
359 @retval EFI_INVALID_PARAMETER A parameter is invalid.
360 @retval EFI_NOT_FOUND The required object was not found.
361 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
362 Manager is less than the Object size for the
369 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
370 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
371 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
372 OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
380 UINT32 GicRedistCount
;
382 CM_ARM_GICC_INFO
* GicCInfo
;
383 CM_ARM_GICD_INFO
* GicDInfo
;
384 CM_ARM_GIC_MSI_FRAME_INFO
* GicMSIInfo
;
385 CM_ARM_GIC_REDIST_INFO
* GicRedistInfo
;
386 CM_ARM_GIC_ITS_INFO
* GicItsInfo
;
390 UINT32 GicRedistOffset
;
393 EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
* Madt
;
395 ASSERT (This
!= NULL
);
396 ASSERT (AcpiTableInfo
!= NULL
);
397 ASSERT (CfgMgrProtocol
!= NULL
);
398 ASSERT (Table
!= NULL
);
399 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
400 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
402 if ((AcpiTableInfo
->AcpiTableRevision
< This
->MinAcpiTableRevision
) ||
403 (AcpiTableInfo
->AcpiTableRevision
> This
->AcpiTableRevision
)) {
406 "ERROR: MADT: Requested table revision = %d, is not supported."
407 "Supported table revision: Minimum = %d, Maximum = %d\n",
408 AcpiTableInfo
->AcpiTableRevision
,
409 This
->MinAcpiTableRevision
,
410 This
->AcpiTableRevision
412 return EFI_INVALID_PARAMETER
;
417 Status
= GetEArmObjGicCInfo (
423 if (EFI_ERROR (Status
)) {
426 "ERROR: MADT: Failed to get GICC Info. Status = %r\n",
432 if (GicCCount
== 0) {
435 "ERROR: MADT: GIC CPU Interface information not provided.\n"
437 ASSERT (GicCCount
!= 0);
438 Status
= EFI_INVALID_PARAMETER
;
442 Status
= GetEArmObjGicDInfo (
448 if (EFI_ERROR (Status
)) {
451 "ERROR: MADT: Failed to get GICD Info. Status = %r\n",
457 if (GicDCount
== 0) {
460 "ERROR: MADT: GIC Distributor information not provided.\n"
462 ASSERT (GicDCount
!= 0);
463 Status
= EFI_INVALID_PARAMETER
;
470 "ERROR: MADT: One, and only one, GIC distributor must be present."
474 ASSERT (GicDCount
<= 1);
475 Status
= EFI_INVALID_PARAMETER
;
479 Status
= GetEArmObjGicMsiFrameInfo (
485 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
488 "ERROR: MADT: Failed to get GIC MSI Info. Status = %r\n",
494 Status
= GetEArmObjGicRedistributorInfo (
500 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
503 "ERROR: MADT: Failed to get GIC Redistributor Info. Status = %r\n",
509 Status
= GetEArmObjGicItsInfo (
515 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
518 "ERROR: MADT: Failed to get GIC ITS Info. Status = %r\n",
524 TableSize
= sizeof (EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
);
526 GicCOffset
= TableSize
;
527 TableSize
+= (sizeof (EFI_ACPI_6_2_GIC_STRUCTURE
) * GicCCount
);
529 GicDOffset
= TableSize
;
530 TableSize
+= (sizeof (EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE
) * GicDCount
);
532 GicMSIOffset
= TableSize
;
533 TableSize
+= (sizeof (EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE
) * GicMSICount
);
535 GicRedistOffset
= TableSize
;
536 TableSize
+= (sizeof (EFI_ACPI_6_2_GICR_STRUCTURE
) * GicRedistCount
);
538 GicItsOffset
= TableSize
;
539 TableSize
+= (sizeof (EFI_ACPI_6_2_GIC_ITS_STRUCTURE
) * GicItsCount
);
541 // Allocate the Buffer for MADT table
542 *Table
= (EFI_ACPI_DESCRIPTION_HEADER
*)AllocateZeroPool (TableSize
);
543 if (*Table
== NULL
) {
544 Status
= EFI_OUT_OF_RESOURCES
;
547 "ERROR: MADT: Failed to allocate memory for MADT Table, Size = %d," \
555 Madt
= (EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
*)*Table
;
559 "MADT: Madt = 0x%p TableSize = 0x%x\n",
564 Status
= AddAcpiHeader (
571 if (EFI_ERROR (Status
)) {
574 "ERROR: MADT: Failed to add ACPI header. Status = %r\n",
581 (EFI_ACPI_6_2_GIC_STRUCTURE
*)((UINT8
*)Madt
+ GicCOffset
),
587 (EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE
*)((UINT8
*)Madt
+ GicDOffset
),
591 if (GicMSICount
!= 0) {
592 AddGICMsiFrameInfoList (
593 (EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE
*)((UINT8
*)Madt
+ GicMSIOffset
),
599 if (GicRedistCount
!= 0) {
600 AddGICRedistributorList (
601 (EFI_ACPI_6_2_GICR_STRUCTURE
*)((UINT8
*)Madt
+ GicRedistOffset
),
607 if (GicItsCount
!= 0) {
609 (EFI_ACPI_6_2_GIC_ITS_STRUCTURE
*)((UINT8
*)Madt
+ GicItsOffset
),
618 if (*Table
!= NULL
) {
625 /** Free any resources allocated for constructing the MADT
627 @param [in] This Pointer to the table generator.
628 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
629 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
631 @param [in, out] Table Pointer to the ACPI Table.
633 @retval EFI_SUCCESS The resources were freed successfully.
634 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
638 FreeMadtTableResources (
639 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
640 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
641 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
642 IN OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
645 ASSERT (This
!= NULL
);
646 ASSERT (AcpiTableInfo
!= NULL
);
647 ASSERT (CfgMgrProtocol
!= NULL
);
648 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
649 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
651 if ((Table
== NULL
) || (*Table
== NULL
)) {
652 DEBUG ((DEBUG_ERROR
, "ERROR: MADT: Invalid Table Pointer\n"));
653 ASSERT ((Table
!= NULL
) && (*Table
!= NULL
));
654 return EFI_INVALID_PARAMETER
;
662 /** The MADT Table Generator revision.
664 #define MADT_GENERATOR_REVISION CREATE_REVISION (1, 0)
666 /** The interface for the MADT Table Generator.
670 ACPI_TABLE_GENERATOR MadtGenerator
= {
672 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdMadt
),
673 // Generator Description
674 L
"ACPI.STD.MADT.GENERATOR",
675 // ACPI Table Signature
676 EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE
,
677 // ACPI Table Revision supported by this Generator
678 EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION
,
679 // Minimum supported ACPI Table Revision
680 EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION
,
682 TABLE_GENERATOR_CREATOR_ID_ARM
,
684 MADT_GENERATOR_REVISION
,
685 // Build Table function
687 // Free Resource function
688 FreeMadtTableResources
,
689 // Extended build function not needed
691 // Extended build function not implemented by the generator.
692 // Hence extended free resource function is not required.
696 /** Register the Generator with the ACPI Table Factory.
698 @param [in] ImageHandle The handle to the image.
699 @param [in] SystemTable Pointer to the System Table.
701 @retval EFI_SUCCESS The Generator is registered.
702 @retval EFI_INVALID_PARAMETER A parameter is invalid.
703 @retval EFI_ALREADY_STARTED The Generator for the Table ID
704 is already registered.
708 AcpiMadtLibConstructor (
709 IN CONST EFI_HANDLE ImageHandle
,
710 IN EFI_SYSTEM_TABLE
* CONST SystemTable
714 Status
= RegisterAcpiTableGenerator (&MadtGenerator
);
715 DEBUG ((DEBUG_INFO
, "MADT: Register Generator. Status = %r\n", Status
));
716 ASSERT_EFI_ERROR (Status
);
720 /** Deregister the Generator from the ACPI Table Factory.
722 @param [in] ImageHandle The handle to the image.
723 @param [in] SystemTable Pointer to the System Table.
725 @retval EFI_SUCCESS The Generator is deregistered.
726 @retval EFI_INVALID_PARAMETER A parameter is invalid.
727 @retval EFI_NOT_FOUND The Generator is not registered.
731 AcpiMadtLibDestructor (
732 IN CONST EFI_HANDLE ImageHandle
,
733 IN EFI_SYSTEM_TABLE
* CONST SystemTable
737 Status
= DeregisterAcpiTableGenerator (&MadtGenerator
);
738 DEBUG ((DEBUG_INFO
, "MADT: Deregister Generator. Status = %r\n", Status
));
739 ASSERT_EFI_ERROR (Status
);