]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Madt/MadtParser.c
ShellPkg: acpiview: MADT: Validate global pointers before use
[mirror_edk2.git] / ShellPkg / Library / UefiShellAcpiViewCommandLib / Parsers / Madt / MadtParser.c
CommitLineData
a6eaba4d 1/** @file\r
ee4dc24f
RN
2 MADT table parser\r
3\r
8a08dc54 4 Copyright (c) 2016 - 2019, ARM Limited. All rights reserved.\r
56ba3746 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
ee4dc24f
RN
6\r
7 @par Reference(s):\r
8a08dc54
KK
8 - ACPI 6.3 Specification - January 2019\r
9 - Arm Generic Interrupt Controller Architecture Specification,\r
10 GIC architecture version 3 and version 4, issue E\r
11 - Arm Server Base System Architecture 5.0\r
ee4dc24f
RN
12**/\r
13\r
14#include <IndustryStandard/Acpi.h>\r
15#include <Library/UefiLib.h>\r
16#include "AcpiParser.h"\r
17#include "AcpiTableParser.h"\r
8a08dc54 18#include "MadtParser.h"\r
ee4dc24f
RN
19\r
20// Local Variables\r
21STATIC CONST UINT8* MadtInterruptControllerType;\r
22STATIC CONST UINT8* MadtInterruptControllerLength;\r
23STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;\r
24\r
a6eaba4d
DB
25/**\r
26 This function validates the System Vector Base in the GICD.\r
27\r
28 @param [in] Ptr Pointer to the start of the field data.\r
29 @param [in] Context Pointer to context specific information e.g. this\r
30 could be a pointer to the ACPI table header.\r
31**/\r
ee4dc24f
RN
32STATIC\r
33VOID\r
34EFIAPI\r
35ValidateGICDSystemVectorBase (\r
36 IN UINT8* Ptr,\r
37 IN VOID* Context\r
9cb5bcce
KK
38)\r
39{\r
40 if (*(UINT32*)Ptr != 0) {\r
41 IncrementErrorCount ();\r
42 Print (\r
43 L"\nERROR: System Vector Base must be zero."\r
44 );\r
45 }\r
46}\r
ee4dc24f 47\r
8a08dc54
KK
48/**\r
49 This function validates the SPE Overflow Interrupt in the GICC.\r
50\r
51 @param [in] Ptr Pointer to the start of the field data.\r
52 @param [in] Context Pointer to context specific information e.g. this\r
53 could be a pointer to the ACPI table header.\r
54**/\r
55STATIC\r
56VOID\r
57EFIAPI\r
58ValidateSpeOverflowInterrupt (\r
59 IN UINT8* Ptr,\r
60 IN VOID* Context\r
9cb5bcce
KK
61 )\r
62{\r
63 UINT16 SpeOverflowInterrupt;\r
64\r
65 SpeOverflowInterrupt = *(UINT16*)Ptr;\r
66\r
67 // SPE not supported by this processor\r
68 if (SpeOverflowInterrupt == 0) {\r
69 return;\r
70 }\r
71\r
72 if ((SpeOverflowInterrupt < ARM_PPI_ID_MIN) ||\r
73 ((SpeOverflowInterrupt > ARM_PPI_ID_MAX) &&\r
74 (SpeOverflowInterrupt < ARM_PPI_ID_EXTENDED_MIN)) ||\r
75 (SpeOverflowInterrupt > ARM_PPI_ID_EXTENDED_MAX)) {\r
76 IncrementErrorCount ();\r
77 Print (\r
78 L"\nERROR: SPE Overflow Interrupt ID of %d is not in the allowed PPI ID "\r
79 L"ranges of %d-%d or %d-%d (for GICv3.1 or later).",\r
80 SpeOverflowInterrupt,\r
81 ARM_PPI_ID_MIN,\r
82 ARM_PPI_ID_MAX,\r
83 ARM_PPI_ID_EXTENDED_MIN,\r
84 ARM_PPI_ID_EXTENDED_MAX\r
85 );\r
86 } else if (SpeOverflowInterrupt != ARM_PPI_ID_PMBIRQ) {\r
87 IncrementWarningCount();\r
88 Print (\r
89 L"\nWARNING: SPE Overflow Interrupt ID of %d is not compliant with SBSA "\r
90 L"Level 3 PPI ID assignment: %d.",\r
91 SpeOverflowInterrupt,\r
92 ARM_PPI_ID_PMBIRQ\r
93 );\r
94 }\r
95}\r
8a08dc54 96\r
a6eaba4d
DB
97/**\r
98 An ACPI_PARSER array describing the GICC Interrupt Controller Structure.\r
99**/\r
ee4dc24f
RN
100STATIC CONST ACPI_PARSER GicCParser[] = {\r
101 {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
102 {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},\r
103 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},\r
104\r
105 {L"CPU Interface Number", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r
106 {L"ACPI Processor UID", 4, 8, L"0x%x", NULL, NULL, NULL, NULL},\r
107 {L"Flags", 4, 12, L"0x%x", NULL, NULL, NULL, NULL},\r
108 {L"Parking Protocol Version", 4, 16, L"0x%x", NULL, NULL, NULL, NULL},\r
109\r
110 {L"Performance Interrupt GSIV", 4, 20, L"0x%x", NULL, NULL, NULL, NULL},\r
111 {L"Parked Address", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL},\r
112 {L"Physical Base Address", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL},\r
113 {L"GICV", 8, 40, L"0x%lx", NULL, NULL, NULL, NULL},\r
114 {L"GICH", 8, 48, L"0x%lx", NULL, NULL, NULL, NULL},\r
115 {L"VGIC Maintenance interrupt", 4, 56, L"0x%x", NULL, NULL, NULL, NULL},\r
116 {L"GICR Base Address", 8, 60, L"0x%lx", NULL, NULL, NULL, NULL},\r
117 {L"MPIDR", 8, 68, L"0x%lx", NULL, NULL, NULL, NULL},\r
118 {L"Processor Power Efficiency Class", 1, 76, L"0x%x", NULL, NULL, NULL,\r
119 NULL},\r
8a08dc54
KK
120 {L"Reserved", 1, 77, L"0x%x", NULL, NULL, NULL, NULL},\r
121 {L"SPE overflow Interrupt", 2, 78, L"0x%x", NULL, NULL,\r
122 ValidateSpeOverflowInterrupt, NULL}\r
ee4dc24f
RN
123};\r
124\r
a6eaba4d
DB
125/**\r
126 An ACPI_PARSER array describing the GICD Interrupt Controller Structure.\r
127**/\r
ee4dc24f
RN
128STATIC CONST ACPI_PARSER GicDParser[] = {\r
129 {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
130 {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},\r
131 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},\r
132\r
133 {L"GIC ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r
134 {L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL},\r
135 {L"System Vector Base", 4, 16, L"0x%x", NULL, NULL,\r
136 ValidateGICDSystemVectorBase, NULL},\r
137 {L"GIC Version", 1, 20, L"%d", NULL, NULL, NULL, NULL},\r
138 {L"Reserved", 3, 21, L"%x %x %x", Dump3Chars, NULL, NULL, NULL}\r
139};\r
140\r
a6eaba4d
DB
141/**\r
142 An ACPI_PARSER array describing the MSI Frame Interrupt Controller Structure.\r
143**/\r
ee4dc24f
RN
144STATIC CONST ACPI_PARSER GicMSIFrameParser[] = {\r
145 {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
146 {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},\r
147 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},\r
148\r
149 {L"MSI Frame ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r
150 {L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL},\r
151 {L"Flags", 4, 16, L"0x%x", NULL, NULL, NULL, NULL},\r
152\r
153 {L"SPI Count", 2, 20, L"%d", NULL, NULL, NULL, NULL},\r
154 {L"SPI Base", 2, 22, L"0x%x", NULL, NULL, NULL, NULL}\r
155};\r
156\r
a6eaba4d
DB
157/**\r
158 An ACPI_PARSER array describing the GICR Interrupt Controller Structure.\r
159**/\r
ee4dc24f
RN
160STATIC CONST ACPI_PARSER GicRParser[] = {\r
161 {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
162 {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},\r
163 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},\r
164\r
165 {L"Discovery Range Base Address", 8, 4, L"0x%lx", NULL, NULL, NULL,\r
166 NULL},\r
167 {L"Discovery Range Length", 4, 12, L"0x%x", NULL, NULL, NULL, NULL}\r
168};\r
169\r
a6eaba4d
DB
170/**\r
171 An ACPI_PARSER array describing the GIC ITS Interrupt Controller Structure.\r
172**/\r
ee4dc24f
RN
173STATIC CONST ACPI_PARSER GicITSParser[] = {\r
174 {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
175 {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},\r
176 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},\r
177\r
178 {L"GIC ITS ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r
179 {L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL},\r
180 {L"Reserved", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}\r
181};\r
182\r
a6eaba4d
DB
183/**\r
184 An ACPI_PARSER array describing the ACPI MADT Table.\r
185**/\r
ee4dc24f
RN
186STATIC CONST ACPI_PARSER MadtParser[] = {\r
187 PARSE_ACPI_HEADER (&AcpiHdrInfo),\r
188 {L"Local Interrupt Controller Address", 4, 36, L"0x%x", NULL, NULL, NULL,\r
189 NULL},\r
190 {L"Flags", 4, 40, L"0x%x", NULL, NULL, NULL, NULL}\r
191};\r
192\r
a6eaba4d
DB
193/**\r
194 An ACPI_PARSER array describing the MADT Interrupt Controller Structure Header Structure.\r
195**/\r
ee4dc24f
RN
196STATIC CONST ACPI_PARSER MadtInterruptControllerHeaderParser[] = {\r
197 {NULL, 1, 0, NULL, NULL, (VOID**)&MadtInterruptControllerType, NULL, NULL},\r
198 {L"Length", 1, 1, NULL, NULL, (VOID**)&MadtInterruptControllerLength, NULL,\r
199 NULL},\r
200 {L"Reserved", 2, 2, NULL, NULL, NULL, NULL, NULL}\r
201};\r
202\r
a6eaba4d
DB
203/**\r
204 This function parses the ACPI MADT table.\r
ee4dc24f
RN
205 When trace is enabled this function parses the MADT table and\r
206 traces the ACPI table fields.\r
207\r
208 This function currently parses the following Interrupt Controller\r
209 Structures:\r
210 - GICC\r
211 - GICD\r
212 - GIC MSI Frame\r
213 - GICR\r
214 - GIC ITS\r
215\r
216 This function also performs validation of the ACPI table fields.\r
217\r
218 @param [in] Trace If TRUE, trace the ACPI fields.\r
219 @param [in] Ptr Pointer to the start of the buffer.\r
220 @param [in] AcpiTableLength Length of the ACPI table.\r
221 @param [in] AcpiTableRevision Revision of the ACPI table.\r
a6eaba4d 222**/\r
ee4dc24f
RN
223VOID\r
224EFIAPI\r
225ParseAcpiMadt (\r
226 IN BOOLEAN Trace,\r
227 IN UINT8* Ptr,\r
228 IN UINT32 AcpiTableLength,\r
229 IN UINT8 AcpiTableRevision\r
230 )\r
231{\r
232 UINT32 Offset;\r
233 UINT8* InterruptContollerPtr;\r
f75c7478
DB
234 UINT32 GICDCount;\r
235\r
236 GICDCount = 0;\r
ee4dc24f
RN
237\r
238 if (!Trace) {\r
239 return;\r
240 }\r
241\r
242 Offset = ParseAcpi (\r
243 TRUE,\r
244 0,\r
245 "MADT",\r
246 Ptr,\r
247 AcpiTableLength,\r
248 PARSER_PARAMS (MadtParser)\r
249 );\r
250 InterruptContollerPtr = Ptr + Offset;\r
251\r
252 while (Offset < AcpiTableLength) {\r
253 // Parse Interrupt Controller Structure to obtain Length.\r
254 ParseAcpi (\r
255 FALSE,\r
256 0,\r
257 NULL,\r
258 InterruptContollerPtr,\r
05d40295 259 AcpiTableLength - Offset,\r
ee4dc24f
RN
260 PARSER_PARAMS (MadtInterruptControllerHeaderParser)\r
261 );\r
262\r
c4a53853
KK
263 // Check if the values used to control the parsing logic have been\r
264 // successfully read.\r
265 if ((MadtInterruptControllerType == NULL) ||\r
266 (MadtInterruptControllerLength == NULL)) {\r
267 IncrementErrorCount ();\r
268 Print (\r
269 L"ERROR: Insufficient remaining table buffer length to read the " \\r
270 L"Interrupt Controller Structure header. Length = %d.\n",\r
271 AcpiTableLength - Offset\r
272 );\r
273 return;\r
274 }\r
275\r
d23bf797
KK
276 // Make sure forward progress is made.\r
277 if (*MadtInterruptControllerLength < 2) {\r
ee4dc24f
RN
278 IncrementErrorCount ();\r
279 Print (\r
d23bf797
KK
280 L"ERROR: Structure length is too small: " \\r
281 L"MadtInterruptControllerLength = %d. " \\r
282 L"MadtInterruptControllerType = %d. MADT parsing aborted.\n",\r
283 *MadtInterruptControllerLength,\r
284 *MadtInterruptControllerType\r
285 );\r
286 return;\r
287 }\r
288\r
289 // Make sure the MADT structure lies inside the table\r
290 if ((Offset + *MadtInterruptControllerLength) > AcpiTableLength) {\r
291 IncrementErrorCount ();\r
292 Print (\r
293 L"ERROR: Invalid MADT structure length. " \\r
294 L"MadtInterruptControllerLength = %d. " \\r
295 L"RemainingTableBufferLength = %d. MADT parsing aborted.\n",\r
296 *MadtInterruptControllerLength,\r
297 AcpiTableLength - Offset\r
298 );\r
299 return;\r
ee4dc24f
RN
300 }\r
301\r
302 switch (*MadtInterruptControllerType) {\r
8a08dc54 303 case EFI_ACPI_6_3_GIC: {\r
ee4dc24f
RN
304 ParseAcpi (\r
305 TRUE,\r
306 2,\r
307 "GICC",\r
308 InterruptContollerPtr,\r
309 *MadtInterruptControllerLength,\r
310 PARSER_PARAMS (GicCParser)\r
311 );\r
312 break;\r
313 }\r
314\r
8a08dc54 315 case EFI_ACPI_6_3_GICD: {\r
ee4dc24f
RN
316 if (++GICDCount > 1) {\r
317 IncrementErrorCount ();\r
318 Print (\r
319 L"ERROR: Only one GICD must be present,"\r
e6f958d1 320 L" GICDCount = %d\n",\r
ee4dc24f
RN
321 GICDCount\r
322 );\r
323 }\r
324 ParseAcpi (\r
325 TRUE,\r
326 2,\r
327 "GICD",\r
328 InterruptContollerPtr,\r
329 *MadtInterruptControllerLength,\r
330 PARSER_PARAMS (GicDParser)\r
331 );\r
332 break;\r
333 }\r
334\r
8a08dc54 335 case EFI_ACPI_6_3_GIC_MSI_FRAME: {\r
ee4dc24f
RN
336 ParseAcpi (\r
337 TRUE,\r
338 2,\r
339 "GIC MSI Frame",\r
340 InterruptContollerPtr,\r
341 *MadtInterruptControllerLength,\r
342 PARSER_PARAMS (GicMSIFrameParser)\r
343 );\r
344 break;\r
345 }\r
346\r
8a08dc54 347 case EFI_ACPI_6_3_GICR: {\r
ee4dc24f
RN
348 ParseAcpi (\r
349 TRUE,\r
350 2,\r
351 "GICR",\r
352 InterruptContollerPtr,\r
353 *MadtInterruptControllerLength,\r
354 PARSER_PARAMS (GicRParser)\r
355 );\r
356 break;\r
357 }\r
358\r
8a08dc54 359 case EFI_ACPI_6_3_GIC_ITS: {\r
ee4dc24f
RN
360 ParseAcpi (\r
361 TRUE,\r
362 2,\r
363 "GIC ITS",\r
364 InterruptContollerPtr,\r
365 *MadtInterruptControllerLength,\r
366 PARSER_PARAMS (GicITSParser)\r
367 );\r
368 break;\r
369 }\r
370\r
371 default: {\r
372 IncrementErrorCount ();\r
373 Print (\r
374 L"ERROR: Unknown Interrupt Controller Structure,"\r
e6f958d1 375 L" Type = %d, Length = %d\n",\r
ee4dc24f
RN
376 *MadtInterruptControllerType,\r
377 *MadtInterruptControllerLength\r
378 );\r
379 }\r
380 } // switch\r
381\r
382 InterruptContollerPtr += *MadtInterruptControllerLength;\r
383 Offset += *MadtInterruptControllerLength;\r
384 } // while\r
385}\r