mirror of https://github.com/acidanthera/audk.git
453 lines
13 KiB
C
453 lines
13 KiB
C
/** @file
|
|
ACPI Sdt Protocol Driver
|
|
|
|
Copyright (c) 2010, 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"
|
|
|
|
/**
|
|
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
|
|
);
|
|
}
|