/** @file | |
DBG2 table parser | |
Copyright (c) 2016 - 2020, ARM Limited. All rights reserved. | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
@par Reference(s): | |
- Microsoft Debug Port Table 2 (DBG2) Specification - December 10, 2015. | |
**/ | |
#include <IndustryStandard/DebugPort2Table.h> | |
#include <Library/UefiLib.h> | |
#include "AcpiParser.h" | |
#include "AcpiTableParser.h" | |
// Local variables pointing to the table fields | |
STATIC CONST UINT32 *OffsetDbgDeviceInfo; | |
STATIC CONST UINT32 *NumberDbgDeviceInfo; | |
STATIC CONST UINT16 *DbgDevInfoLen; | |
STATIC CONST UINT8 *GasCount; | |
STATIC CONST UINT16 *NameSpaceStringLength; | |
STATIC CONST UINT16 *NameSpaceStringOffset; | |
STATIC CONST UINT16 *OEMDataLength; | |
STATIC CONST UINT16 *OEMDataOffset; | |
STATIC CONST UINT16 *BaseAddrRegOffset; | |
STATIC CONST UINT16 *AddrSizeOffset; | |
STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; | |
/** | |
This function validates the NameSpace string length. | |
@param [in] Ptr Pointer to the start of the buffer. | |
@param [in] Context Pointer to context specific information e.g. this | |
could be a pointer to the ACPI table header. | |
**/ | |
STATIC | |
VOID | |
EFIAPI | |
ValidateNameSpaceStrLen ( | |
IN UINT8 *Ptr, | |
IN VOID *Context | |
) | |
{ | |
UINT16 NameSpaceStrLen; | |
NameSpaceStrLen = *(UINT16 *)Ptr; | |
if (NameSpaceStrLen < 2) { | |
IncrementErrorCount (); | |
Print ( | |
L"\nERROR: NamespaceString Length = %d. If no Namespace device exists, " \ | |
L"NamespaceString[] must contain a period '.'", | |
NameSpaceStrLen | |
); | |
} | |
} | |
/// An ACPI_PARSER array describing the ACPI DBG2 table. | |
STATIC CONST ACPI_PARSER Dbg2Parser[] = { | |
PARSE_ACPI_HEADER (&AcpiHdrInfo), | |
{ L"OffsetDbgDeviceInfo", 4, 36, L"0x%x", NULL, | |
(VOID **)&OffsetDbgDeviceInfo, NULL, NULL }, | |
{ L"NumberDbgDeviceInfo", 4, 40, L"%d", NULL, | |
(VOID **)&NumberDbgDeviceInfo, NULL, NULL } | |
}; | |
/// An ACPI_PARSER array describing the debug device information structure | |
/// header. | |
STATIC CONST ACPI_PARSER DbgDevInfoHeaderParser[] = { | |
{ L"Revision", 1, 0, L"0x%x", NULL, NULL, NULL, NULL }, | |
{ L"Length", 2, 1, L"%d", NULL, (VOID **)&DbgDevInfoLen, NULL, NULL } | |
}; | |
/// An ACPI_PARSER array describing the debug device information. | |
STATIC CONST ACPI_PARSER DbgDevInfoParser[] = { | |
{ L"Revision", 1, 0, L"0x%x", NULL, NULL, NULL, NULL }, | |
{ L"Length", 2, 1, L"%d", NULL, NULL, NULL, NULL }, | |
{ L"Generic Address Registers Count", 1, 3, L"0x%x", NULL, | |
(VOID **)&GasCount, NULL, NULL }, | |
{ L"NameSpace String Length", 2, 4, L"%d", NULL, | |
(VOID **)&NameSpaceStringLength, ValidateNameSpaceStrLen, NULL }, | |
{ L"NameSpace String Offset", 2, 6, L"0x%x", NULL, | |
(VOID **)&NameSpaceStringOffset, NULL, NULL }, | |
{ L"OEM Data Length", 2, 8, L"%d", NULL, (VOID **)&OEMDataLength, | |
NULL, NULL }, | |
{ L"OEM Data Offset", 2, 10, L"0x%x", NULL, (VOID **)&OEMDataOffset, | |
NULL, NULL }, | |
{ L"Port Type", 2, 12, L"0x%x", NULL, NULL, NULL, NULL }, | |
{ L"Port SubType", 2, 14, L"0x%x", NULL, NULL, NULL, NULL }, | |
{ L"Reserved", 2, 16, L"%x", NULL, NULL, NULL, NULL }, | |
{ L"Base Address Register Offset", 2, 18, L"0x%x", NULL, | |
(VOID **)&BaseAddrRegOffset, NULL, NULL }, | |
{ L"Address Size Offset", 2, 20, L"0x%x", NULL, | |
(VOID **)&AddrSizeOffset, NULL, NULL } | |
}; | |
/** | |
This function parses the debug device information structure. | |
@param [in] Ptr Pointer to the start of the buffer. | |
@param [in] Length Length of the debug device information structure. | |
**/ | |
STATIC | |
VOID | |
EFIAPI | |
DumpDbgDeviceInfo ( | |
IN UINT8 *Ptr, | |
IN UINT16 Length | |
) | |
{ | |
UINT16 Index; | |
UINT16 Offset; | |
ParseAcpi ( | |
TRUE, | |
2, | |
"Debug Device Info", | |
Ptr, | |
Length, | |
PARSER_PARAMS (DbgDevInfoParser) | |
); | |
// Check if the values used to control the parsing logic have been | |
// successfully read. | |
if ((GasCount == NULL) || | |
(NameSpaceStringLength == NULL) || | |
(NameSpaceStringOffset == NULL) || | |
(OEMDataLength == NULL) || | |
(OEMDataOffset == NULL) || | |
(BaseAddrRegOffset == NULL) || | |
(AddrSizeOffset == NULL)) | |
{ | |
IncrementErrorCount (); | |
Print ( | |
L"ERROR: Insufficient Debug Device Information Structure length. " \ | |
L"Length = %d.\n", | |
Length | |
); | |
return; | |
} | |
// GAS | |
Index = 0; | |
Offset = *BaseAddrRegOffset; | |
while ((Index++ < *GasCount) && | |
(Offset < Length)) | |
{ | |
PrintFieldName (4, L"BaseAddressRegister"); | |
Offset += (UINT16)DumpGasStruct ( | |
Ptr + Offset, | |
4, | |
Length - Offset | |
); | |
} | |
// Make sure the array of address sizes corresponding to each GAS fit in the | |
// Debug Device Information structure | |
if ((*AddrSizeOffset + (*GasCount * sizeof (UINT32))) > Length) { | |
IncrementErrorCount (); | |
Print ( | |
L"ERROR: Invalid GAS count. GasCount = %d. RemainingBufferLength = %d. " \ | |
L"Parsing of the Debug Device Information structure aborted.\n", | |
*GasCount, | |
Length - *AddrSizeOffset | |
); | |
return; | |
} | |
// Address Size | |
Index = 0; | |
Offset = *AddrSizeOffset; | |
while ((Index++ < *GasCount) && | |
(Offset < Length)) | |
{ | |
PrintFieldName (4, L"Address Size"); | |
Print (L"0x%x\n", *((UINT32 *)(Ptr + Offset))); | |
Offset += sizeof (UINT32); | |
} | |
// NameSpace String | |
Index = 0; | |
Offset = *NameSpaceStringOffset; | |
PrintFieldName (4, L"NameSpace String"); | |
while ((Index++ < *NameSpaceStringLength) && | |
(Offset < Length)) | |
{ | |
Print (L"%c", *(Ptr + Offset)); | |
Offset++; | |
} | |
Print (L"\n"); | |
// OEM Data | |
if (*OEMDataOffset != 0) { | |
Index = 0; | |
Offset = *OEMDataOffset; | |
PrintFieldName (4, L"OEM Data"); | |
while ((Index++ < *OEMDataLength) && | |
(Offset < Length)) | |
{ | |
Print (L"%x ", *(Ptr + Offset)); | |
if ((Index & 7) == 0) { | |
Print (L"\n%-*s ", OUTPUT_FIELD_COLUMN_WIDTH, L""); | |
} | |
Offset++; | |
} | |
Print (L"\n"); | |
} | |
} | |
/** | |
This function parses the ACPI DBG2 table. | |
When trace is enabled this function parses the DBG2 table and | |
traces the ACPI table fields. | |
This function also performs validation of the ACPI table fields. | |
@param [in] Trace If TRUE, trace the ACPI fields. | |
@param [in] Ptr Pointer to the start of the buffer. | |
@param [in] AcpiTableLength Length of the ACPI table. | |
@param [in] AcpiTableRevision Revision of the ACPI table. | |
**/ | |
VOID | |
EFIAPI | |
ParseAcpiDbg2 ( | |
IN BOOLEAN Trace, | |
IN UINT8 *Ptr, | |
IN UINT32 AcpiTableLength, | |
IN UINT8 AcpiTableRevision | |
) | |
{ | |
UINT32 Offset; | |
UINT32 Index; | |
if (!Trace) { | |
return; | |
} | |
Offset = ParseAcpi ( | |
TRUE, | |
0, | |
"DBG2", | |
Ptr, | |
AcpiTableLength, | |
PARSER_PARAMS (Dbg2Parser) | |
); | |
// Check if the values used to control the parsing logic have been | |
// successfully read. | |
if ((OffsetDbgDeviceInfo == NULL) || | |
(NumberDbgDeviceInfo == NULL)) | |
{ | |
IncrementErrorCount (); | |
Print ( | |
L"ERROR: Insufficient table length. AcpiTableLength = %d\n", | |
AcpiTableLength | |
); | |
return; | |
} | |
Offset = *OffsetDbgDeviceInfo; | |
Index = 0; | |
while (Index++ < *NumberDbgDeviceInfo) { | |
// Parse the Debug Device Information Structure header to obtain Length | |
ParseAcpi ( | |
FALSE, | |
0, | |
NULL, | |
Ptr + Offset, | |
AcpiTableLength - Offset, | |
PARSER_PARAMS (DbgDevInfoHeaderParser) | |
); | |
// Check if the values used to control the parsing logic have been | |
// successfully read. | |
if (DbgDevInfoLen == NULL) { | |
IncrementErrorCount (); | |
Print ( | |
L"ERROR: Insufficient remaining table buffer length to read the " \ | |
L"Debug Device Information structure's 'Length' field. " \ | |
L"RemainingTableBufferLength = %d.\n", | |
AcpiTableLength - Offset | |
); | |
return; | |
} | |
// Validate Debug Device Information Structure length | |
if ((*DbgDevInfoLen == 0) || | |
((Offset + (*DbgDevInfoLen)) > AcpiTableLength)) | |
{ | |
IncrementErrorCount (); | |
Print ( | |
L"ERROR: Invalid Debug Device Information Structure length. " \ | |
L"Length = %d. Offset = %d. AcpiTableLength = %d.\n", | |
*DbgDevInfoLen, | |
Offset, | |
AcpiTableLength | |
); | |
return; | |
} | |
DumpDbgDeviceInfo (Ptr + Offset, (*DbgDevInfoLen)); | |
Offset += (*DbgDevInfoLen); | |
} | |
} |