1 /** @file
2 AML Print Function.
3
4 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
5 Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8 **/
9
10 #include <AmlNodeDefines.h>
11 #include <AmlDbgPrint/AmlDbgPrint.h>
12
13 #include <AmlCoreInterface.h>
14 #include <String/AmlString.h>
15 #include <Tree/AmlNode.h>
16 #include <Tree/AmlTreeTraversal.h>
17
18 #if !defined (MDEPKG_NDEBUG)
19
20 /** String table representing AML Data types as defined by EAML_NODE_DATA_TYPE.
21 */
22 CONST CHAR8 * NodeDataTypeStrTbl[] = {
23 "EAmlNodeDataTypeNone",
24 "EAmlNodeDataTypeReserved1",
25 "EAmlNodeDataTypeReserved2",
26 "EAmlNodeDataTypeReserved3",
27 "EAmlNodeDataTypeReserved4",
28 "EAmlNodeDataTypeReserved5",
29 "EAmlNodeDataTypeNameString",
30 "EAmlNodeDataTypeString",
31 "EAmlNodeDataTypeUInt",
32 "EAmlNodeDataTypeRaw",
33 "EAmlNodeDataTypeResourceData",
34 "EAmlNodeDataTypeFieldPkgLen",
35 "EAmlNodeDataTypeMax"
36 };
37
38 /** String table representing AML Node types as defined by EAML_NODE_TYPE.
39 */
40 CONST CHAR8 * NodeTypeStrTbl[] = {
41 "EAmlNodeUnknown",
42 "EAmlNodeRoot",
43 "EAmlNodeObject",
44 "EAmlNodeData",
45 "EAmlNodeMax"
46 };
47
48 /** Print Size chars at Buffer address.
49
50 @param [in] ErrorLevel Error level for the DEBUG macro.
51 @param [in] Buffer Buffer containing the chars.
52 @param [in] Size Number of chars to print.
53 **/
54 VOID
55 EFIAPI
AmlDbgPrintChars(IN UINT32 ErrorLevel,IN CONST CHAR8 * Buffer,IN UINT32 Size)56 AmlDbgPrintChars (
57 IN UINT32 ErrorLevel,
58 IN CONST CHAR8 * Buffer,
59 IN UINT32 Size
60 )
61 {
62 UINT32 i;
63
64 if (Buffer == NULL) {
65 ASSERT (0);
66 return;
67 }
68
69 for (i = 0; i < Size; i++) {
70 DEBUG ((ErrorLevel, "%c", Buffer[i]));
71 }
72 }
73
74 /** Print an AML NameSeg.
75 Don't print trailing underscores ('_').
76
77 @param [in] Buffer Buffer containing an AML NameSeg.
78 **/
79 VOID
80 EFIAPI
AmlDbgPrintNameSeg(IN CONST CHAR8 * Buffer)81 AmlDbgPrintNameSeg (
82 IN CONST CHAR8 * Buffer
83 )
84 {
85 if (Buffer == NULL) {
86 ASSERT (0);
87 return;
88 }
89
90 DEBUG ((DEBUG_INFO, "%c", Buffer[0]));
91 if ((Buffer[1] == AML_NAME_CHAR__) &&
92 (Buffer[2] == AML_NAME_CHAR__) &&
93 (Buffer[3] == AML_NAME_CHAR__)) {
94 return;
95 }
96 DEBUG ((DEBUG_INFO, "%c", Buffer[1]));
97 if ((Buffer[2] == AML_NAME_CHAR__) &&
98 (Buffer[3] == AML_NAME_CHAR__)) {
99 return;
100 }
101 DEBUG ((DEBUG_INFO, "%c", Buffer[2]));
102 if (Buffer[3] == AML_NAME_CHAR__) {
103 return;
104 }
105 DEBUG ((DEBUG_INFO, "%c", Buffer[3]));
106 return;
107 }
108
109 /** Print an AML NameString.
110
111 @param [in] Buffer Buffer containing an AML NameString.
112 @param [in] NewLine Print a newline char at the end of the NameString.
113 **/
114 VOID
115 EFIAPI
AmlDbgPrintNameString(IN CONST CHAR8 * Buffer,IN BOOLEAN NewLine)116 AmlDbgPrintNameString (
117 IN CONST CHAR8 * Buffer,
118 IN BOOLEAN NewLine
119 )
120 {
121 UINT8 SegCount;
122 UINT8 Index;
123
124 if (Buffer == NULL) {
125 ASSERT (0);
126 return;
127 }
128
129 // Handle Root and Parent(s).
130 if (*Buffer == AML_ROOT_CHAR) {
131 Buffer++;
132 DEBUG ((DEBUG_INFO, "\\"));
133 } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
134 do {
135 Buffer++;
136 DEBUG ((DEBUG_INFO, "^"));
137 } while (*Buffer == AML_PARENT_PREFIX_CHAR);
138 }
139
140 // Handle SegCount(s).
141 if (*Buffer == AML_DUAL_NAME_PREFIX) {
142 Buffer++;
143 SegCount = 2;
144 } else if (*Buffer == AML_MULTI_NAME_PREFIX) {
145 Buffer++;
146 // For multi name prefix the seg count is in the second byte.
147 SegCount = *Buffer;
148 Buffer++;
149 } else if (AmlIsLeadNameChar (*Buffer)) {
150 // Only check the first char first to avoid overflow.
151 // Then the whole NameSeg can be checked.
152 if (!AmlIsNameSeg (Buffer)) {
153 ASSERT (0);
154 return;
155 }
156 SegCount = 1;
157 } else if (*Buffer == AML_ZERO_OP) {
158 SegCount = 0;
159 } else {
160 // Should not be possible.
161 ASSERT (0);
162 return;
163 }
164
165 if (SegCount != 0) {
166 AmlDbgPrintNameSeg (Buffer);
167 Buffer += AML_NAME_SEG_SIZE;
168 for (Index = 0; Index < SegCount - 1; Index++) {
169 DEBUG ((DEBUG_INFO, "."));
170 AmlDbgPrintNameSeg (Buffer);
171 Buffer += AML_NAME_SEG_SIZE;
172 }
173 }
174
175 if (NewLine) {
176 DEBUG ((DEBUG_INFO, "\n"));
177 }
178
179 return;
180 }
181
182 /** Print the information contained in the header of the Node.
183
184 @param [in] Node Pointer to a node.
185 @param [in] Level Level of the indentation.
186 **/
187 STATIC
188 VOID
189 EFIAPI
AmlDbgPrintNodeHeader(IN AML_NODE_HEADER * Node,IN UINT8 Level)190 AmlDbgPrintNodeHeader (
191 IN AML_NODE_HEADER * Node,
192 IN UINT8 Level
193 )
194 {
195 if (!IS_AML_NODE_VALID (Node)) {
196 ASSERT (0);
197 return;
198 }
199
200 DEBUG ((
201 DEBUG_INFO,
202 "%3d | %-15s | ",
203 Level,
204 NodeTypeStrTbl[Node->NodeType]
205 ));
206 }
207
208 /** Print fields of a data node.
209
210 @param [in] DataNode Pointer to a data node.
211 @param [in] Level Level of the indentation.
212 **/
213 STATIC
214 VOID
215 EFIAPI
AmlDbgPrintDataNode(IN AML_DATA_NODE * DataNode,IN UINT8 Level)216 AmlDbgPrintDataNode (
217 IN AML_DATA_NODE * DataNode,
218 IN UINT8 Level
219 )
220 {
221 UINT32 Idx;
222
223 if (!IS_AML_DATA_NODE (DataNode)) {
224 ASSERT (0);
225 return;
226 }
227
228 AmlDbgPrintNodeHeader ((AML_NODE_HEADER*)DataNode, Level);
229
230 DEBUG ((DEBUG_INFO, "%-36s | ", NodeDataTypeStrTbl[DataNode->DataType]));
231 DEBUG ((DEBUG_INFO, "0x%04x | ", DataNode->Size));
232
233 if ((DataNode->DataType == EAmlNodeDataTypeNameString) ||
234 (DataNode->DataType == EAmlNodeDataTypeString)) {
235 AmlDbgPrintChars (
236 DEBUG_INFO,
237 (CONST CHAR8*)DataNode->Buffer,
238 DataNode->Size
239 );
240 } else if (DataNode->DataType == EAmlNodeDataTypeUInt) {
241 switch (DataNode->Size) {
242 case 1:
243 {
244 DEBUG ((DEBUG_INFO, "0x%0x", *((UINT8*)DataNode->Buffer)));
245 break;
246 }
247 case 2:
248 {
249 DEBUG ((DEBUG_INFO, "0x%0x", *((UINT16*)DataNode->Buffer)));
250 break;
251 }
252 case 4:
253 {
254 DEBUG ((DEBUG_INFO, "0x%0lx", *((UINT32*)DataNode->Buffer)));
255 break;
256 }
257 case 8:
258 {
259 DEBUG ((DEBUG_INFO, "0x%0llx", *((UINT64*)DataNode->Buffer)));
260 break;
261 }
262 default:
263 {
264 ASSERT (0);
265 return;
266 }
267 }
268 } else {
269 // No specific format.
270 for (Idx = 0; Idx < DataNode->Size; Idx++) {
271 DEBUG ((DEBUG_INFO, "%02x ", DataNode->Buffer[Idx]));
272 }
273 }
274
275 DEBUG ((DEBUG_INFO, "\n"));
276 }
277
278 /** Print fields of an object node.
279
280 @param [in] ObjectNode Pointer to an object node.
281 @param [in] Level Level of the indentation.
282 **/
283 STATIC
284 VOID
285 EFIAPI
AmlDbgPrintObjectNode(IN AML_OBJECT_NODE * ObjectNode,IN UINT8 Level)286 AmlDbgPrintObjectNode (
287 IN AML_OBJECT_NODE * ObjectNode,
288 IN UINT8 Level
289 )
290 {
291 if (!IS_AML_OBJECT_NODE (ObjectNode)) {
292 ASSERT (0);
293 return;
294 }
295
296 AmlDbgPrintNodeHeader ((AML_NODE_HEADER*)ObjectNode, Level);
297
298 DEBUG ((DEBUG_INFO, "0x%02x | ", ObjectNode->AmlByteEncoding->OpCode));
299 DEBUG ((DEBUG_INFO, "0x%02x | ", ObjectNode->AmlByteEncoding->SubOpCode));
300
301 // Print a string corresponding to the field object OpCode/SubOpCode.
302 if (AmlNodeHasAttribute (ObjectNode, AML_IS_FIELD_ELEMENT)) {
303 DEBUG ((DEBUG_INFO, "%-15s ", AmlGetFieldOpCodeStr (
304 ObjectNode->AmlByteEncoding->OpCode,
305 0
306 )));
307 } else {
308 // Print a string corresponding to the object OpCode/SubOpCode.
309 DEBUG ((DEBUG_INFO, "%-15s | ", AmlGetOpCodeStr (
310 ObjectNode->AmlByteEncoding->OpCode,
311 ObjectNode->AmlByteEncoding->SubOpCode)
312 ));
313 }
314
315 DEBUG ((DEBUG_INFO, "%3d | ", ObjectNode->AmlByteEncoding->MaxIndex));
316 DEBUG ((DEBUG_INFO, "0x%08x | ", ObjectNode->AmlByteEncoding->Attribute));
317 DEBUG ((DEBUG_INFO, "0x%04x | ", ObjectNode->PkgLen));
318 if (AmlNodeHasAttribute (ObjectNode, AML_IN_NAMESPACE)) {
319 AmlDbgPrintNameString (
320 AmlNodeGetName ((CONST AML_OBJECT_NODE*)ObjectNode),
321 FALSE
322 );
323 }
324
325 DEBUG ((DEBUG_INFO, "\n"));
326 }
327
328 /** Print fields of a root node.
329
330 @param [in] RootNode Pointer to a root node.
331 @param [in] Level Level of the indentation.
332 **/
333 STATIC
334 VOID
335 EFIAPI
AmlDbgPrintRootNode(IN AML_ROOT_NODE * RootNode,IN UINT8 Level)336 AmlDbgPrintRootNode (
337 IN AML_ROOT_NODE * RootNode,
338 IN UINT8 Level
339 )
340 {
341 if (!IS_AML_ROOT_NODE (RootNode)) {
342 ASSERT (0);
343 return;
344 }
345
346 AmlDbgPrintNodeHeader ((AML_NODE_HEADER*)RootNode, Level);
347
348 DEBUG ((DEBUG_INFO, "%8x | ", RootNode->SdtHeader->Signature));
349 DEBUG ((DEBUG_INFO, "0x%08x | ", RootNode->SdtHeader->Length));
350 DEBUG ((DEBUG_INFO, "%3d | ", RootNode->SdtHeader->Revision));
351 DEBUG ((DEBUG_INFO, "0x%02x | ", RootNode->SdtHeader->Checksum));
352 DEBUG ((
353 DEBUG_INFO,
354 "%c%c%c%c%c%c | ",
355 RootNode->SdtHeader->OemId[0],
356 RootNode->SdtHeader->OemId[1],
357 RootNode->SdtHeader->OemId[2],
358 RootNode->SdtHeader->OemId[3],
359 RootNode->SdtHeader->OemId[4],
360 RootNode->SdtHeader->OemId[5]
361 ));
362 DEBUG ((DEBUG_INFO, "%-16llx | ", RootNode->SdtHeader->OemTableId));
363 DEBUG ((DEBUG_INFO, "%8x | ", RootNode->SdtHeader->OemRevision));
364 DEBUG ((DEBUG_INFO, "%8x | ", RootNode->SdtHeader->CreatorId));
365 DEBUG ((DEBUG_INFO, "%8x", RootNode->SdtHeader->CreatorRevision));
366 DEBUG ((DEBUG_INFO, "\n"));
367 }
368
369 /** Print a header to help interpreting node information.
370 **/
371 STATIC
372 VOID
373 EFIAPI
AmlDbgPrintTableHeader(VOID)374 AmlDbgPrintTableHeader (
375 VOID
376 )
377 {
378 DEBUG ((DEBUG_INFO, "Lvl | Node Type |\n"));
379 DEBUG ((
380 DEBUG_INFO,
381 " | %-15s | Signature| Length | Rev | CSum | OemId | "
382 "OemTableId | OemRev | CreatorId| CreatorRev\n",
383 NodeTypeStrTbl[EAmlNodeRoot]
384 ));
385 DEBUG ((
386 DEBUG_INFO,
387 " | %-15s | Op | SubOp| OpName | MaxI| Attribute | "
388 "PkgLen | NodeName (opt)\n",
389 NodeTypeStrTbl[EAmlNodeObject]
390 ));
391 DEBUG ((
392 DEBUG_INFO,
393 " | %-15s | Data Type | Size | "
394 "Buffer\n",
395 NodeTypeStrTbl[EAmlNodeData]
396 ));
397 DEBUG ((
398 DEBUG_INFO,
399 "---------------------------------------"
400 "---------------------------------------\n"
401 ));
402 }
403
404 /** Recursively print the subtree under the Node.
405 This is an internal function.
406
407 @param [in] Node Pointer to the root of the subtree to print.
408 Can be a root/object/data node.
409 @param [in] Recurse If TRUE, recurse.
410 @param [in] Level Level in the tree.
411 **/
412 STATIC
413 VOID
414 EFIAPI
AmlDbgPrintTreeInternal(IN AML_NODE_HEADER * Node,IN BOOLEAN Recurse,IN UINT8 Level)415 AmlDbgPrintTreeInternal (
416 IN AML_NODE_HEADER * Node,
417 IN BOOLEAN Recurse,
418 IN UINT8 Level
419 )
420 {
421 AML_NODE_HEADER * ChildNode;
422
423 if (!IS_AML_NODE_VALID (Node)) {
424 ASSERT (0);
425 return;
426 }
427
428 if (IS_AML_DATA_NODE (Node)) {
429 AmlDbgPrintDataNode ((AML_DATA_NODE*)Node, Level);
430 return;
431 } else if (IS_AML_OBJECT_NODE (Node)) {
432 AmlDbgPrintObjectNode ((AML_OBJECT_NODE*)Node, Level);
433 } else if (IS_AML_ROOT_NODE (Node)) {
434 AmlDbgPrintRootNode ((AML_ROOT_NODE*)Node, Level);
435 } else {
436 // Should not be possible.
437 ASSERT (0);
438 return;
439 }
440
441 if (!Recurse) {
442 return;
443 }
444
445 // Get the first child node.
446 ChildNode = AmlGetNextSibling (Node, NULL);
447 while (ChildNode != NULL) {
448 ASSERT (Level < MAX_UINT8);
449 AmlDbgPrintTreeInternal (ChildNode, Recurse, (UINT8)(Level + 1));
450 ChildNode = AmlGetNextSibling (Node, ChildNode);
451 }
452 }
453
454 /** Print Node information.
455
456 @param [in] Node Pointer to the Node to print.
457 Can be a root/object/data node.
458 **/
459 VOID
460 EFIAPI
AmlDbgPrintNode(IN AML_NODE_HEADER * Node)461 AmlDbgPrintNode (
462 IN AML_NODE_HEADER * Node
463 )
464 {
465 AmlDbgPrintTableHeader ();
466 AmlDbgPrintTreeInternal (Node, FALSE, 0);
467 }
468
469 /** Recursively print the subtree under the Node.
470
471 @param [in] Node Pointer to the root of the subtree to print.
472 Can be a root/object/data node.
473 **/
474 VOID
475 EFIAPI
AmlDbgPrintTree(IN AML_NODE_HEADER * Node)476 AmlDbgPrintTree (
477 IN AML_NODE_HEADER * Node
478 )
479 {
480 AmlDbgPrintTableHeader ();
481 AmlDbgPrintTreeInternal (Node, TRUE, 0);
482 }
483
484 /** This function performs a raw data dump of the ACPI table.
485
486 @param [in] Ptr Pointer to the start of the table buffer.
487 @param [in] Length The length of the buffer.
488 **/
489 VOID
490 EFIAPI
DumpRaw(IN CONST UINT8 * Ptr,IN UINT32 Length)491 DumpRaw (
492 IN CONST UINT8 * Ptr,
493 IN UINT32 Length
494 )
495 {
496 UINT32 ByteCount;
497 UINT32 PartLineChars;
498 UINT32 AsciiBufferIndex;
499 CHAR8 AsciiBuffer[17];
500
501 ByteCount = 0;
502 AsciiBufferIndex = 0;
503
504 DEBUG ((DEBUG_VERBOSE, "Address : 0x%p\n", Ptr));
505 DEBUG ((DEBUG_VERBOSE, "Length : %lld", Length));
506
507 while (ByteCount < Length) {
508 if ((ByteCount & 0x0F) == 0) {
509 AsciiBuffer[AsciiBufferIndex] = '\0';
510 DEBUG ((DEBUG_VERBOSE, " %a\n%08X : ", AsciiBuffer, ByteCount));
511 AsciiBufferIndex = 0;
512 } else if ((ByteCount & 0x07) == 0) {
513 DEBUG ((DEBUG_VERBOSE, "- "));
514 }
515
516 if ((*Ptr >= ' ') && (*Ptr < 0x7F)) {
517 AsciiBuffer[AsciiBufferIndex++] = *Ptr;
518 } else {
519 AsciiBuffer[AsciiBufferIndex++] = '.';
520 }
521
522 DEBUG ((DEBUG_VERBOSE, "%02X ", *Ptr++));
523
524 ByteCount++;
525 }
526
527 // Justify the final line using spaces before printing
528 // the ASCII data.
529 PartLineChars = (Length & 0x0F);
530 if (PartLineChars != 0) {
531 PartLineChars = 48 - (PartLineChars * 3);
532 if ((Length & 0x0F) <= 8) {
533 PartLineChars += 2;
534 }
535 while (PartLineChars > 0) {
536 DEBUG ((DEBUG_VERBOSE, " "));
537 PartLineChars--;
538 }
539 }
540
541 // Print ASCII data for the final line.
542 AsciiBuffer[AsciiBufferIndex] = '\0';
543 DEBUG ((DEBUG_VERBOSE, " %a\n\n", AsciiBuffer));
544 }
545
546 #endif // MDEPKG_NDEBUG
547