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