]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Madt/MadtParser.c
ShellPkg: acpiview: MADT: Prevent buffer overruns
[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
d23bf797
KK
263 // Make sure forward progress is made.\r
264 if (*MadtInterruptControllerLength < 2) {\r
ee4dc24f
RN
265 IncrementErrorCount ();\r
266 Print (\r
d23bf797
KK
267 L"ERROR: Structure length is too small: " \\r
268 L"MadtInterruptControllerLength = %d. " \\r
269 L"MadtInterruptControllerType = %d. MADT parsing aborted.\n",\r
270 *MadtInterruptControllerLength,\r
271 *MadtInterruptControllerType\r
272 );\r
273 return;\r
274 }\r
275\r
276 // Make sure the MADT structure lies inside the table\r
277 if ((Offset + *MadtInterruptControllerLength) > AcpiTableLength) {\r
278 IncrementErrorCount ();\r
279 Print (\r
280 L"ERROR: Invalid MADT structure length. " \\r
281 L"MadtInterruptControllerLength = %d. " \\r
282 L"RemainingTableBufferLength = %d. MADT parsing aborted.\n",\r
283 *MadtInterruptControllerLength,\r
284 AcpiTableLength - Offset\r
285 );\r
286 return;\r
ee4dc24f
RN
287 }\r
288\r
289 switch (*MadtInterruptControllerType) {\r
8a08dc54 290 case EFI_ACPI_6_3_GIC: {\r
ee4dc24f
RN
291 ParseAcpi (\r
292 TRUE,\r
293 2,\r
294 "GICC",\r
295 InterruptContollerPtr,\r
296 *MadtInterruptControllerLength,\r
297 PARSER_PARAMS (GicCParser)\r
298 );\r
299 break;\r
300 }\r
301\r
8a08dc54 302 case EFI_ACPI_6_3_GICD: {\r
ee4dc24f
RN
303 if (++GICDCount > 1) {\r
304 IncrementErrorCount ();\r
305 Print (\r
306 L"ERROR: Only one GICD must be present,"\r
e6f958d1 307 L" GICDCount = %d\n",\r
ee4dc24f
RN
308 GICDCount\r
309 );\r
310 }\r
311 ParseAcpi (\r
312 TRUE,\r
313 2,\r
314 "GICD",\r
315 InterruptContollerPtr,\r
316 *MadtInterruptControllerLength,\r
317 PARSER_PARAMS (GicDParser)\r
318 );\r
319 break;\r
320 }\r
321\r
8a08dc54 322 case EFI_ACPI_6_3_GIC_MSI_FRAME: {\r
ee4dc24f
RN
323 ParseAcpi (\r
324 TRUE,\r
325 2,\r
326 "GIC MSI Frame",\r
327 InterruptContollerPtr,\r
328 *MadtInterruptControllerLength,\r
329 PARSER_PARAMS (GicMSIFrameParser)\r
330 );\r
331 break;\r
332 }\r
333\r
8a08dc54 334 case EFI_ACPI_6_3_GICR: {\r
ee4dc24f
RN
335 ParseAcpi (\r
336 TRUE,\r
337 2,\r
338 "GICR",\r
339 InterruptContollerPtr,\r
340 *MadtInterruptControllerLength,\r
341 PARSER_PARAMS (GicRParser)\r
342 );\r
343 break;\r
344 }\r
345\r
8a08dc54 346 case EFI_ACPI_6_3_GIC_ITS: {\r
ee4dc24f
RN
347 ParseAcpi (\r
348 TRUE,\r
349 2,\r
350 "GIC ITS",\r
351 InterruptContollerPtr,\r
352 *MadtInterruptControllerLength,\r
353 PARSER_PARAMS (GicITSParser)\r
354 );\r
355 break;\r
356 }\r
357\r
358 default: {\r
359 IncrementErrorCount ();\r
360 Print (\r
361 L"ERROR: Unknown Interrupt Controller Structure,"\r
e6f958d1 362 L" Type = %d, Length = %d\n",\r
ee4dc24f
RN
363 *MadtInterruptControllerType,\r
364 *MadtInterruptControllerLength\r
365 );\r
366 }\r
367 } // switch\r
368\r
369 InterruptContollerPtr += *MadtInterruptControllerLength;\r
370 Offset += *MadtInterruptControllerLength;\r
371 } // while\r
372}\r