]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Madt/MadtParser.c
a1bf86ade5313f954a77b325c13394cfce133939
[mirror_edk2.git] / ShellPkg / Library / UefiShellAcpiViewCommandLib / Parsers / Madt / MadtParser.c
1 /** @file
2 MADT table parser
3
4 Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 @par Reference(s):
8 - ACPI 6.2 Specification - Errata A, September 2017
9 **/
10
11 #include <IndustryStandard/Acpi.h>
12 #include <Library/UefiLib.h>
13 #include "AcpiParser.h"
14 #include "AcpiTableParser.h"
15
16 // Local Variables
17 STATIC CONST UINT8* MadtInterruptControllerType;
18 STATIC CONST UINT8* MadtInterruptControllerLength;
19 STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;
20
21 /**
22 This function validates the System Vector Base in the GICD.
23
24 @param [in] Ptr Pointer to the start of the field data.
25 @param [in] Context Pointer to context specific information e.g. this
26 could be a pointer to the ACPI table header.
27 **/
28 STATIC
29 VOID
30 EFIAPI
31 ValidateGICDSystemVectorBase (
32 IN UINT8* Ptr,
33 IN VOID* Context
34 );
35
36 /**
37 An ACPI_PARSER array describing the GICC Interrupt Controller Structure.
38 **/
39 STATIC CONST ACPI_PARSER GicCParser[] = {
40 {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},
41 {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},
42 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},
43
44 {L"CPU Interface Number", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},
45 {L"ACPI Processor UID", 4, 8, L"0x%x", NULL, NULL, NULL, NULL},
46 {L"Flags", 4, 12, L"0x%x", NULL, NULL, NULL, NULL},
47 {L"Parking Protocol Version", 4, 16, L"0x%x", NULL, NULL, NULL, NULL},
48
49 {L"Performance Interrupt GSIV", 4, 20, L"0x%x", NULL, NULL, NULL, NULL},
50 {L"Parked Address", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL},
51 {L"Physical Base Address", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL},
52 {L"GICV", 8, 40, L"0x%lx", NULL, NULL, NULL, NULL},
53 {L"GICH", 8, 48, L"0x%lx", NULL, NULL, NULL, NULL},
54 {L"VGIC Maintenance interrupt", 4, 56, L"0x%x", NULL, NULL, NULL, NULL},
55 {L"GICR Base Address", 8, 60, L"0x%lx", NULL, NULL, NULL, NULL},
56 {L"MPIDR", 8, 68, L"0x%lx", NULL, NULL, NULL, NULL},
57 {L"Processor Power Efficiency Class", 1, 76, L"0x%x", NULL, NULL, NULL,
58 NULL},
59 {L"Reserved", 3, 77, L"%x %x %x", Dump3Chars, NULL, NULL, NULL}
60 };
61
62 /**
63 An ACPI_PARSER array describing the GICD Interrupt Controller Structure.
64 **/
65 STATIC CONST ACPI_PARSER GicDParser[] = {
66 {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},
67 {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},
68 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},
69
70 {L"GIC ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},
71 {L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL},
72 {L"System Vector Base", 4, 16, L"0x%x", NULL, NULL,
73 ValidateGICDSystemVectorBase, NULL},
74 {L"GIC Version", 1, 20, L"%d", NULL, NULL, NULL, NULL},
75 {L"Reserved", 3, 21, L"%x %x %x", Dump3Chars, NULL, NULL, NULL}
76 };
77
78 /**
79 An ACPI_PARSER array describing the MSI Frame Interrupt Controller Structure.
80 **/
81 STATIC CONST ACPI_PARSER GicMSIFrameParser[] = {
82 {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},
83 {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},
84 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},
85
86 {L"MSI Frame ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},
87 {L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL},
88 {L"Flags", 4, 16, L"0x%x", NULL, NULL, NULL, NULL},
89
90 {L"SPI Count", 2, 20, L"%d", NULL, NULL, NULL, NULL},
91 {L"SPI Base", 2, 22, L"0x%x", NULL, NULL, NULL, NULL}
92 };
93
94 /**
95 An ACPI_PARSER array describing the GICR Interrupt Controller Structure.
96 **/
97 STATIC CONST ACPI_PARSER GicRParser[] = {
98 {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},
99 {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},
100 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},
101
102 {L"Discovery Range Base Address", 8, 4, L"0x%lx", NULL, NULL, NULL,
103 NULL},
104 {L"Discovery Range Length", 4, 12, L"0x%x", NULL, NULL, NULL, NULL}
105 };
106
107 /**
108 An ACPI_PARSER array describing the GIC ITS Interrupt Controller Structure.
109 **/
110 STATIC CONST ACPI_PARSER GicITSParser[] = {
111 {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},
112 {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},
113 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},
114
115 {L"GIC ITS ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},
116 {L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL},
117 {L"Reserved", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}
118 };
119
120 /**
121 An ACPI_PARSER array describing the ACPI MADT Table.
122 **/
123 STATIC CONST ACPI_PARSER MadtParser[] = {
124 PARSE_ACPI_HEADER (&AcpiHdrInfo),
125 {L"Local Interrupt Controller Address", 4, 36, L"0x%x", NULL, NULL, NULL,
126 NULL},
127 {L"Flags", 4, 40, L"0x%x", NULL, NULL, NULL, NULL}
128 };
129
130 /**
131 An ACPI_PARSER array describing the MADT Interrupt Controller Structure Header Structure.
132 **/
133 STATIC CONST ACPI_PARSER MadtInterruptControllerHeaderParser[] = {
134 {NULL, 1, 0, NULL, NULL, (VOID**)&MadtInterruptControllerType, NULL, NULL},
135 {L"Length", 1, 1, NULL, NULL, (VOID**)&MadtInterruptControllerLength, NULL,
136 NULL},
137 {L"Reserved", 2, 2, NULL, NULL, NULL, NULL, NULL}
138 };
139
140 /**
141 This function validates the System Vector Base in the GICD.
142
143 @param [in] Ptr Pointer to the start of the field data.
144 @param [in] Context Pointer to context specific information e.g. this
145 could be a pointer to the ACPI table header.
146 **/
147 STATIC
148 VOID
149 EFIAPI
150 ValidateGICDSystemVectorBase (
151 IN UINT8* Ptr,
152 IN VOID* Context
153 )
154 {
155 if (*(UINT32*)Ptr != 0) {
156 IncrementErrorCount ();
157 Print (
158 L"\nERROR: System Vector Base must be zero."
159 );
160 }
161 }
162
163 /**
164 This function parses the ACPI MADT table.
165 When trace is enabled this function parses the MADT table and
166 traces the ACPI table fields.
167
168 This function currently parses the following Interrupt Controller
169 Structures:
170 - GICC
171 - GICD
172 - GIC MSI Frame
173 - GICR
174 - GIC ITS
175
176 This function also performs validation of the ACPI table fields.
177
178 @param [in] Trace If TRUE, trace the ACPI fields.
179 @param [in] Ptr Pointer to the start of the buffer.
180 @param [in] AcpiTableLength Length of the ACPI table.
181 @param [in] AcpiTableRevision Revision of the ACPI table.
182 **/
183 VOID
184 EFIAPI
185 ParseAcpiMadt (
186 IN BOOLEAN Trace,
187 IN UINT8* Ptr,
188 IN UINT32 AcpiTableLength,
189 IN UINT8 AcpiTableRevision
190 )
191 {
192 UINT32 Offset;
193 UINT8* InterruptContollerPtr;
194 UINT32 GICDCount;
195
196 GICDCount = 0;
197
198 if (!Trace) {
199 return;
200 }
201
202 Offset = ParseAcpi (
203 TRUE,
204 0,
205 "MADT",
206 Ptr,
207 AcpiTableLength,
208 PARSER_PARAMS (MadtParser)
209 );
210 InterruptContollerPtr = Ptr + Offset;
211
212 while (Offset < AcpiTableLength) {
213 // Parse Interrupt Controller Structure to obtain Length.
214 ParseAcpi (
215 FALSE,
216 0,
217 NULL,
218 InterruptContollerPtr,
219 2, // Length is 1 byte at offset 1
220 PARSER_PARAMS (MadtInterruptControllerHeaderParser)
221 );
222
223 if (((Offset + (*MadtInterruptControllerLength)) > AcpiTableLength) ||
224 (*MadtInterruptControllerLength < 4)) {
225 IncrementErrorCount ();
226 Print (
227 L"ERROR: Invalid Interrupt Controller Length,"
228 L" Type = %d, Length = %d\n",
229 *MadtInterruptControllerType,
230 *MadtInterruptControllerLength
231 );
232 break;
233 }
234
235 switch (*MadtInterruptControllerType) {
236 case EFI_ACPI_6_2_GIC: {
237 ParseAcpi (
238 TRUE,
239 2,
240 "GICC",
241 InterruptContollerPtr,
242 *MadtInterruptControllerLength,
243 PARSER_PARAMS (GicCParser)
244 );
245 break;
246 }
247
248 case EFI_ACPI_6_2_GICD: {
249 if (++GICDCount > 1) {
250 IncrementErrorCount ();
251 Print (
252 L"ERROR: Only one GICD must be present,"
253 L" GICDCount = %d\n",
254 GICDCount
255 );
256 }
257 ParseAcpi (
258 TRUE,
259 2,
260 "GICD",
261 InterruptContollerPtr,
262 *MadtInterruptControllerLength,
263 PARSER_PARAMS (GicDParser)
264 );
265 break;
266 }
267
268 case EFI_ACPI_6_2_GIC_MSI_FRAME: {
269 ParseAcpi (
270 TRUE,
271 2,
272 "GIC MSI Frame",
273 InterruptContollerPtr,
274 *MadtInterruptControllerLength,
275 PARSER_PARAMS (GicMSIFrameParser)
276 );
277 break;
278 }
279
280 case EFI_ACPI_6_2_GICR: {
281 ParseAcpi (
282 TRUE,
283 2,
284 "GICR",
285 InterruptContollerPtr,
286 *MadtInterruptControllerLength,
287 PARSER_PARAMS (GicRParser)
288 );
289 break;
290 }
291
292 case EFI_ACPI_6_2_GIC_ITS: {
293 ParseAcpi (
294 TRUE,
295 2,
296 "GIC ITS",
297 InterruptContollerPtr,
298 *MadtInterruptControllerLength,
299 PARSER_PARAMS (GicITSParser)
300 );
301 break;
302 }
303
304 default: {
305 IncrementErrorCount ();
306 Print (
307 L"ERROR: Unknown Interrupt Controller Structure,"
308 L" Type = %d, Length = %d\n",
309 *MadtInterruptControllerType,
310 *MadtInterruptControllerLength
311 );
312 }
313 } // switch
314
315 InterruptContollerPtr += *MadtInterruptControllerLength;
316 Offset += *MadtInterruptControllerLength;
317 } // while
318 }