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