blob: fbcf340e4b855d5300a98da55e41d0cb4952b89d [file] [log] [blame]
/** @file
ACPI Sdt Protocol Driver
Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "AcpiTable.h"
/**
Retrieve option term according to AmlByteEncoding and Buffer.
@param[in] AmlByteEncoding AML Byte Encoding.
@param[in] Buffer AML buffer.
@param[in] MaxBufferSize AML buffer MAX size. The parser can not parse any data exceed this region.
@param[in] TermIndex Index of the data to retrieve from the object.
@param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
for the specified index.
@param[out] Data Upon return, points to the pointer to the data.
@param[out] DataSize Upon return, points to the size of Data.
@retval EFI_SUCCESS Success.
@retval EFI_INVALID_PARAMETER Buffer does not refer to a valid ACPI object.
**/
EFI_STATUS
AmlParseOptionTerm (
IN AML_BYTE_ENCODING *AmlByteEncoding,
IN UINT8 *Buffer,
IN UINTN MaxBufferSize,
IN AML_OP_PARSE_INDEX TermIndex,
OUT EFI_ACPI_DATA_TYPE *DataType,
OUT VOID **Data,
OUT UINTN *DataSize
)
{
AML_BYTE_ENCODING *ChildAmlByteEncoding;
EFI_STATUS Status;
if (DataType != NULL) {
*DataType = AmlTypeToAcpiType (AmlByteEncoding->Format[TermIndex - 1]);
}
if (Data != NULL) {
*Data = Buffer;
}
//
// Parse term according to AML type
//
switch (AmlByteEncoding->Format[TermIndex - 1]) {
case AML_UINT8:
*DataSize = sizeof (UINT8);
break;
case AML_UINT16:
*DataSize = sizeof (UINT16);
break;
case AML_UINT32:
*DataSize = sizeof (UINT32);
break;
case AML_UINT64:
*DataSize = sizeof (UINT64);
break;
case AML_STRING:
*DataSize = AsciiStrSize ((CHAR8 *)Buffer);
break;
case AML_NAME:
Status = AmlGetNameStringSize (Buffer, DataSize);
if (EFI_ERROR (Status)) {
return EFI_INVALID_PARAMETER;
}
break;
case AML_OBJECT:
ChildAmlByteEncoding = AmlSearchByOpByte (Buffer);
if (ChildAmlByteEncoding == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// NOTE: We need override DataType here, if there is a case the AML_OBJECT is AML_NAME.
// We need convert type from EFI_ACPI_DATA_TYPE_CHILD to EFI_ACPI_DATA_TYPE_NAME_STRING.
// We should not return CHILD because there is NO OpCode for NameString.
//
if ((ChildAmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
if (DataType != NULL) {
*DataType = AmlTypeToAcpiType (AML_NAME);
}
Status = AmlGetNameStringSize (Buffer, DataSize);
if (EFI_ERROR (Status)) {
return EFI_INVALID_PARAMETER;
}
break;
}
//
// It is real AML_OBJECT
//
*DataSize = AmlGetObjectSize (
ChildAmlByteEncoding,
Buffer,
MaxBufferSize
);
if (*DataSize == 0) {
return EFI_INVALID_PARAMETER;
}
break;
case AML_NONE:
//
// No term
//
case AML_OPCODE:
default:
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
if (*DataSize > MaxBufferSize) {
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
/**
Retrieve information according to AmlByteEncoding and Buffer.
@param[in] AmlByteEncoding AML Byte Encoding.
@param[in] Buffer AML buffer.
@param[in] MaxBufferSize AML buffer MAX size. The parser can not parse any data exceed this region.
@param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
in the ACPI encoding, with index 0 always being the ACPI opcode.
@param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
for the specified index.
@param[out] Data Upon return, points to the pointer to the data.
@param[out] DataSize Upon return, points to the size of Data.
@retval EFI_SUCCESS Success.
@retval EFI_INVALID_PARAMETER Buffer does not refer to a valid ACPI object.
**/
EFI_STATUS
AmlParseOptionCommon (
IN AML_BYTE_ENCODING *AmlByteEncoding,
IN UINT8 *Buffer,
IN UINTN MaxBufferSize,
IN AML_OP_PARSE_INDEX Index,
OUT EFI_ACPI_DATA_TYPE *DataType,
OUT VOID **Data,
OUT UINTN *DataSize
)
{
UINT8 *CurrentBuffer;
UINTN PkgLength;
UINTN OpLength;
UINTN PkgOffset;
AML_OP_PARSE_INDEX TermIndex;
EFI_STATUS Status;
ASSERT ((Index <= AmlByteEncoding->MaxIndex) || (Index == AML_OP_PARSE_INDEX_GET_SIZE));
//
// 0. Check if this is NAME string.
//
if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
//
// Only allow GET_SIZE
//
if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
return EFI_INVALID_PARAMETER;
}
//
// return NameString size
//
Status = AmlGetNameStringSize (Buffer, DataSize);
if (EFI_ERROR (Status)) {
return EFI_INVALID_PARAMETER;
}
if (*DataSize > MaxBufferSize) {
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
//
// Not NAME string, start parsing
//
CurrentBuffer = Buffer;
//
// 1. Get OpCode
//
if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
*DataType = EFI_ACPI_DATA_TYPE_OPCODE;
*Data = (VOID *)CurrentBuffer;
}
if (*CurrentBuffer == AML_EXT_OP) {
OpLength = 2;
} else {
OpLength = 1;
}
*DataSize = OpLength;
if (Index == AML_OP_PARSE_INDEX_GET_OPCODE) {
return EFI_SUCCESS;
}
if (OpLength > MaxBufferSize) {
return EFI_INVALID_PARAMETER;
}
CurrentBuffer += OpLength;
//
// 2. Skip PkgLength field, if have
//
if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
PkgOffset = AmlGetPkgLength (CurrentBuffer, &PkgLength);
//
// Override MaxBufferSize if it is valid PkgLength
//
if (OpLength + PkgLength > MaxBufferSize) {
return EFI_INVALID_PARAMETER;
} else {
MaxBufferSize = OpLength + PkgLength;
}
} else {
PkgOffset = 0;
PkgLength = 0;
}
CurrentBuffer += PkgOffset;
//
// 3. Get Term one by one.
//
TermIndex = AML_OP_PARSE_INDEX_GET_TERM1;
while ((Index >= TermIndex) && (TermIndex <= AmlByteEncoding->MaxIndex) && ((UINTN)CurrentBuffer < (UINTN)Buffer + MaxBufferSize)) {
Status = AmlParseOptionTerm (
AmlByteEncoding,
CurrentBuffer,
(UINTN)Buffer + MaxBufferSize - (UINTN)CurrentBuffer,
TermIndex,
DataType,
Data,
DataSize
);
if (EFI_ERROR (Status)) {
return EFI_INVALID_PARAMETER;
}
if (Index == TermIndex) {
//
// Done
//
return EFI_SUCCESS;
}
//
// Parse next one
//
CurrentBuffer += *DataSize;
TermIndex++;
}
//
// Finish all options, but no option found.
//
if ((UINTN)CurrentBuffer > (UINTN)Buffer + MaxBufferSize) {
return EFI_INVALID_PARAMETER;
}
if ((UINTN)CurrentBuffer == (UINTN)Buffer + MaxBufferSize) {
if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
return EFI_INVALID_PARAMETER;
}
}
//
// 4. Finish parsing all node, return size
//
ASSERT (Index == AML_OP_PARSE_INDEX_GET_SIZE);
if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
*DataSize = OpLength + PkgLength;
} else {
*DataSize = (UINTN)CurrentBuffer - (UINTN)Buffer;
}
return EFI_SUCCESS;
}
/**
Return object size.
@param[in] AmlByteEncoding AML Byte Encoding.
@param[in] Buffer AML object buffer.
@param[in] MaxBufferSize AML object buffer MAX size. The parser can not parse any data exceed this region.
@return Size of the object.
**/
UINTN
AmlGetObjectSize (
IN AML_BYTE_ENCODING *AmlByteEncoding,
IN UINT8 *Buffer,
IN UINTN MaxBufferSize
)
{
EFI_STATUS Status;
UINTN DataSize;
Status = AmlParseOptionCommon (
AmlByteEncoding,
Buffer,
MaxBufferSize,
AML_OP_PARSE_INDEX_GET_SIZE,
NULL,
NULL,
&DataSize
);
if (EFI_ERROR (Status)) {
return 0;
} else {
return DataSize;
}
}
/**
Return object name.
@param[in] AmlHandle AML handle.
@return Name of the object.
**/
CHAR8 *
AmlGetObjectName (
IN EFI_AML_HANDLE *AmlHandle
)
{
AML_BYTE_ENCODING *AmlByteEncoding;
VOID *NameString;
UINTN NameSize;
AML_OP_PARSE_INDEX TermIndex;
EFI_STATUS Status;
EFI_ACPI_DATA_TYPE DataType;
AmlByteEncoding = AmlHandle->AmlByteEncoding;
ASSERT ((AmlByteEncoding->Attribute & AML_IN_NAMESPACE) != 0);
//
// Find out Last Name index, according to OpCode table.
// The last name will be the node name by design.
//
TermIndex = AmlByteEncoding->MaxIndex;
for (TermIndex = AmlByteEncoding->MaxIndex; TermIndex > 0; TermIndex--) {
if (AmlByteEncoding->Format[TermIndex - 1] == AML_NAME) {
break;
}
}
ASSERT (TermIndex != 0);
//
// Get Name for this node.
//
Status = AmlParseOptionHandleCommon (
AmlHandle,
TermIndex,
&DataType,
&NameString,
&NameSize
);
if (EFI_ERROR (Status)) {
return NULL;
}
ASSERT (DataType == EFI_ACPI_DATA_TYPE_NAME_STRING);
return NameString;
}
/**
Return offset of last option.
@param[in] AmlHandle AML Handle.
@param[out] Buffer Upon return, points to the offset after last option.
@retval EFI_SUCCESS Success.
@retval EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
**/
EFI_STATUS
AmlGetOffsetAfterLastOption (
IN EFI_AML_HANDLE *AmlHandle,
OUT UINT8 **Buffer
)
{
EFI_ACPI_DATA_TYPE DataType;
VOID *Data;
UINTN DataSize;
EFI_STATUS Status;
Status = AmlParseOptionHandleCommon (
AmlHandle,
AmlHandle->AmlByteEncoding->MaxIndex,
&DataType,
&Data,
&DataSize
);
if (EFI_ERROR (Status)) {
return EFI_INVALID_PARAMETER;
}
//
// We need to parse the rest buffer after last node.
//
*Buffer = (UINT8 *)((UINTN)Data + DataSize);
//
// We need skip PkgLength if no Option
//
if (DataType == EFI_ACPI_DATA_TYPE_OPCODE) {
*Buffer += AmlGetPkgLength (*Buffer, &DataSize);
}
return EFI_SUCCESS;
}
/**
Retrieve information according to AmlHandle
@param[in] AmlHandle AML handle.
@param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
in the ACPI encoding, with index 0 always being the ACPI opcode.
@param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
for the specified index.
@param[out] Data Upon return, points to the pointer to the data.
@param[out] DataSize Upon return, points to the size of Data.
@retval EFI_SUCCESS Success.
@retval EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
**/
EFI_STATUS
AmlParseOptionHandleCommon (
IN EFI_AML_HANDLE *AmlHandle,
IN AML_OP_PARSE_INDEX Index,
OUT EFI_ACPI_DATA_TYPE *DataType,
OUT VOID **Data,
OUT UINTN *DataSize
)
{
return AmlParseOptionCommon (
AmlHandle->AmlByteEncoding,
AmlHandle->Buffer,
AmlHandle->Size,
Index,
DataType,
Data,
DataSize
);
}