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 Gicd
->GicId
= GicDInfo
->GicId
;
196 // UINT64 PhysicalBaseAddress
197 Gicd
->PhysicalBaseAddress
= GicDInfo
->PhysicalBaseAddress
;
199 Gicd
->SystemVectorBase
= EFI_ACPI_RESERVED_DWORD
;
201 Gicd
->GicVersion
= GicDInfo
->GicVersion
;
202 // UINT8 Reserved2[3]
203 Gicd
->Reserved2
[0] = EFI_ACPI_RESERVED_BYTE
;
204 Gicd
->Reserved2
[1] = EFI_ACPI_RESERVED_BYTE
;
205 Gicd
->Reserved2
[2] = EFI_ACPI_RESERVED_BYTE
;
208 /** Update the GIC MSI Frame Information.
210 @param [in] GicMsiFrame Pointer to GIC MSI Frame structure.
211 @param [in] GicMsiFrameInfo Pointer to the GIC MSI Frame Information.
216 IN EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE
* CONST GicMsiFrame
,
217 IN CONST CM_ARM_GIC_MSI_FRAME_INFO
* CONST GicMsiFrameInfo
220 ASSERT (GicMsiFrame
!= NULL
);
221 ASSERT (GicMsiFrameInfo
!= NULL
);
223 GicMsiFrame
->Type
= EFI_ACPI_6_2_GIC_MSI_FRAME
;
224 GicMsiFrame
->Length
= sizeof (EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE
);
225 GicMsiFrame
->Reserved1
= EFI_ACPI_RESERVED_WORD
;
226 GicMsiFrame
->GicMsiFrameId
= GicMsiFrameInfo
->GicMsiFrameId
;
227 GicMsiFrame
->PhysicalBaseAddress
= GicMsiFrameInfo
->PhysicalBaseAddress
;
229 GicMsiFrame
->Flags
= GicMsiFrameInfo
->Flags
;
230 GicMsiFrame
->SPICount
= GicMsiFrameInfo
->SPICount
;
231 GicMsiFrame
->SPIBase
= GicMsiFrameInfo
->SPIBase
;
234 /** Add the GIC MSI Frame Information to the MADT Table.
236 @param [in] GicMsiFrame Pointer to GIC MSI Frame structure list.
237 @param [in] GicMsiFrameInfo Pointer to the GIC MSI Frame info list.
238 @param [in] GicMsiFrameCount Count of GIC MSI Frames.
242 AddGICMsiFrameInfoList (
243 IN EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE
* GicMsiFrame
,
244 IN CONST CM_ARM_GIC_MSI_FRAME_INFO
* GicMsiFrameInfo
,
245 IN UINT32 GicMsiFrameCount
248 ASSERT (GicMsiFrame
!= NULL
);
249 ASSERT (GicMsiFrameInfo
!= NULL
);
251 while (GicMsiFrameCount
-- != 0) {
252 AddGICMsiFrame (GicMsiFrame
++, GicMsiFrameInfo
++);
256 /** Update the GIC Redistributor Information.
258 @param [in] Gicr Pointer to GIC Redistributor structure.
259 @param [in] GicRedisributorInfo Pointer to the GIC Redistributor Info.
263 AddGICRedistributor (
264 IN EFI_ACPI_6_2_GICR_STRUCTURE
* CONST Gicr
,
265 IN CONST CM_ARM_GIC_REDIST_INFO
* CONST GicRedisributorInfo
268 ASSERT (Gicr
!= NULL
);
269 ASSERT (GicRedisributorInfo
!= NULL
);
271 Gicr
->Type
= EFI_ACPI_6_2_GICR
;
272 Gicr
->Length
= sizeof (EFI_ACPI_6_2_GICR_STRUCTURE
);
273 Gicr
->Reserved
= EFI_ACPI_RESERVED_WORD
;
274 Gicr
->DiscoveryRangeBaseAddress
=
275 GicRedisributorInfo
->DiscoveryRangeBaseAddress
;
276 Gicr
->DiscoveryRangeLength
= GicRedisributorInfo
->DiscoveryRangeLength
;
279 /** Add the GIC Redistributor Information to the MADT Table.
281 @param [in] Gicr Pointer to GIC Redistributor structure list.
282 @param [in] GicRInfo Pointer to the GIC Distributor info list.
283 @param [in] GicRCount Count of GIC Distributors.
287 AddGICRedistributorList (
288 IN EFI_ACPI_6_2_GICR_STRUCTURE
* Gicr
,
289 IN CONST CM_ARM_GIC_REDIST_INFO
* GicRInfo
,
293 ASSERT (Gicr
!= NULL
);
294 ASSERT (GicRInfo
!= NULL
);
296 while (GicRCount
-- != 0) {
297 AddGICRedistributor (Gicr
++, GicRInfo
++);
301 /** Update the GIC Interrupt Translation Service Information
303 @param [in] GicIts Pointer to GIC ITS structure.
304 @param [in] GicItsInfo Pointer to the GIC ITS Information.
308 AddGICInterruptTranslationService (
309 IN EFI_ACPI_6_2_GIC_ITS_STRUCTURE
* CONST GicIts
,
310 IN CONST CM_ARM_GIC_ITS_INFO
* CONST GicItsInfo
313 ASSERT (GicIts
!= NULL
);
314 ASSERT (GicItsInfo
!= NULL
);
316 GicIts
->Type
= EFI_ACPI_6_2_GIC_ITS
;
317 GicIts
->Length
= sizeof (EFI_ACPI_6_2_GIC_ITS_STRUCTURE
);
318 GicIts
->Reserved
= EFI_ACPI_RESERVED_WORD
;
319 GicIts
->GicItsId
= GicItsInfo
->GicItsId
;
320 GicIts
->PhysicalBaseAddress
= GicItsInfo
->PhysicalBaseAddress
;
321 GicIts
->Reserved2
= EFI_ACPI_RESERVED_DWORD
;
324 /** Add the GIC Interrupt Translation Service Information
327 @param [in] GicIts Pointer to GIC ITS structure list.
328 @param [in] GicItsInfo Pointer to the GIC ITS list.
329 @param [in] GicItsCount Count of GIC ITS.
334 IN EFI_ACPI_6_2_GIC_ITS_STRUCTURE
* GicIts
,
335 IN CONST CM_ARM_GIC_ITS_INFO
* GicItsInfo
,
336 IN UINT32 GicItsCount
339 ASSERT (GicIts
!= NULL
);
340 ASSERT (GicItsInfo
!= NULL
);
342 while (GicItsCount
-- != 0) {
343 AddGICInterruptTranslationService (GicIts
++, GicItsInfo
++);
347 /** Construct the MADT ACPI table.
349 This function invokes the Configuration Manager protocol interface
350 to get the required hardware information for generating the ACPI
353 If this function allocates any resources then they must be freed
354 in the FreeXXXXTableResources function.
356 @param [in] This Pointer to the table generator.
357 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
358 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
360 @param [out] Table Pointer to the constructed ACPI Table.
362 @retval EFI_SUCCESS Table generated successfully.
363 @retval EFI_INVALID_PARAMETER A parameter is invalid.
364 @retval EFI_NOT_FOUND The required object was not found.
365 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
366 Manager is less than the Object size for the
373 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
374 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
375 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
376 OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
384 UINT32 GicRedistCount
;
386 CM_ARM_GICC_INFO
* GicCInfo
;
387 CM_ARM_GICD_INFO
* GicDInfo
;
388 CM_ARM_GIC_MSI_FRAME_INFO
* GicMSIInfo
;
389 CM_ARM_GIC_REDIST_INFO
* GicRedistInfo
;
390 CM_ARM_GIC_ITS_INFO
* GicItsInfo
;
394 UINT32 GicRedistOffset
;
397 EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
* Madt
;
399 ASSERT (This
!= NULL
);
400 ASSERT (AcpiTableInfo
!= NULL
);
401 ASSERT (CfgMgrProtocol
!= NULL
);
402 ASSERT (Table
!= NULL
);
403 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
404 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
406 if ((AcpiTableInfo
->AcpiTableRevision
< This
->MinAcpiTableRevision
) ||
407 (AcpiTableInfo
->AcpiTableRevision
> This
->AcpiTableRevision
)) {
410 "ERROR: MADT: Requested table revision = %d, is not supported."
411 "Supported table revision: Minimum = %d, Maximum = %d\n",
412 AcpiTableInfo
->AcpiTableRevision
,
413 This
->MinAcpiTableRevision
,
414 This
->AcpiTableRevision
416 return EFI_INVALID_PARAMETER
;
421 Status
= GetEArmObjGicCInfo (
427 if (EFI_ERROR (Status
)) {
430 "ERROR: MADT: Failed to get GICC Info. Status = %r\n",
436 if (GicCCount
== 0) {
439 "ERROR: MADT: GIC CPU Interface information not provided.\n"
441 ASSERT (GicCCount
!= 0);
442 Status
= EFI_INVALID_PARAMETER
;
446 Status
= GetEArmObjGicDInfo (
452 if (EFI_ERROR (Status
)) {
455 "ERROR: MADT: Failed to get GICD Info. Status = %r\n",
461 if (GicDCount
== 0) {
464 "ERROR: MADT: GIC Distributor information not provided.\n"
466 ASSERT (GicDCount
!= 0);
467 Status
= EFI_INVALID_PARAMETER
;
474 "ERROR: MADT: One, and only one, GIC distributor must be present."
478 ASSERT (GicDCount
<= 1);
479 Status
= EFI_INVALID_PARAMETER
;
483 Status
= GetEArmObjGicMsiFrameInfo (
489 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
492 "ERROR: MADT: Failed to get GIC MSI Info. Status = %r\n",
498 Status
= GetEArmObjGicRedistributorInfo (
504 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
507 "ERROR: MADT: Failed to get GIC Redistributor Info. Status = %r\n",
513 Status
= GetEArmObjGicItsInfo (
519 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
522 "ERROR: MADT: Failed to get GIC ITS Info. Status = %r\n",
528 TableSize
= sizeof (EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
);
530 GicCOffset
= TableSize
;
531 TableSize
+= (sizeof (EFI_ACPI_6_2_GIC_STRUCTURE
) * GicCCount
);
533 GicDOffset
= TableSize
;
534 TableSize
+= (sizeof (EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE
) * GicDCount
);
536 GicMSIOffset
= TableSize
;
537 TableSize
+= (sizeof (EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE
) * GicMSICount
);
539 GicRedistOffset
= TableSize
;
540 TableSize
+= (sizeof (EFI_ACPI_6_2_GICR_STRUCTURE
) * GicRedistCount
);
542 GicItsOffset
= TableSize
;
543 TableSize
+= (sizeof (EFI_ACPI_6_2_GIC_ITS_STRUCTURE
) * GicItsCount
);
545 // Allocate the Buffer for MADT table
546 *Table
= (EFI_ACPI_DESCRIPTION_HEADER
*)AllocateZeroPool (TableSize
);
547 if (*Table
== NULL
) {
548 Status
= EFI_OUT_OF_RESOURCES
;
551 "ERROR: MADT: Failed to allocate memory for MADT Table, Size = %d," \
559 Madt
= (EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
*)*Table
;
563 "MADT: Madt = 0x%p TableSize = 0x%x\n",
568 Status
= AddAcpiHeader (
575 if (EFI_ERROR (Status
)) {
578 "ERROR: MADT: Failed to add ACPI header. Status = %r\n",
585 (EFI_ACPI_6_2_GIC_STRUCTURE
*)((UINT8
*)Madt
+ GicCOffset
),
591 (EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE
*)((UINT8
*)Madt
+ GicDOffset
),
595 if (GicMSICount
!= 0) {
596 AddGICMsiFrameInfoList (
597 (EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE
*)((UINT8
*)Madt
+ GicMSIOffset
),
603 if (GicRedistCount
!= 0) {
604 AddGICRedistributorList (
605 (EFI_ACPI_6_2_GICR_STRUCTURE
*)((UINT8
*)Madt
+ GicRedistOffset
),
611 if (GicItsCount
!= 0) {
613 (EFI_ACPI_6_2_GIC_ITS_STRUCTURE
*)((UINT8
*)Madt
+ GicItsOffset
),
622 if (*Table
!= NULL
) {
629 /** Free any resources allocated for constructing the MADT
631 @param [in] This Pointer to the table generator.
632 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
633 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
635 @param [in, out] Table Pointer to the ACPI Table.
637 @retval EFI_SUCCESS The resources were freed successfully.
638 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
642 FreeMadtTableResources (
643 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
644 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
645 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
646 IN OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
649 ASSERT (This
!= NULL
);
650 ASSERT (AcpiTableInfo
!= NULL
);
651 ASSERT (CfgMgrProtocol
!= NULL
);
652 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
653 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
655 if ((Table
== NULL
) || (*Table
== NULL
)) {
656 DEBUG ((DEBUG_ERROR
, "ERROR: MADT: Invalid Table Pointer\n"));
657 ASSERT ((Table
!= NULL
) && (*Table
!= NULL
));
658 return EFI_INVALID_PARAMETER
;
666 /** The MADT Table Generator revision.
668 #define MADT_GENERATOR_REVISION CREATE_REVISION (1, 0)
670 /** The interface for the MADT Table Generator.
674 ACPI_TABLE_GENERATOR MadtGenerator
= {
676 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdMadt
),
677 // Generator Description
678 L
"ACPI.STD.MADT.GENERATOR",
679 // ACPI Table Signature
680 EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE
,
681 // ACPI Table Revision supported by this Generator
682 EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION
,
683 // Minimum supported ACPI Table Revision
684 EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION
,
686 TABLE_GENERATOR_CREATOR_ID_ARM
,
688 MADT_GENERATOR_REVISION
,
689 // Build Table function
691 // Free Resource function
692 FreeMadtTableResources
,
693 // Extended build function not needed
695 // Extended build function not implemented by the generator.
696 // Hence extended free resource function is not required.
700 /** Register the Generator with the ACPI Table Factory.
702 @param [in] ImageHandle The handle to the image.
703 @param [in] SystemTable Pointer to the System Table.
705 @retval EFI_SUCCESS The Generator is registered.
706 @retval EFI_INVALID_PARAMETER A parameter is invalid.
707 @retval EFI_ALREADY_STARTED The Generator for the Table ID
708 is already registered.
712 AcpiMadtLibConstructor (
713 IN CONST EFI_HANDLE ImageHandle
,
714 IN EFI_SYSTEM_TABLE
* CONST SystemTable
718 Status
= RegisterAcpiTableGenerator (&MadtGenerator
);
719 DEBUG ((DEBUG_INFO
, "MADT: Register Generator. Status = %r\n", Status
));
720 ASSERT_EFI_ERROR (Status
);
724 /** Deregister the Generator from the ACPI Table Factory.
726 @param [in] ImageHandle The handle to the image.
727 @param [in] SystemTable Pointer to the System Table.
729 @retval EFI_SUCCESS The Generator is deregistered.
730 @retval EFI_INVALID_PARAMETER A parameter is invalid.
731 @retval EFI_NOT_FOUND The Generator is not registered.
735 AcpiMadtLibDestructor (
736 IN CONST EFI_HANDLE ImageHandle
,
737 IN EFI_SYSTEM_TABLE
* CONST SystemTable
741 Status
= DeregisterAcpiTableGenerator (&MadtGenerator
);
742 DEBUG ((DEBUG_INFO
, "MADT: Deregister Generator. Status = %r\n", Status
));
743 ASSERT_EFI_ERROR (Status
);