audk/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlString.c

546 lines
10 KiB
C

/** @file
ACPI Sdt Protocol Driver
Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "AcpiTable.h"
/**
Check if it is AML Root name
@param[in] Buffer AML path.
@retval TRUE AML path is root.
@retval FALSE AML path is not root.
**/
BOOLEAN
AmlIsRootPath (
IN UINT8 *Buffer
)
{
if ((Buffer[0] == AML_ROOT_CHAR) && (Buffer[1] == 0)) {
return TRUE;
} else {
return FALSE;
}
}
/**
Check if it is AML LeadName.
@param[in] Ch Char.
@retval TRUE Char is AML LeadName.
@retval FALSE Char is not AML LeadName.
**/
BOOLEAN
AmlIsLeadName (
IN CHAR8 Ch
)
{
if ((Ch == '_') || (Ch >= 'A' && Ch <= 'Z')) {
return TRUE;
} else {
return FALSE;
}
}
/**
Check if it is AML Name.
@param[in] Ch Char.
@retval TRUE Char is AML Name.
@retval FALSE Char is not AML Name.
**/
BOOLEAN
AmlIsName (
IN CHAR8 Ch
)
{
if (AmlIsLeadName (Ch) || (Ch >= '0' && Ch <= '9')) {
return TRUE;
} else {
return FALSE;
}
}
/**
Return is buffer is AML NameSeg.
@param[in] Buffer AML NameSement.
@retval TRUE It is AML NameSegment.
@retval FALSE It is not AML NameSegment.
**/
BOOLEAN
AmlIsNameSeg (
IN UINT8 *Buffer
)
{
UINTN Index;
if (!AmlIsLeadName (Buffer[0])) {
return FALSE;
}
for (Index = 1; Index < AML_NAME_SEG_SIZE; Index++) {
if (!AmlIsName (Buffer[Index])) {
return FALSE;
}
}
return TRUE;
}
/**
Get AML NameString size.
@param[in] Buffer AML NameString.
@param[out] BufferSize AML NameString size
@retval EFI_SUCCESS Success.
@retval EFI_INVALID_PARAMETER Buffer does not refer to a valid AML NameString.
**/
EFI_STATUS
AmlGetNameStringSize (
IN UINT8 *Buffer,
OUT UINTN *BufferSize
)
{
UINTN SegCount;
UINTN Length;
UINTN Index;
Length = 0;
//
// Parse root or parent prefix
//
if (*Buffer == AML_ROOT_CHAR) {
Buffer ++;
Length ++;
} else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
do {
Buffer ++;
Length ++;
} while (*Buffer == AML_PARENT_PREFIX_CHAR);
}
//
// Parse name segment
//
if (*Buffer == AML_DUAL_NAME_PREFIX) {
Buffer ++;
Length ++;
SegCount = 2;
} else if (*Buffer == AML_MULTI_NAME_PREFIX) {
Buffer ++;
Length ++;
SegCount = *Buffer;
Buffer ++;
Length ++;
} else if (*Buffer == 0) {
//
// NULL Name, only for Root
//
SegCount = 0;
Buffer --;
if ((Length == 1) && (*Buffer == AML_ROOT_CHAR)) {
*BufferSize = 2;
return EFI_SUCCESS;
} else {
return EFI_INVALID_PARAMETER;
}
} else {
//
// NameSeg
//
SegCount = 1;
}
Index = 0;
do {
if (!AmlIsNameSeg (Buffer)) {
return EFI_INVALID_PARAMETER;
}
Buffer += AML_NAME_SEG_SIZE;
Length += AML_NAME_SEG_SIZE;
Index ++;
} while (Index < SegCount);
*BufferSize = Length;
return EFI_SUCCESS;
}
/**
Check if it is ASL LeadName.
@param[in] Ch Char.
@retval TRUE Char is ASL LeadName.
@retval FALSE Char is not ASL LeadName.
**/
BOOLEAN
AmlIsAslLeadName (
IN CHAR8 Ch
)
{
if (AmlIsLeadName (Ch) || (Ch >= 'a' && Ch <= 'z')) {
return TRUE;
} else {
return FALSE;
}
}
/**
Check if it is ASL Name.
@param[in] Ch Char.
@retval TRUE Char is ASL Name.
@retval FALSE Char is not ASL Name.
**/
BOOLEAN
AmlIsAslName (
IN CHAR8 Ch
)
{
if (AmlIsAslLeadName (Ch) || (Ch >= '0' && Ch <= '9')) {
return TRUE;
} else {
return FALSE;
}
}
/**
Get ASL NameString size.
@param[in] Buffer ASL NameString.
@return ASL NameString size.
**/
UINTN
AmlGetAslNameSegLength (
IN UINT8 *Buffer
)
{
UINTN Length;
UINTN Index;
if (*Buffer == 0) {
return 0;
}
Length = 0;
//
// 1st
//
if (AmlIsAslLeadName (*Buffer)) {
Length ++;
Buffer ++;
}
if ((*Buffer == 0) || (*Buffer == '.')) {
return Length;
}
//
// 2, 3, 4 name char
//
for (Index = 0; Index < 3; Index++) {
if (AmlIsAslName (*Buffer)) {
Length ++;
Buffer ++;
}
if ((*Buffer == 0) || (*Buffer == '.')) {
return Length;
}
}
//
// Invalid ASL name
//
return 0;
}
/**
Get ASL NameString size.
@param[in] Buffer ASL NameString.
@param[out] Root On return, points to Root char number.
@param[out] Parent On return, points to Parent char number.
@param[out] SegCount On return, points to Segment count.
@return ASL NameString size.
**/
UINTN
AmlGetAslNameStringSize (
IN UINT8 *Buffer,
OUT UINTN *Root,
OUT UINTN *Parent,
OUT UINTN *SegCount
)
{
UINTN NameLength;
UINTN TotalLength;
*Root = 0;
*Parent = 0;
*SegCount = 0;
TotalLength = 0;
NameLength = 0;
if (*Buffer == AML_ROOT_CHAR) {
*Root = 1;
Buffer ++;
} else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
do {
Buffer ++;
(*Parent) ++;
} while (*Buffer == AML_PARENT_PREFIX_CHAR);
}
//
// Now parse name
//
while (*Buffer != 0) {
NameLength = AmlGetAslNameSegLength (Buffer);
if ((NameLength == 0) || (NameLength > AML_NAME_SEG_SIZE)) {
return 0;
}
(*SegCount) ++;
Buffer += NameLength;
if (*Buffer == 0) {
break;
}
Buffer ++;
}
//
// Check SegCoount
//
if (*SegCount > 0xFF) {
return 0;
}
//
// Calculate total length
//
TotalLength = *Root + *Parent + (*SegCount) * AML_NAME_SEG_SIZE;
if (*SegCount > 2) {
TotalLength += 2;
} else if (*SegCount == 2) {
TotalLength += 1;
}
//
// Add NULL char
//
TotalLength ++;
return TotalLength;
}
/**
Copy mem, and cast all the char in dest to be upper case.
@param[in] DstBuffer Destination buffer.
@param[in] SrcBuffer Source buffer.
@param[in] Length Buffer length.
**/
VOID
AmlUpperCaseCopyMem (
IN UINT8 *DstBuffer,
IN UINT8 *SrcBuffer,
IN UINTN Length
)
{
UINTN Index;
for (Index = 0; Index < Length; Index++) {
if (SrcBuffer[Index] >= 'a' && SrcBuffer[Index] <= 'z') {
DstBuffer[Index] = (UINT8)(SrcBuffer[Index] - 'a' + 'A');
} else {
DstBuffer[Index] = SrcBuffer[Index];
}
}
}
/**
Return AML name according to ASL name.
The caller need free the AmlName returned.
@param[in] AslPath ASL name.
@return AmlName
**/
UINT8 *
AmlNameFromAslName (
IN UINT8 *AslPath
)
{
UINTN Root;
UINTN Parent;
UINTN SegCount;
UINTN TotalLength;
UINTN NameLength;
UINT8 *Buffer;
UINT8 *AmlPath;
UINT8 *AmlBuffer;
TotalLength = AmlGetAslNameStringSize (AslPath, &Root, &Parent, &SegCount);
if (TotalLength == 0) {
return NULL;
}
AmlPath = AllocatePool (TotalLength);
ASSERT (AmlPath != NULL);
AmlBuffer = AmlPath;
Buffer = AslPath;
//
// Handle Root and Parent
//
if (Root == 1) {
*AmlBuffer = AML_ROOT_CHAR;
AmlBuffer ++;
Buffer ++;
} else if (Parent > 0) {
SetMem (AmlBuffer, Parent, AML_PARENT_PREFIX_CHAR);
AmlBuffer += Parent;
Buffer += Parent;
}
//
// Handle SegCount
//
if (SegCount > 2) {
*AmlBuffer = AML_MULTI_NAME_PREFIX;
AmlBuffer ++;
*AmlBuffer = (UINT8)SegCount;
AmlBuffer ++;
} else if (SegCount == 2) {
*AmlBuffer = AML_DUAL_NAME_PREFIX;
AmlBuffer ++;
}
//
// Now to name
//
while (*Buffer != 0) {
NameLength = AmlGetAslNameSegLength (Buffer);
ASSERT ((NameLength != 0) && (NameLength <= AML_NAME_SEG_SIZE));
AmlUpperCaseCopyMem (AmlBuffer, Buffer, NameLength);
SetMem (AmlBuffer + NameLength, AML_NAME_SEG_SIZE - NameLength, AML_NAME_CHAR__);
Buffer += NameLength;
AmlBuffer += AML_NAME_SEG_SIZE;
if (*Buffer == 0) {
break;
}
Buffer ++;
}
//
// Add NULL
//
AmlPath[TotalLength - 1] = 0;
return AmlPath;
}
/**
Print AML NameSeg.
@param[in] Buffer AML NameSeg.
**/
VOID
AmlPrintNameSeg (
IN UINT8 *Buffer
)
{
DEBUG ((EFI_D_ERROR, "%c", Buffer[0]));
if ((Buffer[1] == '_') && (Buffer[2] == '_') && (Buffer[3] == '_')) {
return ;
}
DEBUG ((EFI_D_ERROR, "%c", Buffer[1]));
if ((Buffer[2] == '_') && (Buffer[3] == '_')) {
return ;
}
DEBUG ((EFI_D_ERROR, "%c", Buffer[2]));
if (Buffer[3] == '_') {
return ;
}
DEBUG ((EFI_D_ERROR, "%c", Buffer[3]));
return ;
}
/**
Print AML NameString.
@param[in] Buffer AML NameString.
**/
VOID
AmlPrintNameString (
IN UINT8 *Buffer
)
{
UINT8 SegCount;
UINT8 Index;
if (*Buffer == AML_ROOT_CHAR) {
//
// RootChar
//
Buffer ++;
DEBUG ((EFI_D_ERROR, "\\"));
} else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
//
// ParentPrefixChar
//
do {
Buffer ++;
DEBUG ((EFI_D_ERROR, "^"));
} while (*Buffer == AML_PARENT_PREFIX_CHAR);
}
if (*Buffer == AML_DUAL_NAME_PREFIX) {
//
// DualName
//
Buffer ++;
SegCount = 2;
} else if (*Buffer == AML_MULTI_NAME_PREFIX) {
//
// MultiName
//
Buffer ++;
SegCount = *Buffer;
Buffer ++;
} else if (*Buffer == 0) {
//
// NULL Name
//
return ;
} else {
//
// NameSeg
//
SegCount = 1;
}
AmlPrintNameSeg (Buffer);
Buffer += AML_NAME_SEG_SIZE;
for (Index = 0; Index < SegCount - 1; Index++) {
DEBUG ((EFI_D_ERROR, "."));
AmlPrintNameSeg (Buffer);
Buffer += AML_NAME_SEG_SIZE;
}
return ;
}