]>
Commit | Line | Data |
---|---|---|
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 | |
47d20b54 MK |
17 | STATIC CONST UINT32 *OffsetDbgDeviceInfo;\r |
18 | STATIC CONST UINT32 *NumberDbgDeviceInfo;\r | |
19 | STATIC CONST UINT16 *DbgDevInfoLen;\r | |
20 | STATIC CONST UINT8 *GasCount;\r | |
21 | STATIC CONST UINT16 *NameSpaceStringLength;\r | |
22 | STATIC CONST UINT16 *NameSpaceStringOffset;\r | |
23 | STATIC CONST UINT16 *OEMDataLength;\r | |
24 | STATIC CONST UINT16 *OEMDataOffset;\r | |
25 | STATIC CONST UINT16 *BaseAddrRegOffset;\r | |
26 | STATIC CONST UINT16 *AddrSizeOffset;\r | |
27 | STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;\r | |
ee4dc24f | 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 |
36 | STATIC\r |
37 | VOID\r | |
38 | EFIAPI\r | |
39 | ValidateNameSpaceStrLen (\r | |
47d20b54 MK |
40 | IN UINT8 *Ptr,\r |
41 | IN VOID *Context\r | |
8ff68cd5 KK |
42 | )\r |
43 | {\r | |
47d20b54 | 44 | UINT16 NameSpaceStrLen;\r |
ee4dc24f | 45 | \r |
47d20b54 | 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 | |
47d20b54 | 52 | L"NamespaceString[] must contain a period '.'",\r |
8ff68cd5 KK |
53 | NameSpaceStrLen\r |
54 | );\r | |
55 | }\r | |
56 | }\r | |
ee4dc24f RN |
57 | \r |
58 | /// An ACPI_PARSER array describing the ACPI DBG2 table.\r | |
47d20b54 | 59 | STATIC CONST ACPI_PARSER Dbg2Parser[] = {\r |
ee4dc24f | 60 | PARSE_ACPI_HEADER (&AcpiHdrInfo),\r |
47d20b54 MK |
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 | |
ee4dc24f RN |
65 | };\r |
66 | \r | |
ffb18f77 KK |
67 | /// An ACPI_PARSER array describing the debug device information structure\r |
68 | /// header.\r | |
47d20b54 MK |
69 | STATIC 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 | |
ffb18f77 KK |
72 | };\r |
73 | \r | |
ee4dc24f | 74 | /// An ACPI_PARSER array describing the debug device information.\r |
47d20b54 MK |
75 | STATIC CONST ACPI_PARSER DbgDevInfoParser[] = {\r |
76 | { L"Revision", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },\r | |
77 | { L"Length", 2, 1, L"%d", NULL, NULL, NULL, NULL },\r | |
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 | |
ee4dc24f RN |
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 |
106 | STATIC\r |
107 | VOID\r | |
108 | EFIAPI\r | |
109 | DumpDbgDeviceInfo (\r | |
47d20b54 MK |
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 | |
47d20b54 MK |
134 | (AddrSizeOffset == NULL))\r |
135 | {\r | |
ccb4c38a KK |
136 | IncrementErrorCount ();\r |
137 | Print (\r | |
138 | L"ERROR: Insufficient Debug Device Information Structure length. " \\r | |
47d20b54 | 139 | L"Length = %d.\n",\r |
ccb4c38a KK |
140 | Length\r |
141 | );\r | |
142 | return;\r | |
143 | }\r | |
144 | \r | |
ffb18f77 | 145 | // GAS\r |
47d20b54 | 146 | Index = 0;\r |
ffb18f77 KK |
147 | Offset = *BaseAddrRegOffset;\r |
148 | while ((Index++ < *GasCount) &&\r | |
47d20b54 MK |
149 | (Offset < Length))\r |
150 | {\r | |
ee4dc24f | 151 | PrintFieldName (4, L"BaseAddressRegister");\r |
ffb18f77 KK |
152 | Offset += (UINT16)DumpGasStruct (\r |
153 | Ptr + Offset,\r | |
154 | 4,\r | |
155 | Length - Offset\r | |
156 | );\r | |
157 | }\r | |
158 | \r | |
159 | // Make sure the array of address sizes corresponding to each GAS fit in the\r | |
160 | // Debug Device Information structure\r | |
161 | if ((*AddrSizeOffset + (*GasCount * sizeof (UINT32))) > Length) {\r | |
162 | IncrementErrorCount ();\r | |
163 | Print (\r | |
164 | L"ERROR: Invalid GAS count. GasCount = %d. RemainingBufferLength = %d. " \\r | |
47d20b54 | 165 | L"Parsing of the Debug Device Information structure aborted.\n",\r |
ffb18f77 KK |
166 | *GasCount,\r |
167 | Length - *AddrSizeOffset\r | |
168 | );\r | |
169 | return;\r | |
170 | }\r | |
171 | \r | |
172 | // Address Size\r | |
47d20b54 | 173 | Index = 0;\r |
ffb18f77 KK |
174 | Offset = *AddrSizeOffset;\r |
175 | while ((Index++ < *GasCount) &&\r | |
47d20b54 MK |
176 | (Offset < Length))\r |
177 | {\r | |
ee4dc24f | 178 | PrintFieldName (4, L"Address Size");\r |
47d20b54 | 179 | Print (L"0x%x\n", *((UINT32 *)(Ptr + Offset)));\r |
ffb18f77 | 180 | Offset += sizeof (UINT32);\r |
ee4dc24f RN |
181 | }\r |
182 | \r | |
183 | // NameSpace String\r | |
47d20b54 | 184 | Index = 0;\r |
ffb18f77 | 185 | Offset = *NameSpaceStringOffset;\r |
ee4dc24f | 186 | PrintFieldName (4, L"NameSpace String");\r |
ffb18f77 | 187 | while ((Index++ < *NameSpaceStringLength) &&\r |
47d20b54 MK |
188 | (Offset < Length))\r |
189 | {\r | |
ffb18f77 KK |
190 | Print (L"%c", *(Ptr + Offset));\r |
191 | Offset++;\r | |
ee4dc24f | 192 | }\r |
47d20b54 | 193 | \r |
ee4dc24f RN |
194 | Print (L"\n");\r |
195 | \r | |
196 | // OEM Data\r | |
ffb18f77 | 197 | if (*OEMDataOffset != 0) {\r |
47d20b54 | 198 | Index = 0;\r |
ffb18f77 KK |
199 | Offset = *OEMDataOffset;\r |
200 | PrintFieldName (4, L"OEM Data");\r | |
201 | while ((Index++ < *OEMDataLength) &&\r | |
47d20b54 MK |
202 | (Offset < Length))\r |
203 | {\r | |
ffb18f77 KK |
204 | Print (L"%x ", *(Ptr + Offset));\r |
205 | if ((Index & 7) == 0) {\r | |
206 | Print (L"\n%-*s ", OUTPUT_FIELD_COLUMN_WIDTH, L"");\r | |
207 | }\r | |
47d20b54 | 208 | \r |
ffb18f77 | 209 | Offset++;\r |
ee4dc24f | 210 | }\r |
47d20b54 | 211 | \r |
ffb18f77 | 212 | Print (L"\n");\r |
ee4dc24f | 213 | }\r |
ee4dc24f RN |
214 | }\r |
215 | \r | |
a6eaba4d DB |
216 | /**\r |
217 | This function parses the ACPI DBG2 table.\r | |
ee4dc24f RN |
218 | When trace is enabled this function parses the DBG2 table and\r |
219 | traces the ACPI table fields.\r | |
220 | \r | |
221 | This function also performs validation of the ACPI table fields.\r | |
222 | \r | |
223 | @param [in] Trace If TRUE, trace the ACPI fields.\r | |
224 | @param [in] Ptr Pointer to the start of the buffer.\r | |
225 | @param [in] AcpiTableLength Length of the ACPI table.\r | |
226 | @param [in] AcpiTableRevision Revision of the ACPI table.\r | |
a6eaba4d | 227 | **/\r |
ee4dc24f RN |
228 | VOID\r |
229 | EFIAPI\r | |
230 | ParseAcpiDbg2 (\r | |
47d20b54 MK |
231 | IN BOOLEAN Trace,\r |
232 | IN UINT8 *Ptr,\r | |
233 | IN UINT32 AcpiTableLength,\r | |
234 | IN UINT8 AcpiTableRevision\r | |
ee4dc24f RN |
235 | )\r |
236 | {\r | |
47d20b54 MK |
237 | UINT32 Offset;\r |
238 | UINT32 Index;\r | |
ee4dc24f RN |
239 | \r |
240 | if (!Trace) {\r | |
241 | return;\r | |
242 | }\r | |
243 | \r | |
244 | Offset = ParseAcpi (\r | |
245 | TRUE,\r | |
246 | 0,\r | |
247 | "DBG2",\r | |
248 | Ptr,\r | |
249 | AcpiTableLength,\r | |
250 | PARSER_PARAMS (Dbg2Parser)\r | |
251 | );\r | |
ee4dc24f | 252 | \r |
ccb4c38a KK |
253 | // Check if the values used to control the parsing logic have been\r |
254 | // successfully read.\r | |
255 | if ((OffsetDbgDeviceInfo == NULL) ||\r | |
47d20b54 MK |
256 | (NumberDbgDeviceInfo == NULL))\r |
257 | {\r | |
ccb4c38a KK |
258 | IncrementErrorCount ();\r |
259 | Print (\r | |
260 | L"ERROR: Insufficient table length. AcpiTableLength = %d\n",\r | |
261 | AcpiTableLength\r | |
262 | );\r | |
263 | return;\r | |
264 | }\r | |
265 | \r | |
ffb18f77 | 266 | Offset = *OffsetDbgDeviceInfo;\r |
47d20b54 | 267 | Index = 0;\r |
ffb18f77 KK |
268 | \r |
269 | while (Index++ < *NumberDbgDeviceInfo) {\r | |
ffb18f77 KK |
270 | // Parse the Debug Device Information Structure header to obtain Length\r |
271 | ParseAcpi (\r | |
272 | FALSE,\r | |
273 | 0,\r | |
274 | NULL,\r | |
275 | Ptr + Offset,\r | |
276 | AcpiTableLength - Offset,\r | |
277 | PARSER_PARAMS (DbgDevInfoHeaderParser)\r | |
ee4dc24f | 278 | );\r |
ffb18f77 | 279 | \r |
ccb4c38a KK |
280 | // Check if the values used to control the parsing logic have been\r |
281 | // successfully read.\r | |
282 | if (DbgDevInfoLen == NULL) {\r | |
283 | IncrementErrorCount ();\r | |
284 | Print (\r | |
285 | L"ERROR: Insufficient remaining table buffer length to read the " \\r | |
47d20b54 MK |
286 | L"Debug Device Information structure's 'Length' field. " \\r |
287 | L"RemainingTableBufferLength = %d.\n",\r | |
ccb4c38a KK |
288 | AcpiTableLength - Offset\r |
289 | );\r | |
290 | return;\r | |
291 | }\r | |
292 | \r | |
b8504826 KK |
293 | // Validate Debug Device Information Structure length\r |
294 | if ((*DbgDevInfoLen == 0) ||\r | |
47d20b54 MK |
295 | ((Offset + (*DbgDevInfoLen)) > AcpiTableLength))\r |
296 | {\r | |
ffb18f77 KK |
297 | IncrementErrorCount ();\r |
298 | Print (\r | |
b8504826 | 299 | L"ERROR: Invalid Debug Device Information Structure length. " \\r |
47d20b54 | 300 | L"Length = %d. Offset = %d. AcpiTableLength = %d.\n",\r |
ffb18f77 | 301 | *DbgDevInfoLen,\r |
b8504826 KK |
302 | Offset,\r |
303 | AcpiTableLength\r | |
ffb18f77 KK |
304 | );\r |
305 | return;\r | |
306 | }\r | |
307 | \r | |
308 | DumpDbgDeviceInfo (Ptr + Offset, (*DbgDevInfoLen));\r | |
309 | Offset += (*DbgDevInfoLen);\r | |
ee4dc24f RN |
310 | }\r |
311 | }\r |