]> git.proxmox.com Git - mirror_edk2.git/blame - DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/MadtGenerator.c
DynamicTablesPkg: Add ACPI 6.3 SPE support to MADT generator
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiMadtLibArm / MadtGenerator.c
CommitLineData
015a797a
SM
1/** @file\r
2 MADT Table Generator\r
3\r
4 Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.\r
9cd9bdc6 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
015a797a
SM
6\r
7 @par Reference(s):\r
5506701f 8 - ACPI 6.3 Specification - January 2019\r
015a797a
SM
9\r
10**/\r
11\r
12#include <Library/AcpiLib.h>\r
13#include <Library/DebugLib.h>\r
14#include <Library/MemoryAllocationLib.h>\r
15#include <Protocol/AcpiTable.h>\r
16\r
17// Module specific include files.\r
18#include <AcpiTableGenerator.h>\r
19#include <ConfigurationManagerObject.h>\r
20#include <ConfigurationManagerHelper.h>\r
21#include <Library/TableHelperLib.h>\r
22#include <Protocol/ConfigurationManagerProtocol.h>\r
23\r
24/** ARM standard MADT Generator\r
25\r
26Requirements:\r
27 The following Configuration Manager Object(s) are required by\r
28 this Generator:\r
29 - EArmObjGicCInfo\r
30 - EArmObjGicDInfo\r
31 - EArmObjGicMsiFrameInfo (OPTIONAL)\r
32 - EArmObjGicRedistributorInfo (OPTIONAL)\r
33 - EArmObjGicItsInfo (OPTIONAL)\r
34*/\r
35\r
36/** This macro expands to a function that retrieves the GIC\r
37 CPU interface Information from the Configuration Manager.\r
38*/\r
39GET_OBJECT_LIST (\r
40 EObjNameSpaceArm,\r
41 EArmObjGicCInfo,\r
42 CM_ARM_GICC_INFO\r
43 );\r
44\r
45/** This macro expands to a function that retrieves the GIC\r
46 Distributor Information from the Configuration Manager.\r
47*/\r
48\r
49GET_OBJECT_LIST (\r
50 EObjNameSpaceArm,\r
51 EArmObjGicDInfo,\r
52 CM_ARM_GICD_INFO\r
53 );\r
54\r
55/** This macro expands to a function that retrieves the GIC\r
56 MSI Frame Information from the Configuration Manager.\r
57*/\r
58GET_OBJECT_LIST (\r
59 EObjNameSpaceArm,\r
60 EArmObjGicMsiFrameInfo,\r
61 CM_ARM_GIC_MSI_FRAME_INFO\r
62 );\r
63\r
64/** This macro expands to a function that retrieves the GIC\r
65 Redistributor Information from the Configuration Manager.\r
66*/\r
67\r
68GET_OBJECT_LIST (\r
69 EObjNameSpaceArm,\r
70 EArmObjGicRedistributorInfo,\r
71 CM_ARM_GIC_REDIST_INFO\r
72 );\r
73\r
74/** This macro expands to a function that retrieves the GIC\r
75 Interrupt Translation Service Information from the\r
76 Configuration Manager.\r
77*/\r
78GET_OBJECT_LIST (\r
79 EObjNameSpaceArm,\r
80 EArmObjGicItsInfo,\r
81 CM_ARM_GIC_ITS_INFO\r
82 );\r
83\r
84/** This function updates the GIC CPU Interface Information in the\r
5506701f 85 EFI_ACPI_6_3_GIC_STRUCTURE structure.\r
015a797a 86\r
5506701f
KK
87 @param [in] Gicc Pointer to GIC CPU Interface structure.\r
88 @param [in] GicCInfo Pointer to the GIC CPU Interface Information.\r
89 @param [in] MadtRev MADT table revision.\r
015a797a
SM
90**/\r
91STATIC\r
92VOID\r
93AddGICC (\r
5506701f
KK
94 IN EFI_ACPI_6_3_GIC_STRUCTURE * CONST Gicc,\r
95 IN CONST CM_ARM_GICC_INFO * CONST GicCInfo,\r
96 IN CONST UINT8 MadtRev\r
015a797a
SM
97 )\r
98{\r
99 ASSERT (Gicc != NULL);\r
100 ASSERT (GicCInfo != NULL);\r
101\r
102 // UINT8 Type\r
5506701f 103 Gicc->Type = EFI_ACPI_6_3_GIC;\r
015a797a 104 // UINT8 Length\r
5506701f 105 Gicc->Length = sizeof (EFI_ACPI_6_3_GIC_STRUCTURE);\r
015a797a
SM
106 // UINT16 Reserved\r
107 Gicc->Reserved = EFI_ACPI_RESERVED_WORD;\r
108\r
109 // UINT32 CPUInterfaceNumber\r
110 Gicc->CPUInterfaceNumber = GicCInfo->CPUInterfaceNumber;\r
111 // UINT32 AcpiProcessorUid\r
112 Gicc->AcpiProcessorUid = GicCInfo->AcpiProcessorUid;\r
113 // UINT32 Flags\r
114 Gicc->Flags = GicCInfo->Flags;\r
115 // UINT32 ParkingProtocolVersion\r
116 Gicc->ParkingProtocolVersion = GicCInfo->ParkingProtocolVersion;\r
117 // UINT32 PerformanceInterruptGsiv\r
118 Gicc->PerformanceInterruptGsiv = GicCInfo->PerformanceInterruptGsiv;\r
119 // UINT64 ParkedAddress\r
120 Gicc->ParkedAddress = GicCInfo->ParkedAddress;\r
121\r
122 // UINT64 PhysicalBaseAddress\r
123 Gicc->PhysicalBaseAddress = GicCInfo->PhysicalBaseAddress;\r
124 // UINT64 GICV\r
125 Gicc->GICV = GicCInfo->GICV;\r
126 // UINT64 GICH\r
127 Gicc->GICH = GicCInfo->GICH;\r
128\r
129 // UINT32 VGICMaintenanceInterrupt\r
130 Gicc->VGICMaintenanceInterrupt = GicCInfo->VGICMaintenanceInterrupt;\r
131 // UINT64 GICRBaseAddress\r
132 Gicc->GICRBaseAddress = GicCInfo->GICRBaseAddress;\r
133\r
134 // UINT64 MPIDR\r
135 Gicc->MPIDR = GicCInfo->MPIDR;\r
136 // UINT8 ProcessorPowerEfficiencyClass\r
137 Gicc->ProcessorPowerEfficiencyClass =\r
138 GicCInfo->ProcessorPowerEfficiencyClass;\r
5506701f
KK
139 // UINT8 Reserved2\r
140 Gicc->Reserved2 = EFI_ACPI_RESERVED_BYTE;\r
141\r
142 // UINT16 SpeOverflowInterrupt\r
143 if (MadtRev > EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) {\r
144 Gicc->SpeOverflowInterrupt = GicCInfo->SpeOverflowInterrupt;\r
145 } else {\r
146 // Setting SpeOverflowInterrupt to 0 ensures backward compatibility with\r
147 // ACPI 6.2 by also clearing the Reserved2[1] and Reserved2[2] fields\r
148 // in EFI_ACPI_6_2_GIC_STRUCTURE.\r
149 Gicc->SpeOverflowInterrupt = 0;\r
150 }\r
015a797a
SM
151}\r
152\r
28b824d7
KK
153/**\r
154 Function to test if two GIC CPU Interface information structures have the\r
155 same ACPI Processor UID.\r
156\r
157 @param [in] GicCInfo1 Pointer to the first GICC info structure.\r
158 @param [in] GicCInfo2 Pointer to the second GICC info structure.\r
159 @param [in] Index1 Index of GicCInfo1 in the shared list of GIC\r
160 CPU Interface Info structures.\r
161 @param [in] Index2 Index of GicCInfo2 in the shared list of GIC\r
162 CPU Interface Info structures.\r
163\r
164 @retval TRUE GicCInfo1 and GicCInfo2 have the same UID.\r
165 @retval FALSE GicCInfo1 and GicCInfo2 have different UIDs.\r
166**/\r
167BOOLEAN\r
168EFIAPI\r
169IsAcpiUidEqual (\r
170 IN CONST VOID * GicCInfo1,\r
171 IN CONST VOID * GicCInfo2,\r
172 IN UINTN Index1,\r
173 IN UINTN Index2\r
174 )\r
175{\r
176 UINT32 Uid1;\r
177 UINT32 Uid2;\r
178\r
179 ASSERT ((GicCInfo1 != NULL) && (GicCInfo2 != NULL));\r
180\r
181 Uid1 = ((CM_ARM_GICC_INFO*)GicCInfo1)->AcpiProcessorUid;\r
182 Uid2 = ((CM_ARM_GICC_INFO*)GicCInfo2)->AcpiProcessorUid;\r
183\r
184 if (Uid1 == Uid2) {\r
185 DEBUG ((\r
186 DEBUG_ERROR,\r
187 "ERROR: MADT: GICC Info Structures %d and %d have the same ACPI " \\r
188 "Processor UID: 0x%x.\n",\r
189 Index1,\r
190 Index2,\r
191 Uid1\r
192 ));\r
193 return TRUE;\r
194 }\r
195\r
196 return FALSE;\r
197}\r
198\r
015a797a
SM
199/** Add the GIC CPU Interface Information to the MADT Table.\r
200\r
28b824d7
KK
201 This function also checks for duplicate ACPI Processor UIDs.\r
202\r
203 @param [in] Gicc Pointer to GIC CPU Interface structure list.\r
204 @param [in] GicCInfo Pointer to the GIC CPU Information list.\r
205 @param [in] GicCCount Count of GIC CPU Interfaces.\r
5506701f 206 @param [in] MadtRev MADT table revision.\r
28b824d7
KK
207\r
208 @retval EFI_SUCCESS GIC CPU Interface Information was added\r
209 successfully.\r
210 @retval EFI_INVALID_PARAMETER One or more invalid GIC CPU Info values were\r
211 provided and the generator failed to add the\r
212 information to the table.\r
015a797a
SM
213**/\r
214STATIC\r
28b824d7 215EFI_STATUS\r
015a797a 216AddGICCList (\r
5506701f 217 IN EFI_ACPI_6_3_GIC_STRUCTURE * Gicc,\r
015a797a 218 IN CONST CM_ARM_GICC_INFO * GicCInfo,\r
5506701f
KK
219 IN UINT32 GicCCount,\r
220 IN CONST UINT8 MadtRev\r
015a797a
SM
221 )\r
222{\r
28b824d7
KK
223 BOOLEAN IsAcpiProcUidDuplicated;\r
224\r
015a797a
SM
225 ASSERT (Gicc != NULL);\r
226 ASSERT (GicCInfo != NULL);\r
227\r
28b824d7
KK
228 IsAcpiProcUidDuplicated = FindDuplicateValue (\r
229 GicCInfo,\r
230 GicCCount,\r
231 sizeof (CM_ARM_GICC_INFO),\r
232 IsAcpiUidEqual\r
233 );\r
234 // Duplicate ACPI Processor UID was found so the GICC info provided\r
235 // is invalid\r
236 if (IsAcpiProcUidDuplicated) {\r
237 return EFI_INVALID_PARAMETER;\r
238 }\r
239\r
015a797a 240 while (GicCCount-- != 0) {\r
5506701f 241 AddGICC (Gicc++, GicCInfo++, MadtRev);\r
015a797a 242 }\r
28b824d7
KK
243\r
244 return EFI_SUCCESS;\r
015a797a
SM
245}\r
246\r
247/** Update the GIC Distributor Information in the MADT Table.\r
248\r
249 @param [in] Gicd Pointer to GIC Distributor structure.\r
250 @param [in] GicDInfo Pointer to the GIC Distributor Information.\r
251**/\r
252STATIC\r
253VOID\r
254AddGICD (\r
5506701f 255 EFI_ACPI_6_3_GIC_DISTRIBUTOR_STRUCTURE * CONST Gicd,\r
015a797a
SM
256 CONST CM_ARM_GICD_INFO * CONST GicDInfo\r
257)\r
258{\r
259 ASSERT (Gicd != NULL);\r
260 ASSERT (GicDInfo != NULL);\r
261\r
262 // UINT8 Type\r
5506701f 263 Gicd->Type = EFI_ACPI_6_3_GICD;\r
015a797a 264 // UINT8 Length\r
5506701f 265 Gicd->Length = sizeof (EFI_ACPI_6_3_GIC_DISTRIBUTOR_STRUCTURE);\r
015a797a
SM
266 // UINT16 Reserved\r
267 Gicd->Reserved1 = EFI_ACPI_RESERVED_WORD;\r
268 // UINT32 Identifier\r
24534823
SM
269 // One, and only one, GIC distributor structure must be present\r
270 // in the MADT for an ARM based system\r
271 Gicd->GicId = 0;\r
015a797a
SM
272 // UINT64 PhysicalBaseAddress\r
273 Gicd->PhysicalBaseAddress = GicDInfo->PhysicalBaseAddress;\r
274 // UINT32 VectorBase\r
275 Gicd->SystemVectorBase = EFI_ACPI_RESERVED_DWORD;\r
276 // UINT8 GicVersion\r
277 Gicd->GicVersion = GicDInfo->GicVersion;\r
278 // UINT8 Reserved2[3]\r
279 Gicd->Reserved2[0] = EFI_ACPI_RESERVED_BYTE;\r
280 Gicd->Reserved2[1] = EFI_ACPI_RESERVED_BYTE;\r
281 Gicd->Reserved2[2] = EFI_ACPI_RESERVED_BYTE;\r
282}\r
283\r
284/** Update the GIC MSI Frame Information.\r
285\r
286 @param [in] GicMsiFrame Pointer to GIC MSI Frame structure.\r
287 @param [in] GicMsiFrameInfo Pointer to the GIC MSI Frame Information.\r
288**/\r
289STATIC\r
290VOID\r
291AddGICMsiFrame (\r
5506701f 292 IN EFI_ACPI_6_3_GIC_MSI_FRAME_STRUCTURE * CONST GicMsiFrame,\r
015a797a
SM
293 IN CONST CM_ARM_GIC_MSI_FRAME_INFO * CONST GicMsiFrameInfo\r
294)\r
295{\r
296 ASSERT (GicMsiFrame != NULL);\r
297 ASSERT (GicMsiFrameInfo != NULL);\r
298\r
5506701f
KK
299 GicMsiFrame->Type = EFI_ACPI_6_3_GIC_MSI_FRAME;\r
300 GicMsiFrame->Length = sizeof (EFI_ACPI_6_3_GIC_MSI_FRAME_STRUCTURE);\r
015a797a
SM
301 GicMsiFrame->Reserved1 = EFI_ACPI_RESERVED_WORD;\r
302 GicMsiFrame->GicMsiFrameId = GicMsiFrameInfo->GicMsiFrameId;\r
303 GicMsiFrame->PhysicalBaseAddress = GicMsiFrameInfo->PhysicalBaseAddress;\r
304\r
305 GicMsiFrame->Flags = GicMsiFrameInfo->Flags;\r
306 GicMsiFrame->SPICount = GicMsiFrameInfo->SPICount;\r
307 GicMsiFrame->SPIBase = GicMsiFrameInfo->SPIBase;\r
308}\r
309\r
310/** Add the GIC MSI Frame Information to the MADT Table.\r
311\r
312 @param [in] GicMsiFrame Pointer to GIC MSI Frame structure list.\r
313 @param [in] GicMsiFrameInfo Pointer to the GIC MSI Frame info list.\r
314 @param [in] GicMsiFrameCount Count of GIC MSI Frames.\r
315**/\r
316STATIC\r
317VOID\r
318AddGICMsiFrameInfoList (\r
5506701f 319 IN EFI_ACPI_6_3_GIC_MSI_FRAME_STRUCTURE * GicMsiFrame,\r
015a797a
SM
320 IN CONST CM_ARM_GIC_MSI_FRAME_INFO * GicMsiFrameInfo,\r
321 IN UINT32 GicMsiFrameCount\r
322)\r
323{\r
324 ASSERT (GicMsiFrame != NULL);\r
325 ASSERT (GicMsiFrameInfo != NULL);\r
326\r
327 while (GicMsiFrameCount-- != 0) {\r
328 AddGICMsiFrame (GicMsiFrame++, GicMsiFrameInfo++);\r
329 }\r
330}\r
331\r
332/** Update the GIC Redistributor Information.\r
333\r
334 @param [in] Gicr Pointer to GIC Redistributor structure.\r
335 @param [in] GicRedisributorInfo Pointer to the GIC Redistributor Info.\r
336**/\r
337STATIC\r
338VOID\r
339AddGICRedistributor (\r
5506701f 340 IN EFI_ACPI_6_3_GICR_STRUCTURE * CONST Gicr,\r
015a797a
SM
341 IN CONST CM_ARM_GIC_REDIST_INFO * CONST GicRedisributorInfo\r
342 )\r
343{\r
344 ASSERT (Gicr != NULL);\r
345 ASSERT (GicRedisributorInfo != NULL);\r
346\r
5506701f
KK
347 Gicr->Type = EFI_ACPI_6_3_GICR;\r
348 Gicr->Length = sizeof (EFI_ACPI_6_3_GICR_STRUCTURE);\r
015a797a
SM
349 Gicr->Reserved = EFI_ACPI_RESERVED_WORD;\r
350 Gicr->DiscoveryRangeBaseAddress =\r
351 GicRedisributorInfo->DiscoveryRangeBaseAddress;\r
352 Gicr->DiscoveryRangeLength = GicRedisributorInfo->DiscoveryRangeLength;\r
353}\r
354\r
355/** Add the GIC Redistributor Information to the MADT Table.\r
356\r
357 @param [in] Gicr Pointer to GIC Redistributor structure list.\r
358 @param [in] GicRInfo Pointer to the GIC Distributor info list.\r
359 @param [in] GicRCount Count of GIC Distributors.\r
360**/\r
361STATIC\r
362VOID\r
363AddGICRedistributorList (\r
5506701f 364 IN EFI_ACPI_6_3_GICR_STRUCTURE * Gicr,\r
015a797a
SM
365 IN CONST CM_ARM_GIC_REDIST_INFO * GicRInfo,\r
366 IN UINT32 GicRCount\r
367)\r
368{\r
369 ASSERT (Gicr != NULL);\r
370 ASSERT (GicRInfo != NULL);\r
371\r
372 while (GicRCount-- != 0) {\r
373 AddGICRedistributor (Gicr++, GicRInfo++);\r
374 }\r
375}\r
376\r
377/** Update the GIC Interrupt Translation Service Information\r
378\r
379 @param [in] GicIts Pointer to GIC ITS structure.\r
380 @param [in] GicItsInfo Pointer to the GIC ITS Information.\r
381**/\r
382STATIC\r
383VOID\r
384AddGICInterruptTranslationService (\r
5506701f 385 IN EFI_ACPI_6_3_GIC_ITS_STRUCTURE * CONST GicIts,\r
015a797a
SM
386 IN CONST CM_ARM_GIC_ITS_INFO * CONST GicItsInfo\r
387)\r
388{\r
389 ASSERT (GicIts != NULL);\r
390 ASSERT (GicItsInfo != NULL);\r
391\r
5506701f
KK
392 GicIts->Type = EFI_ACPI_6_3_GIC_ITS;\r
393 GicIts->Length = sizeof (EFI_ACPI_6_3_GIC_ITS_STRUCTURE);\r
015a797a
SM
394 GicIts->Reserved = EFI_ACPI_RESERVED_WORD;\r
395 GicIts->GicItsId = GicItsInfo->GicItsId;\r
396 GicIts->PhysicalBaseAddress = GicItsInfo->PhysicalBaseAddress;\r
397 GicIts->Reserved2 = EFI_ACPI_RESERVED_DWORD;\r
398}\r
399\r
400/** Add the GIC Interrupt Translation Service Information\r
401 to the MADT Table.\r
402\r
403 @param [in] GicIts Pointer to GIC ITS structure list.\r
404 @param [in] GicItsInfo Pointer to the GIC ITS list.\r
405 @param [in] GicItsCount Count of GIC ITS.\r
406**/\r
407STATIC\r
408VOID\r
409AddGICItsList (\r
5506701f 410 IN EFI_ACPI_6_3_GIC_ITS_STRUCTURE * GicIts,\r
015a797a
SM
411 IN CONST CM_ARM_GIC_ITS_INFO * GicItsInfo,\r
412 IN UINT32 GicItsCount\r
413)\r
414{\r
415 ASSERT (GicIts != NULL);\r
416 ASSERT (GicItsInfo != NULL);\r
417\r
418 while (GicItsCount-- != 0) {\r
419 AddGICInterruptTranslationService (GicIts++, GicItsInfo++);\r
420 }\r
421}\r
422\r
423/** Construct the MADT ACPI table.\r
424\r
425 This function invokes the Configuration Manager protocol interface\r
426 to get the required hardware information for generating the ACPI\r
427 table.\r
428\r
429 If this function allocates any resources then they must be freed\r
430 in the FreeXXXXTableResources function.\r
431\r
432 @param [in] This Pointer to the table generator.\r
433 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
434 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
435 Protocol Interface.\r
436 @param [out] Table Pointer to the constructed ACPI Table.\r
437\r
438 @retval EFI_SUCCESS Table generated successfully.\r
439 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
440 @retval EFI_NOT_FOUND The required object was not found.\r
441 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration\r
442 Manager is less than the Object size for the\r
443 requested object.\r
444**/\r
445STATIC\r
446EFI_STATUS\r
447EFIAPI\r
448BuildMadtTable (\r
449 IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
450 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
451 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
452 OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table\r
453 )\r
454{\r
455 EFI_STATUS Status;\r
456 UINT32 TableSize;\r
457 UINT32 GicCCount;\r
458 UINT32 GicDCount;\r
459 UINT32 GicMSICount;\r
460 UINT32 GicRedistCount;\r
461 UINT32 GicItsCount;\r
462 CM_ARM_GICC_INFO * GicCInfo;\r
463 CM_ARM_GICD_INFO * GicDInfo;\r
464 CM_ARM_GIC_MSI_FRAME_INFO * GicMSIInfo;\r
465 CM_ARM_GIC_REDIST_INFO * GicRedistInfo;\r
466 CM_ARM_GIC_ITS_INFO * GicItsInfo;\r
467 UINT32 GicCOffset;\r
468 UINT32 GicDOffset;\r
469 UINT32 GicMSIOffset;\r
470 UINT32 GicRedistOffset;\r
471 UINT32 GicItsOffset;\r
472\r
5506701f 473 EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER * Madt;\r
015a797a
SM
474\r
475 ASSERT (This != NULL);\r
476 ASSERT (AcpiTableInfo != NULL);\r
477 ASSERT (CfgMgrProtocol != NULL);\r
478 ASSERT (Table != NULL);\r
479 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
480 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
481\r
482 if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||\r
483 (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {\r
484 DEBUG ((\r
485 DEBUG_ERROR,\r
486 "ERROR: MADT: Requested table revision = %d, is not supported."\r
487 "Supported table revision: Minimum = %d, Maximum = %d\n",\r
488 AcpiTableInfo->AcpiTableRevision,\r
489 This->MinAcpiTableRevision,\r
490 This->AcpiTableRevision\r
491 ));\r
492 return EFI_INVALID_PARAMETER;\r
493 }\r
494\r
495 *Table = NULL;\r
496\r
497 Status = GetEArmObjGicCInfo (\r
498 CfgMgrProtocol,\r
499 CM_NULL_TOKEN,\r
500 &GicCInfo,\r
501 &GicCCount\r
502 );\r
503 if (EFI_ERROR (Status)) {\r
504 DEBUG ((\r
505 DEBUG_ERROR,\r
506 "ERROR: MADT: Failed to get GICC Info. Status = %r\n",\r
507 Status\r
508 ));\r
509 goto error_handler;\r
510 }\r
511\r
512 if (GicCCount == 0) {\r
513 DEBUG ((\r
514 DEBUG_ERROR,\r
515 "ERROR: MADT: GIC CPU Interface information not provided.\n"\r
516 ));\r
517 ASSERT (GicCCount != 0);\r
518 Status = EFI_INVALID_PARAMETER;\r
519 goto error_handler;\r
520 }\r
521\r
522 Status = GetEArmObjGicDInfo (\r
523 CfgMgrProtocol,\r
524 CM_NULL_TOKEN,\r
525 &GicDInfo,\r
526 &GicDCount\r
527 );\r
528 if (EFI_ERROR (Status)) {\r
529 DEBUG ((\r
530 DEBUG_ERROR,\r
531 "ERROR: MADT: Failed to get GICD Info. Status = %r\n",\r
532 Status\r
533 ));\r
534 goto error_handler;\r
535 }\r
536\r
537 if (GicDCount == 0) {\r
538 DEBUG ((\r
539 DEBUG_ERROR,\r
540 "ERROR: MADT: GIC Distributor information not provided.\n"\r
541 ));\r
542 ASSERT (GicDCount != 0);\r
543 Status = EFI_INVALID_PARAMETER;\r
544 goto error_handler;\r
545 }\r
546\r
547 if (GicDCount > 1) {\r
548 DEBUG ((\r
549 DEBUG_ERROR,\r
550 "ERROR: MADT: One, and only one, GIC distributor must be present."\r
551 "GicDCount = %d\n",\r
552 GicDCount\r
553 ));\r
554 ASSERT (GicDCount <= 1);\r
555 Status = EFI_INVALID_PARAMETER;\r
556 goto error_handler;\r
557 }\r
558\r
559 Status = GetEArmObjGicMsiFrameInfo (\r
560 CfgMgrProtocol,\r
561 CM_NULL_TOKEN,\r
562 &GicMSIInfo,\r
563 &GicMSICount\r
564 );\r
565 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
566 DEBUG ((\r
567 DEBUG_ERROR,\r
568 "ERROR: MADT: Failed to get GIC MSI Info. Status = %r\n",\r
569 Status\r
570 ));\r
571 goto error_handler;\r
572 }\r
573\r
574 Status = GetEArmObjGicRedistributorInfo (\r
575 CfgMgrProtocol,\r
576 CM_NULL_TOKEN,\r
577 &GicRedistInfo,\r
578 &GicRedistCount\r
579 );\r
580 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
581 DEBUG ((\r
582 DEBUG_ERROR,\r
583 "ERROR: MADT: Failed to get GIC Redistributor Info. Status = %r\n",\r
584 Status\r
585 ));\r
586 goto error_handler;\r
587 }\r
588\r
589 Status = GetEArmObjGicItsInfo (\r
590 CfgMgrProtocol,\r
591 CM_NULL_TOKEN,\r
592 &GicItsInfo,\r
593 &GicItsCount\r
594 );\r
595 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
596 DEBUG ((\r
597 DEBUG_ERROR,\r
598 "ERROR: MADT: Failed to get GIC ITS Info. Status = %r\n",\r
599 Status\r
600 ));\r
601 goto error_handler;\r
602 }\r
603\r
5506701f 604 TableSize = sizeof (EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER);\r
015a797a
SM
605\r
606 GicCOffset = TableSize;\r
5506701f 607 TableSize += (sizeof (EFI_ACPI_6_3_GIC_STRUCTURE) * GicCCount);\r
015a797a
SM
608\r
609 GicDOffset = TableSize;\r
5506701f 610 TableSize += (sizeof (EFI_ACPI_6_3_GIC_DISTRIBUTOR_STRUCTURE) * GicDCount);\r
015a797a
SM
611\r
612 GicMSIOffset = TableSize;\r
5506701f 613 TableSize += (sizeof (EFI_ACPI_6_3_GIC_MSI_FRAME_STRUCTURE) * GicMSICount);\r
015a797a
SM
614\r
615 GicRedistOffset = TableSize;\r
5506701f 616 TableSize += (sizeof (EFI_ACPI_6_3_GICR_STRUCTURE) * GicRedistCount);\r
015a797a
SM
617\r
618 GicItsOffset = TableSize;\r
5506701f 619 TableSize += (sizeof (EFI_ACPI_6_3_GIC_ITS_STRUCTURE) * GicItsCount);\r
015a797a
SM
620\r
621 // Allocate the Buffer for MADT table\r
622 *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);\r
623 if (*Table == NULL) {\r
624 Status = EFI_OUT_OF_RESOURCES;\r
625 DEBUG ((\r
626 DEBUG_ERROR,\r
627 "ERROR: MADT: Failed to allocate memory for MADT Table, Size = %d," \\r
628 " Status = %r\n",\r
629 TableSize,\r
630 Status\r
631 ));\r
632 goto error_handler;\r
633 }\r
634\r
5506701f 635 Madt = (EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER*)*Table;\r
015a797a
SM
636\r
637 DEBUG ((\r
638 DEBUG_INFO,\r
639 "MADT: Madt = 0x%p TableSize = 0x%x\n",\r
640 Madt,\r
641 TableSize\r
642 ));\r
643\r
644 Status = AddAcpiHeader (\r
645 CfgMgrProtocol,\r
646 This,\r
647 &Madt->Header,\r
e12bdeb1 648 AcpiTableInfo,\r
015a797a
SM
649 TableSize\r
650 );\r
651 if (EFI_ERROR (Status)) {\r
652 DEBUG ((\r
653 DEBUG_ERROR,\r
654 "ERROR: MADT: Failed to add ACPI header. Status = %r\n",\r
655 Status\r
656 ));\r
657 goto error_handler;\r
658 }\r
659\r
28b824d7 660 Status = AddGICCList (\r
5506701f 661 (EFI_ACPI_6_3_GIC_STRUCTURE*)((UINT8*)Madt + GicCOffset),\r
015a797a 662 GicCInfo,\r
5506701f
KK
663 GicCCount,\r
664 Madt->Header.Revision\r
015a797a 665 );\r
28b824d7
KK
666 if (EFI_ERROR (Status)) {\r
667 DEBUG ((\r
668 DEBUG_ERROR,\r
669 "ERROR: MADT: Failed to add GICC structures. Status = %r\n",\r
670 Status\r
671 ));\r
672 goto error_handler;\r
673 }\r
015a797a
SM
674\r
675 AddGICD (\r
5506701f 676 (EFI_ACPI_6_3_GIC_DISTRIBUTOR_STRUCTURE*)((UINT8*)Madt + GicDOffset),\r
015a797a
SM
677 GicDInfo\r
678 );\r
679\r
680 if (GicMSICount != 0) {\r
681 AddGICMsiFrameInfoList (\r
5506701f 682 (EFI_ACPI_6_3_GIC_MSI_FRAME_STRUCTURE*)((UINT8*)Madt + GicMSIOffset),\r
015a797a
SM
683 GicMSIInfo,\r
684 GicMSICount\r
685 );\r
686 }\r
687\r
688 if (GicRedistCount != 0) {\r
689 AddGICRedistributorList (\r
5506701f 690 (EFI_ACPI_6_3_GICR_STRUCTURE*)((UINT8*)Madt + GicRedistOffset),\r
015a797a
SM
691 GicRedistInfo,\r
692 GicRedistCount\r
693 );\r
694 }\r
695\r
696 if (GicItsCount != 0) {\r
697 AddGICItsList (\r
5506701f 698 (EFI_ACPI_6_3_GIC_ITS_STRUCTURE*)((UINT8*)Madt + GicItsOffset),\r
015a797a
SM
699 GicItsInfo,\r
700 GicItsCount\r
701 );\r
702 }\r
703\r
704 return EFI_SUCCESS;\r
705\r
706error_handler:\r
707 if (*Table != NULL) {\r
708 FreePool (*Table);\r
709 *Table = NULL;\r
710 }\r
711 return Status;\r
712}\r
713\r
714/** Free any resources allocated for constructing the MADT\r
715\r
716 @param [in] This Pointer to the table generator.\r
717 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
718 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
719 Protocol Interface.\r
720 @param [in, out] Table Pointer to the ACPI Table.\r
721\r
722 @retval EFI_SUCCESS The resources were freed successfully.\r
723 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.\r
724**/\r
725STATIC\r
726EFI_STATUS\r
727FreeMadtTableResources (\r
728 IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
729 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
730 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
731 IN OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table\r
732 )\r
733{\r
734 ASSERT (This != NULL);\r
735 ASSERT (AcpiTableInfo != NULL);\r
736 ASSERT (CfgMgrProtocol != NULL);\r
737 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
738 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
739\r
740 if ((Table == NULL) || (*Table == NULL)) {\r
741 DEBUG ((DEBUG_ERROR, "ERROR: MADT: Invalid Table Pointer\n"));\r
742 ASSERT ((Table != NULL) && (*Table != NULL));\r
743 return EFI_INVALID_PARAMETER;\r
744 }\r
745\r
746 FreePool (*Table);\r
747 *Table = NULL;\r
748 return EFI_SUCCESS;\r
749}\r
750\r
751/** The MADT Table Generator revision.\r
752*/\r
753#define MADT_GENERATOR_REVISION CREATE_REVISION (1, 0)\r
754\r
755/** The interface for the MADT Table Generator.\r
756*/\r
757STATIC\r
758CONST\r
759ACPI_TABLE_GENERATOR MadtGenerator = {\r
760 // Generator ID\r
761 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdMadt),\r
762 // Generator Description\r
763 L"ACPI.STD.MADT.GENERATOR",\r
764 // ACPI Table Signature\r
5506701f 765 EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE,\r
015a797a 766 // ACPI Table Revision supported by this Generator\r
5506701f 767 EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION,\r
015a797a
SM
768 // Minimum supported ACPI Table Revision\r
769 EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION,\r
770 // Creator ID\r
771 TABLE_GENERATOR_CREATOR_ID_ARM,\r
772 // Creator Revision\r
773 MADT_GENERATOR_REVISION,\r
774 // Build Table function\r
775 BuildMadtTable,\r
776 // Free Resource function\r
777 FreeMadtTableResources,\r
778 // Extended build function not needed\r
779 NULL,\r
780 // Extended build function not implemented by the generator.\r
781 // Hence extended free resource function is not required.\r
782 NULL\r
783};\r
784\r
785/** Register the Generator with the ACPI Table Factory.\r
786\r
787 @param [in] ImageHandle The handle to the image.\r
788 @param [in] SystemTable Pointer to the System Table.\r
789\r
790 @retval EFI_SUCCESS The Generator is registered.\r
791 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
792 @retval EFI_ALREADY_STARTED The Generator for the Table ID\r
793 is already registered.\r
794**/\r
795EFI_STATUS\r
796EFIAPI\r
797AcpiMadtLibConstructor (\r
798 IN CONST EFI_HANDLE ImageHandle,\r
799 IN EFI_SYSTEM_TABLE * CONST SystemTable\r
800 )\r
801{\r
802 EFI_STATUS Status;\r
803 Status = RegisterAcpiTableGenerator (&MadtGenerator);\r
804 DEBUG ((DEBUG_INFO, "MADT: Register Generator. Status = %r\n", Status));\r
805 ASSERT_EFI_ERROR (Status);\r
806 return Status;\r
807}\r
808\r
809/** Deregister the Generator from the ACPI Table Factory.\r
810\r
811 @param [in] ImageHandle The handle to the image.\r
812 @param [in] SystemTable Pointer to the System Table.\r
813\r
814 @retval EFI_SUCCESS The Generator is deregistered.\r
815 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
816 @retval EFI_NOT_FOUND The Generator is not registered.\r
817**/\r
818EFI_STATUS\r
819EFIAPI\r
820AcpiMadtLibDestructor (\r
821 IN CONST EFI_HANDLE ImageHandle,\r
822 IN EFI_SYSTEM_TABLE * CONST SystemTable\r
823 )\r
824{\r
825 EFI_STATUS Status;\r
826 Status = DeregisterAcpiTableGenerator (&MadtGenerator);\r
827 DEBUG ((DEBUG_INFO, "MADT: Deregister Generator. Status = %r\n", Status));\r
828 ASSERT_EFI_ERROR (Status);\r
829 return Status;\r
830}\r