]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Madt/MadtParser.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ShellPkg / Library / UefiShellAcpiViewCommandLib / Parsers / Madt / MadtParser.c
1 /** @file
2 MADT table parser
3
4 Copyright (c) 2016 - 2020, ARM Limited. All rights reserved.
5 Copyright (c) 2022, AMD Incorporated. All rights reserved.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 @par Reference(s):
9 - ACPI 6.3 Specification - January 2019
10 - Arm Generic Interrupt Controller Architecture Specification,
11 GIC architecture version 3 and version 4, issue E
12 - Arm Server Base System Architecture 5.0
13 **/
14
15 #include <IndustryStandard/Acpi.h>
16 #include <Library/UefiLib.h>
17 #include "AcpiParser.h"
18 #include "AcpiTableParser.h"
19 #include "AcpiViewConfig.h"
20 #include "MadtParser.h"
21
22 // Local Variables
23 STATIC CONST UINT8 *MadtInterruptControllerType;
24 STATIC CONST UINT8 *MadtInterruptControllerLength;
25 STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;
26
27 /**
28 This function validates the System Vector Base in the GICD.
29
30 @param [in] Ptr Pointer to the start of the field data.
31 @param [in] Context Pointer to context specific information e.g. this
32 could be a pointer to the ACPI table header.
33 **/
34 STATIC
35 VOID
36 EFIAPI
37 ValidateGICDSystemVectorBase (
38 IN UINT8 *Ptr,
39 IN VOID *Context
40 )
41 {
42 if (*(UINT32 *)Ptr != 0) {
43 IncrementErrorCount ();
44 Print (
45 L"\nERROR: System Vector Base must be zero."
46 );
47 }
48 }
49
50 /**
51 This function validates the SPE Overflow Interrupt in the GICC.
52
53 @param [in] Ptr Pointer to the start of the field data.
54 @param [in] Context Pointer to context specific information e.g. this
55 could be a pointer to the ACPI table header.
56 **/
57 STATIC
58 VOID
59 EFIAPI
60 ValidateSpeOverflowInterrupt (
61 IN UINT8 *Ptr,
62 IN VOID *Context
63 )
64 {
65 UINT16 SpeOverflowInterrupt;
66
67 SpeOverflowInterrupt = *(UINT16 *)Ptr;
68
69 // SPE not supported by this processor
70 if (SpeOverflowInterrupt == 0) {
71 return;
72 }
73
74 if ((SpeOverflowInterrupt < ARM_PPI_ID_MIN) ||
75 ((SpeOverflowInterrupt > ARM_PPI_ID_MAX) &&
76 (SpeOverflowInterrupt < ARM_PPI_ID_EXTENDED_MIN)) ||
77 (SpeOverflowInterrupt > ARM_PPI_ID_EXTENDED_MAX))
78 {
79 IncrementErrorCount ();
80 Print (
81 L"\nERROR: SPE Overflow Interrupt ID of %d is not in the allowed PPI ID "
82 L"ranges of %d-%d or %d-%d (for GICv3.1 or later).",
83 SpeOverflowInterrupt,
84 ARM_PPI_ID_MIN,
85 ARM_PPI_ID_MAX,
86 ARM_PPI_ID_EXTENDED_MIN,
87 ARM_PPI_ID_EXTENDED_MAX
88 );
89 } else if (SpeOverflowInterrupt != ARM_PPI_ID_PMBIRQ) {
90 IncrementWarningCount ();
91 Print (
92 L"\nWARNING: SPE Overflow Interrupt ID of %d is not compliant with SBSA "
93 L"Level 3 PPI ID assignment: %d.",
94 SpeOverflowInterrupt,
95 ARM_PPI_ID_PMBIRQ
96 );
97 }
98 }
99
100 /**
101 An ACPI_PARSER array describing the GICC Interrupt Controller Structure.
102 **/
103 STATIC CONST ACPI_PARSER GicCParser[] = {
104 { L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
105 { L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL },
106 { L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL },
107
108 { L"CPU Interface Number", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
109 { L"ACPI Processor UID", 4, 8, L"0x%x", NULL, NULL, NULL, NULL },
110 { L"Flags", 4, 12, L"0x%x", NULL, NULL, NULL, NULL },
111 { L"Parking Protocol Version", 4, 16, L"0x%x", NULL, NULL, NULL, NULL },
112
113 { L"Performance Interrupt GSIV", 4, 20, L"0x%x", NULL, NULL, NULL, NULL },
114 { L"Parked Address", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL },
115 { L"Physical Base Address", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL },
116 { L"GICV", 8, 40, L"0x%lx", NULL, NULL, NULL, NULL },
117 { L"GICH", 8, 48, L"0x%lx", NULL, NULL, NULL, NULL },
118 { L"VGIC Maintenance interrupt", 4, 56, L"0x%x", NULL, NULL, NULL, NULL },
119 { L"GICR Base Address", 8, 60, L"0x%lx", NULL, NULL, NULL, NULL },
120 { L"MPIDR", 8, 68, L"0x%lx", NULL, NULL, NULL, NULL },
121 { L"Processor Power Efficiency Class", 1, 76, L"0x%x", NULL, NULL, NULL,
122 NULL },
123 { L"Reserved", 1, 77, L"0x%x", NULL, NULL, NULL, NULL },
124 { L"SPE overflow Interrupt", 2, 78, L"0x%x", NULL, NULL,
125 ValidateSpeOverflowInterrupt, NULL }
126 };
127
128 /**
129 An ACPI_PARSER array describing the GICD Interrupt Controller Structure.
130 **/
131 STATIC CONST ACPI_PARSER GicDParser[] = {
132 { L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
133 { L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL },
134 { L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL },
135
136 { L"GIC ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
137 { L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL },
138 { L"System Vector Base", 4, 16, L"0x%x", NULL, NULL,
139 ValidateGICDSystemVectorBase, NULL },
140 { L"GIC Version", 1, 20, L"%d", NULL, NULL, NULL, NULL },
141 { L"Reserved", 3, 21, L"%x %x %x", Dump3Chars, NULL, NULL, NULL }
142 };
143
144 /**
145 An ACPI_PARSER array describing the MSI Frame Interrupt Controller Structure.
146 **/
147 STATIC CONST ACPI_PARSER GicMSIFrameParser[] = {
148 { L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
149 { L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL },
150 { L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL },
151
152 { L"MSI Frame ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
153 { L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL },
154 { L"Flags", 4, 16, L"0x%x", NULL, NULL, NULL, NULL },
155
156 { L"SPI Count", 2, 20, L"%d", NULL, NULL, NULL, NULL },
157 { L"SPI Base", 2, 22, L"0x%x", NULL, NULL, NULL, NULL }
158 };
159
160 /**
161 An ACPI_PARSER array describing the GICR Interrupt Controller Structure.
162 **/
163 STATIC CONST ACPI_PARSER GicRParser[] = {
164 { L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
165 { L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL },
166 { L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL },
167
168 { L"Discovery Range Base Address", 8, 4, L"0x%lx", NULL, NULL, NULL,
169 NULL },
170 { L"Discovery Range Length", 4, 12, L"0x%x", NULL, NULL, NULL, NULL }
171 };
172
173 /**
174 An ACPI_PARSER array describing the GIC ITS Interrupt Controller Structure.
175 **/
176 STATIC CONST ACPI_PARSER GicITSParser[] = {
177 { L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
178 { L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL },
179 { L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL },
180
181 { L"GIC ITS ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
182 { L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL },
183 { L"Reserved", 4, 16, L"0x%x", NULL, NULL, NULL, NULL }
184 };
185
186 /**
187 An ACPI_PARSER array describing the IO APIC Structure.
188 **/
189 STATIC CONST ACPI_PARSER IoApic[] = {
190 { L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
191 { L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL },
192 { L"I/O APIC ID", 1, 2, L"0x%x", NULL, NULL, NULL, NULL },
193 { L"Reserved", 1, 3, L"0x%x", NULL, NULL, NULL, NULL },
194 { L"I/O APIC Address", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
195 { L"Global System Interrupt Base", 4, 8, L"0x%x", NULL, NULL, NULL, NULL }
196 };
197
198 /**
199 An ACPI_PARSER array describing the Interrupt Source Override Structure.
200 **/
201 STATIC CONST ACPI_PARSER InterruptSourceOverride[] = {
202 { L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
203 { L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL },
204 { L"Bus", 1, 2, L"0x%x", NULL, NULL, NULL, NULL },
205 { L"Source", 1, 3, L"0x%x", NULL, NULL, NULL, NULL },
206 { L"Global System Interrupt", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
207 { L"Flags", 2, 8, L"0x%x", NULL, NULL, NULL, NULL }
208 };
209
210 STATIC CONST ACPI_PARSER LocalApicFlags[] = {
211 { L"Enabled", 1, 0, L"%d", NULL, NULL, NULL, NULL },
212 { L"Online Capable", 1, 1, L"%d", NULL, NULL, NULL, NULL },
213 { L"Reserved", 30, 2, L"%d", NULL, NULL, NULL, NULL }
214 };
215
216 /**
217 This function traces Bit Flags fields.
218 If no format string is specified the Format must be NULL.
219
220 @param [in] Format Optional format string for tracing the data.
221 @param [in] Ptr Pointer to the start of the buffer.
222 **/
223 VOID
224 EFIAPI
225 DumpLocalApicBitFlags (
226 IN CONST CHAR16 *Format OPTIONAL,
227 IN UINT8 *Ptr
228 )
229 {
230 if (Format != NULL) {
231 Print (Format, *(UINT32 *)Ptr);
232 return;
233 }
234
235 Print (L"0x%X\n", *(UINT32 *)Ptr);
236 ParseAcpiBitFields (
237 TRUE,
238 2,
239 NULL,
240 Ptr,
241 4,
242 PARSER_PARAMS (LocalApicFlags)
243 );
244 }
245
246 /**
247 An ACPI_PARSER array describing the Processor Local APIC Structure.
248 **/
249 STATIC CONST ACPI_PARSER ProcessorLocalApic[] = {
250 { L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
251 { L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL },
252
253 { L"ACPI Processor UID", 1, 2, L"0x%x", NULL, NULL, NULL, NULL },
254 { L"APIC ID", 1, 3, L"0x%x", NULL, NULL, NULL, NULL },
255 { L"Flags", 4, 4, NULL, DumpLocalApicBitFlags, NULL, NULL, NULL }
256 };
257
258 /**
259 An ACPI_PARSER array describing the Processor Local x2APIC Structure.
260 **/
261 STATIC CONST ACPI_PARSER ProcessorLocalX2Apic[] = {
262 { L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
263 { L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL },
264 { L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL },
265
266 { L"X2APIC ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
267 { L"Flags", 4, 8, NULL, DumpLocalApicBitFlags, NULL, NULL, NULL },
268 { L"ACPI Processor UID", 4, 12, L"0x%x", NULL, NULL, NULL, NULL }
269 };
270
271 /**
272 An ACPI_PARSER array describing the Local x2APIC NMI Structure.
273 **/
274 STATIC CONST ACPI_PARSER LocalX2ApicNmi[] = {
275 { L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
276 { L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL },
277 { L"Flags", 2, 2, L"0x%x", NULL, NULL, NULL, NULL },
278
279 { L"ACPI Processor UID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
280 { L"Local x2APIC LINT#", 1, 8, L"0x%x", NULL, NULL, NULL, NULL },
281 { L"Reserved", 3, 9, L"0x%x%x%x", Dump3Chars, NULL, NULL, NULL }
282 };
283
284 /**
285 An ACPI_PARSER array describing the ACPI MADT Table.
286 **/
287 STATIC CONST ACPI_PARSER MadtParser[] = {
288 PARSE_ACPI_HEADER (&AcpiHdrInfo),
289 { L"Local Interrupt Controller Address",4, 36, L"0x%x", NULL, NULL, NULL,
290 NULL },
291 { L"Flags", 4, 40, L"0x%x", NULL, NULL, NULL,NULL}
292 };
293
294 /**
295 An ACPI_PARSER array describing the MADT Interrupt Controller Structure Header Structure.
296 **/
297 STATIC CONST ACPI_PARSER MadtInterruptControllerHeaderParser[] = {
298 { NULL, 1, 0, NULL, NULL, (VOID **)&MadtInterruptControllerType, NULL, NULL },
299 { L"Length", 1, 1, NULL, NULL, (VOID **)&MadtInterruptControllerLength, NULL,
300 NULL },
301 { L"Reserved", 2, 2, NULL, NULL, NULL, NULL, NULL }
302 };
303
304 /**
305 This function parses the ACPI MADT table.
306 When trace is enabled this function parses the MADT table and
307 traces the ACPI table fields.
308
309 This function currently parses the following Interrupt Controller
310 Structures:
311 - GICC
312 - GICD
313 - GIC MSI Frame
314 - GICR
315 - GIC ITS
316
317 This function also performs validation of the ACPI table fields.
318
319 @param [in] Trace If TRUE, trace the ACPI fields.
320 @param [in] Ptr Pointer to the start of the buffer.
321 @param [in] AcpiTableLength Length of the ACPI table.
322 @param [in] AcpiTableRevision Revision of the ACPI table.
323 **/
324 VOID
325 EFIAPI
326 ParseAcpiMadt (
327 IN BOOLEAN Trace,
328 IN UINT8 *Ptr,
329 IN UINT32 AcpiTableLength,
330 IN UINT8 AcpiTableRevision
331 )
332 {
333 UINT32 Offset;
334 UINT8 *InterruptContollerPtr;
335 UINT32 GICDCount;
336
337 GICDCount = 0;
338
339 if (!Trace) {
340 return;
341 }
342
343 Offset = ParseAcpi (
344 TRUE,
345 0,
346 "MADT",
347 Ptr,
348 AcpiTableLength,
349 PARSER_PARAMS (MadtParser)
350 );
351 InterruptContollerPtr = Ptr + Offset;
352
353 while (Offset < AcpiTableLength) {
354 // Parse Interrupt Controller Structure to obtain Length.
355 ParseAcpi (
356 FALSE,
357 0,
358 NULL,
359 InterruptContollerPtr,
360 AcpiTableLength - Offset,
361 PARSER_PARAMS (MadtInterruptControllerHeaderParser)
362 );
363
364 // Check if the values used to control the parsing logic have been
365 // successfully read.
366 if ((MadtInterruptControllerType == NULL) ||
367 (MadtInterruptControllerLength == NULL))
368 {
369 IncrementErrorCount ();
370 Print (
371 L"ERROR: Insufficient remaining table buffer length to read the " \
372 L"Interrupt Controller Structure header. Length = %d.\n",
373 AcpiTableLength - Offset
374 );
375 return;
376 }
377
378 // Validate Interrupt Controller Structure length
379 if ((*MadtInterruptControllerLength == 0) ||
380 ((Offset + (*MadtInterruptControllerLength)) > AcpiTableLength))
381 {
382 IncrementErrorCount ();
383 Print (
384 L"ERROR: Invalid Interrupt Controller Structure length. " \
385 L"Length = %d. Offset = %d. AcpiTableLength = %d.\n",
386 *MadtInterruptControllerLength,
387 Offset,
388 AcpiTableLength
389 );
390 return;
391 }
392
393 switch (*MadtInterruptControllerType) {
394 case EFI_ACPI_6_3_GIC:
395 {
396 ParseAcpi (
397 TRUE,
398 2,
399 "GICC",
400 InterruptContollerPtr,
401 *MadtInterruptControllerLength,
402 PARSER_PARAMS (GicCParser)
403 );
404 break;
405 }
406
407 case EFI_ACPI_6_3_GICD:
408 {
409 if (++GICDCount > 1) {
410 IncrementErrorCount ();
411 Print (
412 L"ERROR: Only one GICD must be present,"
413 L" GICDCount = %d\n",
414 GICDCount
415 );
416 }
417
418 ParseAcpi (
419 TRUE,
420 2,
421 "GICD",
422 InterruptContollerPtr,
423 *MadtInterruptControllerLength,
424 PARSER_PARAMS (GicDParser)
425 );
426 break;
427 }
428
429 case EFI_ACPI_6_3_GIC_MSI_FRAME:
430 {
431 ParseAcpi (
432 TRUE,
433 2,
434 "GIC MSI Frame",
435 InterruptContollerPtr,
436 *MadtInterruptControllerLength,
437 PARSER_PARAMS (GicMSIFrameParser)
438 );
439 break;
440 }
441
442 case EFI_ACPI_6_3_GICR:
443 {
444 ParseAcpi (
445 TRUE,
446 2,
447 "GICR",
448 InterruptContollerPtr,
449 *MadtInterruptControllerLength,
450 PARSER_PARAMS (GicRParser)
451 );
452 break;
453 }
454
455 case EFI_ACPI_6_3_GIC_ITS:
456 {
457 ParseAcpi (
458 TRUE,
459 2,
460 "GIC ITS",
461 InterruptContollerPtr,
462 *MadtInterruptControllerLength,
463 PARSER_PARAMS (GicITSParser)
464 );
465 break;
466 }
467
468 case EFI_ACPI_6_3_IO_APIC:
469 {
470 ParseAcpi (
471 TRUE,
472 2,
473 "IO APIC",
474 InterruptContollerPtr,
475 *MadtInterruptControllerLength,
476 PARSER_PARAMS (IoApic)
477 );
478 break;
479 }
480
481 case EFI_ACPI_6_3_INTERRUPT_SOURCE_OVERRIDE:
482 {
483 ParseAcpi (
484 TRUE,
485 2,
486 "INTERRUPT SOURCE OVERRIDE",
487 InterruptContollerPtr,
488 *MadtInterruptControllerLength,
489 PARSER_PARAMS (InterruptSourceOverride)
490 );
491 break;
492 }
493 case EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC:
494 {
495 ParseAcpi (
496 TRUE,
497 2,
498 "PROCESSOR LOCAL APIC",
499 InterruptContollerPtr,
500 *MadtInterruptControllerLength,
501 PARSER_PARAMS (ProcessorLocalApic)
502 );
503 break;
504 }
505 case EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC:
506 {
507 ParseAcpi (
508 TRUE,
509 2,
510 "PROCESSOR LOCAL X2APIC",
511 InterruptContollerPtr,
512 *MadtInterruptControllerLength,
513 PARSER_PARAMS (ProcessorLocalX2Apic)
514 );
515 break;
516 }
517
518 case EFI_ACPI_6_3_LOCAL_X2APIC_NMI:
519 {
520 ParseAcpi (
521 TRUE,
522 2,
523 "LOCAL x2APIC NMI",
524 InterruptContollerPtr,
525 *MadtInterruptControllerLength,
526 PARSER_PARAMS (LocalX2ApicNmi)
527 );
528 break;
529 }
530
531 default:
532 {
533 IncrementErrorCount ();
534 Print (
535 L"ERROR: Unknown Interrupt Controller Structure,"
536 L" Type = %d, Length = %d\n",
537 *MadtInterruptControllerType,
538 *MadtInterruptControllerLength
539 );
540 }
541 } // switch
542
543 InterruptContollerPtr += *MadtInterruptControllerLength;
544 Offset += *MadtInterruptControllerLength;
545 } // while
546 }