mirror of https://github.com/acidanthera/audk.git
547 lines
13 KiB
C
547 lines
13 KiB
C
/** @file
|
|
AML Print Function.
|
|
|
|
Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
|
|
Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
|
|
#include <AmlNodeDefines.h>
|
|
#include <AmlDbgPrint/AmlDbgPrint.h>
|
|
|
|
#include <AmlCoreInterface.h>
|
|
#include <String/AmlString.h>
|
|
#include <Tree/AmlNode.h>
|
|
#include <Tree/AmlTreeTraversal.h>
|
|
|
|
#if !defined (MDEPKG_NDEBUG)
|
|
|
|
/** String table representing AML Data types as defined by EAML_NODE_DATA_TYPE.
|
|
*/
|
|
CONST CHAR8 * NodeDataTypeStrTbl[] = {
|
|
"EAmlNodeDataTypeNone",
|
|
"EAmlNodeDataTypeReserved1",
|
|
"EAmlNodeDataTypeReserved2",
|
|
"EAmlNodeDataTypeReserved3",
|
|
"EAmlNodeDataTypeReserved4",
|
|
"EAmlNodeDataTypeReserved5",
|
|
"EAmlNodeDataTypeNameString",
|
|
"EAmlNodeDataTypeString",
|
|
"EAmlNodeDataTypeUInt",
|
|
"EAmlNodeDataTypeRaw",
|
|
"EAmlNodeDataTypeResourceData",
|
|
"EAmlNodeDataTypeFieldPkgLen",
|
|
"EAmlNodeDataTypeMax"
|
|
};
|
|
|
|
/** String table representing AML Node types as defined by EAML_NODE_TYPE.
|
|
*/
|
|
CONST CHAR8 * NodeTypeStrTbl[] = {
|
|
"EAmlNodeUnknown",
|
|
"EAmlNodeRoot",
|
|
"EAmlNodeObject",
|
|
"EAmlNodeData",
|
|
"EAmlNodeMax"
|
|
};
|
|
|
|
/** Print Size chars at Buffer address.
|
|
|
|
@param [in] ErrorLevel Error level for the DEBUG macro.
|
|
@param [in] Buffer Buffer containing the chars.
|
|
@param [in] Size Number of chars to print.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
AmlDbgPrintChars (
|
|
IN UINT32 ErrorLevel,
|
|
IN CONST CHAR8 * Buffer,
|
|
IN UINT32 Size
|
|
)
|
|
{
|
|
UINT32 i;
|
|
|
|
if (Buffer == NULL) {
|
|
ASSERT (0);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < Size; i++) {
|
|
DEBUG ((ErrorLevel, "%c", Buffer[i]));
|
|
}
|
|
}
|
|
|
|
/** Print an AML NameSeg.
|
|
Don't print trailing underscores ('_').
|
|
|
|
@param [in] Buffer Buffer containing an AML NameSeg.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
AmlDbgPrintNameSeg (
|
|
IN CONST CHAR8 * Buffer
|
|
)
|
|
{
|
|
if (Buffer == NULL) {
|
|
ASSERT (0);
|
|
return;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "%c", Buffer[0]));
|
|
if ((Buffer[1] == AML_NAME_CHAR__) &&
|
|
(Buffer[2] == AML_NAME_CHAR__) &&
|
|
(Buffer[3] == AML_NAME_CHAR__)) {
|
|
return;
|
|
}
|
|
DEBUG ((DEBUG_INFO, "%c", Buffer[1]));
|
|
if ((Buffer[2] == AML_NAME_CHAR__) &&
|
|
(Buffer[3] == AML_NAME_CHAR__)) {
|
|
return;
|
|
}
|
|
DEBUG ((DEBUG_INFO, "%c", Buffer[2]));
|
|
if (Buffer[3] == AML_NAME_CHAR__) {
|
|
return;
|
|
}
|
|
DEBUG ((DEBUG_INFO, "%c", Buffer[3]));
|
|
return;
|
|
}
|
|
|
|
/** Print an AML NameString.
|
|
|
|
@param [in] Buffer Buffer containing an AML NameString.
|
|
@param [in] NewLine Print a newline char at the end of the NameString.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
AmlDbgPrintNameString (
|
|
IN CONST CHAR8 * Buffer,
|
|
IN BOOLEAN NewLine
|
|
)
|
|
{
|
|
UINT8 SegCount;
|
|
UINT8 Index;
|
|
|
|
if (Buffer == NULL) {
|
|
ASSERT (0);
|
|
return;
|
|
}
|
|
|
|
// Handle Root and Parent(s).
|
|
if (*Buffer == AML_ROOT_CHAR) {
|
|
Buffer++;
|
|
DEBUG ((DEBUG_INFO, "\\"));
|
|
} else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
|
|
do {
|
|
Buffer++;
|
|
DEBUG ((DEBUG_INFO, "^"));
|
|
} while (*Buffer == AML_PARENT_PREFIX_CHAR);
|
|
}
|
|
|
|
// Handle SegCount(s).
|
|
if (*Buffer == AML_DUAL_NAME_PREFIX) {
|
|
Buffer++;
|
|
SegCount = 2;
|
|
} else if (*Buffer == AML_MULTI_NAME_PREFIX) {
|
|
Buffer++;
|
|
// For multi name prefix the seg count is in the second byte.
|
|
SegCount = *Buffer;
|
|
Buffer++;
|
|
} else if (AmlIsLeadNameChar (*Buffer)) {
|
|
// Only check the first char first to avoid overflow.
|
|
// Then the whole NameSeg can be checked.
|
|
if (!AmlIsNameSeg (Buffer)) {
|
|
ASSERT (0);
|
|
return;
|
|
}
|
|
SegCount = 1;
|
|
} else if (*Buffer == AML_ZERO_OP) {
|
|
SegCount = 0;
|
|
} else {
|
|
// Should not be possible.
|
|
ASSERT (0);
|
|
return;
|
|
}
|
|
|
|
if (SegCount != 0) {
|
|
AMLDBG_PRINT_NAMESEG (Buffer);
|
|
Buffer += AML_NAME_SEG_SIZE;
|
|
for (Index = 0; Index < SegCount - 1; Index++) {
|
|
DEBUG ((DEBUG_INFO, "."));
|
|
AMLDBG_PRINT_NAMESEG (Buffer);
|
|
Buffer += AML_NAME_SEG_SIZE;
|
|
}
|
|
}
|
|
|
|
if (NewLine) {
|
|
DEBUG ((DEBUG_INFO, "\n"));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/** Print the information contained in the header of the Node.
|
|
|
|
@param [in] Node Pointer to a node.
|
|
@param [in] Level Level of the indentation.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
AmlDbgPrintNodeHeader (
|
|
IN AML_NODE_HEADER * Node,
|
|
IN UINT8 Level
|
|
)
|
|
{
|
|
if (!IS_AML_NODE_VALID (Node)) {
|
|
ASSERT (0);
|
|
return;
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"%3d | %-15s | ",
|
|
Level,
|
|
NodeTypeStrTbl[Node->NodeType]
|
|
));
|
|
}
|
|
|
|
/** Print fields of a data node.
|
|
|
|
@param [in] DataNode Pointer to a data node.
|
|
@param [in] Level Level of the indentation.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
AmlDbgPrintDataNode (
|
|
IN AML_DATA_NODE * DataNode,
|
|
IN UINT8 Level
|
|
)
|
|
{
|
|
UINT32 Idx;
|
|
|
|
if (!IS_AML_DATA_NODE (DataNode)) {
|
|
ASSERT (0);
|
|
return;
|
|
}
|
|
|
|
AmlDbgPrintNodeHeader ((AML_NODE_HEADER*)DataNode, Level);
|
|
|
|
DEBUG ((DEBUG_INFO, "%-36s | ", NodeDataTypeStrTbl[DataNode->DataType]));
|
|
DEBUG ((DEBUG_INFO, "0x%04x | ", DataNode->Size));
|
|
|
|
if ((DataNode->DataType == EAmlNodeDataTypeNameString) ||
|
|
(DataNode->DataType == EAmlNodeDataTypeString)) {
|
|
AMLDBG_PRINT_CHARS (
|
|
DEBUG_INFO,
|
|
(CONST CHAR8*)DataNode->Buffer,
|
|
DataNode->Size
|
|
);
|
|
} else if (DataNode->DataType == EAmlNodeDataTypeUInt) {
|
|
switch (DataNode->Size) {
|
|
case 1:
|
|
{
|
|
DEBUG ((DEBUG_INFO, "0x%0x", *((UINT8*)DataNode->Buffer)));
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
DEBUG ((DEBUG_INFO, "0x%0x", *((UINT16*)DataNode->Buffer)));
|
|
break;
|
|
}
|
|
case 4:
|
|
{
|
|
DEBUG ((DEBUG_INFO, "0x%0lx", *((UINT32*)DataNode->Buffer)));
|
|
break;
|
|
}
|
|
case 8:
|
|
{
|
|
DEBUG ((DEBUG_INFO, "0x%0llx", *((UINT64*)DataNode->Buffer)));
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
ASSERT (0);
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
// No specific format.
|
|
for (Idx = 0; Idx < DataNode->Size; Idx++) {
|
|
DEBUG ((DEBUG_INFO, "%02x ", DataNode->Buffer[Idx]));
|
|
}
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "\n"));
|
|
}
|
|
|
|
/** Print fields of an object node.
|
|
|
|
@param [in] ObjectNode Pointer to an object node.
|
|
@param [in] Level Level of the indentation.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
AmlDbgPrintObjectNode (
|
|
IN AML_OBJECT_NODE * ObjectNode,
|
|
IN UINT8 Level
|
|
)
|
|
{
|
|
if (!IS_AML_OBJECT_NODE (ObjectNode)) {
|
|
ASSERT (0);
|
|
return;
|
|
}
|
|
|
|
AmlDbgPrintNodeHeader ((AML_NODE_HEADER*)ObjectNode, Level);
|
|
|
|
DEBUG ((DEBUG_INFO, "0x%02x | ", ObjectNode->AmlByteEncoding->OpCode));
|
|
DEBUG ((DEBUG_INFO, "0x%02x | ", ObjectNode->AmlByteEncoding->SubOpCode));
|
|
|
|
// Print a string corresponding to the field object OpCode/SubOpCode.
|
|
if (AmlNodeHasAttribute (ObjectNode, AML_IS_FIELD_ELEMENT)) {
|
|
DEBUG ((DEBUG_INFO, "%-15s ", AmlGetFieldOpCodeStr (
|
|
ObjectNode->AmlByteEncoding->OpCode,
|
|
0
|
|
)));
|
|
} else {
|
|
// Print a string corresponding to the object OpCode/SubOpCode.
|
|
DEBUG ((DEBUG_INFO, "%-15s | ", AmlGetOpCodeStr (
|
|
ObjectNode->AmlByteEncoding->OpCode,
|
|
ObjectNode->AmlByteEncoding->SubOpCode)
|
|
));
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "%3d | ", ObjectNode->AmlByteEncoding->MaxIndex));
|
|
DEBUG ((DEBUG_INFO, "0x%08x | ", ObjectNode->AmlByteEncoding->Attribute));
|
|
DEBUG ((DEBUG_INFO, "0x%04x | ", ObjectNode->PkgLen));
|
|
if (AmlNodeHasAttribute (ObjectNode, AML_IN_NAMESPACE)) {
|
|
AMLDBG_PRINT_NAMESTR (
|
|
AmlNodeGetName ((CONST AML_OBJECT_NODE*)ObjectNode),
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "\n"));
|
|
}
|
|
|
|
/** Print fields of a root node.
|
|
|
|
@param [in] RootNode Pointer to a root node.
|
|
@param [in] Level Level of the indentation.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
AmlDbgPrintRootNode (
|
|
IN AML_ROOT_NODE * RootNode,
|
|
IN UINT8 Level
|
|
)
|
|
{
|
|
if (!IS_AML_ROOT_NODE (RootNode)) {
|
|
ASSERT (0);
|
|
return;
|
|
}
|
|
|
|
AmlDbgPrintNodeHeader ((AML_NODE_HEADER*)RootNode, Level);
|
|
|
|
DEBUG ((DEBUG_INFO, "%8x | ", RootNode->SdtHeader->Signature));
|
|
DEBUG ((DEBUG_INFO, "0x%08x | ", RootNode->SdtHeader->Length));
|
|
DEBUG ((DEBUG_INFO, "%3d | ", RootNode->SdtHeader->Revision));
|
|
DEBUG ((DEBUG_INFO, "0x%02x | ", RootNode->SdtHeader->Checksum));
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"%c%c%c%c%c%c | ",
|
|
RootNode->SdtHeader->OemId[0],
|
|
RootNode->SdtHeader->OemId[1],
|
|
RootNode->SdtHeader->OemId[2],
|
|
RootNode->SdtHeader->OemId[3],
|
|
RootNode->SdtHeader->OemId[4],
|
|
RootNode->SdtHeader->OemId[5]
|
|
));
|
|
DEBUG ((DEBUG_INFO, "%-16llx | ", RootNode->SdtHeader->OemTableId));
|
|
DEBUG ((DEBUG_INFO, "%8x | ", RootNode->SdtHeader->OemRevision));
|
|
DEBUG ((DEBUG_INFO, "%8x | ", RootNode->SdtHeader->CreatorId));
|
|
DEBUG ((DEBUG_INFO, "%8x", RootNode->SdtHeader->CreatorRevision));
|
|
DEBUG ((DEBUG_INFO, "\n"));
|
|
}
|
|
|
|
/** Print a header to help interpreting node information.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
AmlDbgPrintTableHeader (
|
|
VOID
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "Lvl | Node Type |\n"));
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
" | %-15s | Signature| Length | Rev | CSum | OemId | "
|
|
"OemTableId | OemRev | CreatorId| CreatorRev\n",
|
|
NodeTypeStrTbl[EAmlNodeRoot]
|
|
));
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
" | %-15s | Op | SubOp| OpName | MaxI| Attribute | "
|
|
"PkgLen | NodeName (opt)\n",
|
|
NodeTypeStrTbl[EAmlNodeObject]
|
|
));
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
" | %-15s | Data Type | Size | "
|
|
"Buffer\n",
|
|
NodeTypeStrTbl[EAmlNodeData]
|
|
));
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"---------------------------------------"
|
|
"---------------------------------------\n"
|
|
));
|
|
}
|
|
|
|
/** Recursively print the subtree under the Node.
|
|
This is an internal function.
|
|
|
|
@param [in] Node Pointer to the root of the subtree to print.
|
|
Can be a root/object/data node.
|
|
@param [in] Recurse If TRUE, recurse.
|
|
@param [in] Level Level in the tree.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
AmlDbgPrintTreeInternal (
|
|
IN AML_NODE_HEADER * Node,
|
|
IN BOOLEAN Recurse,
|
|
IN UINT8 Level
|
|
)
|
|
{
|
|
AML_NODE_HEADER * ChildNode;
|
|
|
|
if (!IS_AML_NODE_VALID (Node)) {
|
|
ASSERT (0);
|
|
return;
|
|
}
|
|
|
|
if (IS_AML_DATA_NODE (Node)) {
|
|
AmlDbgPrintDataNode ((AML_DATA_NODE*)Node, Level);
|
|
return;
|
|
} else if (IS_AML_OBJECT_NODE (Node)) {
|
|
AmlDbgPrintObjectNode ((AML_OBJECT_NODE*)Node, Level);
|
|
} else if (IS_AML_ROOT_NODE (Node)) {
|
|
AmlDbgPrintRootNode ((AML_ROOT_NODE*)Node, Level);
|
|
} else {
|
|
// Should not be possible.
|
|
ASSERT (0);
|
|
return;
|
|
}
|
|
|
|
if (!Recurse) {
|
|
return;
|
|
}
|
|
|
|
// Get the first child node.
|
|
ChildNode = AmlGetNextSibling (Node, NULL);
|
|
while (ChildNode != NULL) {
|
|
ASSERT (Level < MAX_UINT8);
|
|
AmlDbgPrintTreeInternal (ChildNode, Recurse, (UINT8)(Level + 1));
|
|
ChildNode = AmlGetNextSibling (Node, ChildNode);
|
|
}
|
|
}
|
|
|
|
/** Print Node information.
|
|
|
|
@param [in] Node Pointer to the Node to print.
|
|
Can be a root/object/data node.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
AmlDbgPrintNode (
|
|
IN AML_NODE_HEADER * Node
|
|
)
|
|
{
|
|
AmlDbgPrintTableHeader ();
|
|
AmlDbgPrintTreeInternal (Node, FALSE, 0);
|
|
}
|
|
|
|
/** Recursively print the subtree under the Node.
|
|
|
|
@param [in] Node Pointer to the root of the subtree to print.
|
|
Can be a root/object/data node.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
AmlDbgPrintTree (
|
|
IN AML_NODE_HEADER * Node
|
|
)
|
|
{
|
|
AmlDbgPrintTableHeader ();
|
|
AmlDbgPrintTreeInternal (Node, TRUE, 0);
|
|
}
|
|
|
|
/** This function performs a raw data dump of the ACPI table.
|
|
|
|
@param [in] Ptr Pointer to the start of the table buffer.
|
|
@param [in] Length The length of the buffer.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
AmlDbgDumpRaw (
|
|
IN CONST UINT8 * Ptr,
|
|
IN UINT32 Length
|
|
)
|
|
{
|
|
UINT32 ByteCount;
|
|
UINT32 PartLineChars;
|
|
UINT32 AsciiBufferIndex;
|
|
CHAR8 AsciiBuffer[17];
|
|
|
|
ByteCount = 0;
|
|
AsciiBufferIndex = 0;
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "Address : 0x%p\n", Ptr));
|
|
DEBUG ((DEBUG_VERBOSE, "Length : %lld", Length));
|
|
|
|
while (ByteCount < Length) {
|
|
if ((ByteCount & 0x0F) == 0) {
|
|
AsciiBuffer[AsciiBufferIndex] = '\0';
|
|
DEBUG ((DEBUG_VERBOSE, " %a\n%08X : ", AsciiBuffer, ByteCount));
|
|
AsciiBufferIndex = 0;
|
|
} else if ((ByteCount & 0x07) == 0) {
|
|
DEBUG ((DEBUG_VERBOSE, "- "));
|
|
}
|
|
|
|
if ((*Ptr >= ' ') && (*Ptr < 0x7F)) {
|
|
AsciiBuffer[AsciiBufferIndex++] = *Ptr;
|
|
} else {
|
|
AsciiBuffer[AsciiBufferIndex++] = '.';
|
|
}
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "%02X ", *Ptr++));
|
|
|
|
ByteCount++;
|
|
}
|
|
|
|
// Justify the final line using spaces before printing
|
|
// the ASCII data.
|
|
PartLineChars = (Length & 0x0F);
|
|
if (PartLineChars != 0) {
|
|
PartLineChars = 48 - (PartLineChars * 3);
|
|
if ((Length & 0x0F) <= 8) {
|
|
PartLineChars += 2;
|
|
}
|
|
while (PartLineChars > 0) {
|
|
DEBUG ((DEBUG_VERBOSE, " "));
|
|
PartLineChars--;
|
|
}
|
|
}
|
|
|
|
// Print ASCII data for the final line.
|
|
AsciiBuffer[AsciiBufferIndex] = '\0';
|
|
DEBUG ((DEBUG_VERBOSE, " %a\n\n", AsciiBuffer));
|
|
}
|
|
|
|
#endif // MDEPKG_NDEBUG
|