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