]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Dbg2/Dbg2Parser.c
ShellPkg: acpiview: Prevent infinite loop if structure length is 0
[mirror_edk2.git] / ShellPkg / Library / UefiShellAcpiViewCommandLib / Parsers / Dbg2 / Dbg2Parser.c
CommitLineData
a6eaba4d 1/** @file\r
ee4dc24f
RN
2 DBG2 table parser\r
3\r
b8504826 4 Copyright (c) 2016 - 2020, 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
8 - Microsoft Debug Port Table 2 (DBG2) Specification - December 10, 2015.\r
9**/\r
10\r
11#include <IndustryStandard/DebugPort2Table.h>\r
12#include <Library/UefiLib.h>\r
13#include "AcpiParser.h"\r
14#include "AcpiTableParser.h"\r
15\r
16// Local variables pointing to the table fields\r
17STATIC CONST UINT32* OffsetDbgDeviceInfo;\r
18STATIC CONST UINT32* NumberDbgDeviceInfo;\r
19STATIC CONST UINT16* DbgDevInfoLen;\r
20STATIC CONST UINT8* GasCount;\r
21STATIC CONST UINT16* NameSpaceStringLength;\r
22STATIC CONST UINT16* NameSpaceStringOffset;\r
23STATIC CONST UINT16* OEMDataLength;\r
24STATIC CONST UINT16* OEMDataOffset;\r
25STATIC CONST UINT16* BaseAddrRegOffset;\r
26STATIC CONST UINT16* AddrSizeOffset;\r
27STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;\r
28\r
a6eaba4d 29/**\r
8ff68cd5 30 This function validates the NameSpace string length.\r
ee4dc24f
RN
31\r
32 @param [in] Ptr Pointer to the start of the buffer.\r
33 @param [in] Context Pointer to context specific information e.g. this\r
34 could be a pointer to the ACPI table header.\r
a6eaba4d 35**/\r
ee4dc24f
RN
36STATIC\r
37VOID\r
38EFIAPI\r
39ValidateNameSpaceStrLen (\r
8ff68cd5
KK
40 IN UINT8* Ptr,\r
41 IN VOID* Context\r
42 )\r
43{\r
44 UINT16 NameSpaceStrLen;\r
ee4dc24f 45\r
8ff68cd5 46 NameSpaceStrLen = *(UINT16*)Ptr;\r
ee4dc24f 47\r
8ff68cd5
KK
48 if (NameSpaceStrLen < 2) {\r
49 IncrementErrorCount ();\r
50 Print (\r
51 L"\nERROR: NamespaceString Length = %d. If no Namespace device exists, " \\r
52 L"NamespaceString[] must contain a period '.'",\r
53 NameSpaceStrLen\r
54 );\r
55 }\r
56}\r
ee4dc24f
RN
57\r
58/// An ACPI_PARSER array describing the ACPI DBG2 table.\r
59STATIC CONST ACPI_PARSER Dbg2Parser[] = {\r
60 PARSE_ACPI_HEADER (&AcpiHdrInfo),\r
61 {L"OffsetDbgDeviceInfo", 4, 36, L"0x%x", NULL,\r
62 (VOID**)&OffsetDbgDeviceInfo, NULL, NULL},\r
63 {L"NumberDbgDeviceInfo", 4, 40, L"%d", NULL,\r
64 (VOID**)&NumberDbgDeviceInfo, NULL, NULL}\r
65};\r
66\r
ffb18f77
KK
67/// An ACPI_PARSER array describing the debug device information structure\r
68/// header.\r
69STATIC CONST ACPI_PARSER DbgDevInfoHeaderParser[] = {\r
70 {L"Revision", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
71 {L"Length", 2, 1, L"%d", NULL, (VOID**)&DbgDevInfoLen, NULL, NULL}\r
72};\r
73\r
ee4dc24f
RN
74/// An ACPI_PARSER array describing the debug device information.\r
75STATIC CONST ACPI_PARSER DbgDevInfoParser[] = {\r
76 {L"Revision", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
ffb18f77 77 {L"Length", 2, 1, L"%d", NULL, NULL, NULL, NULL},\r
ee4dc24f
RN
78\r
79 {L"Generic Address Registers Count", 1, 3, L"0x%x", NULL,\r
80 (VOID**)&GasCount, NULL, NULL},\r
81 {L"NameSpace String Length", 2, 4, L"%d", NULL,\r
82 (VOID**)&NameSpaceStringLength, ValidateNameSpaceStrLen, NULL},\r
83 {L"NameSpace String Offset", 2, 6, L"0x%x", NULL,\r
84 (VOID**)&NameSpaceStringOffset, NULL, NULL},\r
85 {L"OEM Data Length", 2, 8, L"%d", NULL, (VOID**)&OEMDataLength,\r
86 NULL, NULL},\r
87 {L"OEM Data Offset", 2, 10, L"0x%x", NULL, (VOID**)&OEMDataOffset,\r
88 NULL, NULL},\r
89\r
90 {L"Port Type", 2, 12, L"0x%x", NULL, NULL, NULL, NULL},\r
91 {L"Port SubType", 2, 14, L"0x%x", NULL, NULL, NULL, NULL},\r
92 {L"Reserved", 2, 16, L"%x", NULL, NULL, NULL, NULL},\r
93\r
94 {L"Base Address Register Offset", 2, 18, L"0x%x", NULL,\r
95 (VOID**)&BaseAddrRegOffset, NULL, NULL},\r
96 {L"Address Size Offset", 2, 20, L"0x%x", NULL,\r
97 (VOID**)&AddrSizeOffset, NULL, NULL}\r
98};\r
99\r
a6eaba4d
DB
100/**\r
101 This function parses the debug device information structure.\r
ee4dc24f 102\r
ffb18f77
KK
103 @param [in] Ptr Pointer to the start of the buffer.\r
104 @param [in] Length Length of the debug device information structure.\r
a6eaba4d 105**/\r
ee4dc24f
RN
106STATIC\r
107VOID\r
108EFIAPI\r
109DumpDbgDeviceInfo (\r
ffb18f77
KK
110 IN UINT8* Ptr,\r
111 IN UINT16 Length\r
ee4dc24f
RN
112 )\r
113{\r
114 UINT16 Index;\r
ffb18f77 115 UINT16 Offset;\r
ee4dc24f
RN
116\r
117 ParseAcpi (\r
118 TRUE,\r
119 2,\r
120 "Debug Device Info",\r
121 Ptr,\r
ffb18f77 122 Length,\r
ee4dc24f
RN
123 PARSER_PARAMS (DbgDevInfoParser)\r
124 );\r
125\r
ccb4c38a
KK
126 // Check if the values used to control the parsing logic have been\r
127 // successfully read.\r
128 if ((GasCount == NULL) ||\r
129 (NameSpaceStringLength == NULL) ||\r
130 (NameSpaceStringOffset == NULL) ||\r
131 (OEMDataLength == NULL) ||\r
132 (OEMDataOffset == NULL) ||\r
133 (BaseAddrRegOffset == NULL) ||\r
134 (AddrSizeOffset == NULL)) {\r
135 IncrementErrorCount ();\r
136 Print (\r
137 L"ERROR: Insufficient Debug Device Information Structure length. " \\r
138 L"Length = %d.\n",\r
139 Length\r
140 );\r
141 return;\r
142 }\r
143\r
ffb18f77 144 // GAS\r
ee4dc24f 145 Index = 0;\r
ffb18f77
KK
146 Offset = *BaseAddrRegOffset;\r
147 while ((Index++ < *GasCount) &&\r
148 (Offset < Length)) {\r
ee4dc24f 149 PrintFieldName (4, L"BaseAddressRegister");\r
ffb18f77
KK
150 Offset += (UINT16)DumpGasStruct (\r
151 Ptr + Offset,\r
152 4,\r
153 Length - Offset\r
154 );\r
155 }\r
156\r
157 // Make sure the array of address sizes corresponding to each GAS fit in the\r
158 // Debug Device Information structure\r
159 if ((*AddrSizeOffset + (*GasCount * sizeof (UINT32))) > Length) {\r
160 IncrementErrorCount ();\r
161 Print (\r
162 L"ERROR: Invalid GAS count. GasCount = %d. RemainingBufferLength = %d. " \\r
163 L"Parsing of the Debug Device Information structure aborted.\n",\r
164 *GasCount,\r
165 Length - *AddrSizeOffset\r
166 );\r
167 return;\r
168 }\r
169\r
170 // Address Size\r
171 Index = 0;\r
172 Offset = *AddrSizeOffset;\r
173 while ((Index++ < *GasCount) &&\r
174 (Offset < Length)) {\r
ee4dc24f 175 PrintFieldName (4, L"Address Size");\r
ffb18f77
KK
176 Print (L"0x%x\n", *((UINT32*)(Ptr + Offset)));\r
177 Offset += sizeof (UINT32);\r
ee4dc24f
RN
178 }\r
179\r
180 // NameSpace String\r
181 Index = 0;\r
ffb18f77 182 Offset = *NameSpaceStringOffset;\r
ee4dc24f 183 PrintFieldName (4, L"NameSpace String");\r
ffb18f77
KK
184 while ((Index++ < *NameSpaceStringLength) &&\r
185 (Offset < Length)) {\r
186 Print (L"%c", *(Ptr + Offset));\r
187 Offset++;\r
ee4dc24f
RN
188 }\r
189 Print (L"\n");\r
190\r
191 // OEM Data\r
ffb18f77
KK
192 if (*OEMDataOffset != 0) {\r
193 Index = 0;\r
194 Offset = *OEMDataOffset;\r
195 PrintFieldName (4, L"OEM Data");\r
196 while ((Index++ < *OEMDataLength) &&\r
197 (Offset < Length)) {\r
198 Print (L"%x ", *(Ptr + Offset));\r
199 if ((Index & 7) == 0) {\r
200 Print (L"\n%-*s ", OUTPUT_FIELD_COLUMN_WIDTH, L"");\r
201 }\r
202 Offset++;\r
ee4dc24f 203 }\r
ffb18f77 204 Print (L"\n");\r
ee4dc24f 205 }\r
ee4dc24f
RN
206}\r
207\r
a6eaba4d
DB
208/**\r
209 This function parses the ACPI DBG2 table.\r
ee4dc24f
RN
210 When trace is enabled this function parses the DBG2 table and\r
211 traces the ACPI table fields.\r
212\r
213 This function also performs validation of the ACPI table fields.\r
214\r
215 @param [in] Trace If TRUE, trace the ACPI fields.\r
216 @param [in] Ptr Pointer to the start of the buffer.\r
217 @param [in] AcpiTableLength Length of the ACPI table.\r
218 @param [in] AcpiTableRevision Revision of the ACPI table.\r
a6eaba4d 219**/\r
ee4dc24f
RN
220VOID\r
221EFIAPI\r
222ParseAcpiDbg2 (\r
223 IN BOOLEAN Trace,\r
224 IN UINT8* Ptr,\r
225 IN UINT32 AcpiTableLength,\r
226 IN UINT8 AcpiTableRevision\r
227 )\r
228{\r
229 UINT32 Offset;\r
ffb18f77 230 UINT32 Index;\r
ee4dc24f
RN
231\r
232 if (!Trace) {\r
233 return;\r
234 }\r
235\r
236 Offset = ParseAcpi (\r
237 TRUE,\r
238 0,\r
239 "DBG2",\r
240 Ptr,\r
241 AcpiTableLength,\r
242 PARSER_PARAMS (Dbg2Parser)\r
243 );\r
ee4dc24f 244\r
ccb4c38a
KK
245 // Check if the values used to control the parsing logic have been\r
246 // successfully read.\r
247 if ((OffsetDbgDeviceInfo == NULL) ||\r
248 (NumberDbgDeviceInfo == NULL)) {\r
249 IncrementErrorCount ();\r
250 Print (\r
251 L"ERROR: Insufficient table length. AcpiTableLength = %d\n",\r
252 AcpiTableLength\r
253 );\r
254 return;\r
255 }\r
256\r
ffb18f77
KK
257 Offset = *OffsetDbgDeviceInfo;\r
258 Index = 0;\r
259\r
260 while (Index++ < *NumberDbgDeviceInfo) {\r
261\r
262 // Parse the Debug Device Information Structure header to obtain Length\r
263 ParseAcpi (\r
264 FALSE,\r
265 0,\r
266 NULL,\r
267 Ptr + Offset,\r
268 AcpiTableLength - Offset,\r
269 PARSER_PARAMS (DbgDevInfoHeaderParser)\r
ee4dc24f 270 );\r
ffb18f77 271\r
ccb4c38a
KK
272 // Check if the values used to control the parsing logic have been\r
273 // successfully read.\r
274 if (DbgDevInfoLen == NULL) {\r
275 IncrementErrorCount ();\r
276 Print (\r
277 L"ERROR: Insufficient remaining table buffer length to read the " \\r
278 L"Debug Device Information structure's 'Length' field. " \\r
279 L"RemainingTableBufferLength = %d.\n",\r
280 AcpiTableLength - Offset\r
281 );\r
282 return;\r
283 }\r
284\r
b8504826
KK
285 // Validate Debug Device Information Structure length\r
286 if ((*DbgDevInfoLen == 0) ||\r
287 ((Offset + (*DbgDevInfoLen)) > AcpiTableLength)) {\r
ffb18f77
KK
288 IncrementErrorCount ();\r
289 Print (\r
b8504826
KK
290 L"ERROR: Invalid Debug Device Information Structure length. " \\r
291 L"Length = %d. Offset = %d. AcpiTableLength = %d.\n",\r
ffb18f77 292 *DbgDevInfoLen,\r
b8504826
KK
293 Offset,\r
294 AcpiTableLength\r
ffb18f77
KK
295 );\r
296 return;\r
297 }\r
298\r
299 DumpDbgDeviceInfo (Ptr + Offset, (*DbgDevInfoLen));\r
300 Offset += (*DbgDevInfoLen);\r
ee4dc24f
RN
301 }\r
302}\r