mirror of https://github.com/acidanthera/audk.git
1474 lines
46 KiB
C
1474 lines
46 KiB
C
/** @file
|
|
AML Parser.
|
|
|
|
Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
|
|
#include <Parser/AmlParser.h>
|
|
|
|
#include <AmlCoreInterface.h>
|
|
#include <AmlDbgPrint/AmlDbgPrint.h>
|
|
#include <Parser/AmlFieldListParser.h>
|
|
#include <Parser/AmlMethodParser.h>
|
|
#include <Parser/AmlResourceDataParser.h>
|
|
#include <String/AmlString.h>
|
|
#include <Tree/AmlNode.h>
|
|
#include <Tree/AmlTree.h>
|
|
|
|
/*
|
|
AML Tree
|
|
--------
|
|
|
|
Each ASL Statement is represented in AML as and ObjectNode.
|
|
Each ObjectNode has an Opcode and has up to six FixedArguments
|
|
followed by a list of VariableArguments.
|
|
(ObjectNode)
|
|
\
|
|
|- [0][1][2][3][4][5] # Fixed Arguments
|
|
|- {(VarArg1)->(VarArg2)->(VarArg3)->...N} # Variable Arguments
|
|
|
|
A RootNode is a special type of Object Node that does not have an
|
|
Opcode or Fixed Arguments. It only has a list of VariableArguments
|
|
(RootNode)
|
|
\
|
|
|- {(VarArg1)->(VarArg2)->(VarArg3)->...N} # Variable Arguments
|
|
|
|
A DataNode consists of a data buffer.
|
|
|
|
A FixedArgument or VariableArgument can be either an ObjectNode or
|
|
a DataNode.
|
|
|
|
Example:
|
|
ASL code sample:
|
|
Device (DEV0) {
|
|
Name (VAR0, 0x6)
|
|
}
|
|
|
|
Tree generated from the ASL code:
|
|
(RootNode)
|
|
\
|
|
|- {(Device statement (ObjectNode))} # Variable Arg of the
|
|
\ # RootNode
|
|
|
|
|
|- [0] - Device Name (DataNode)(="DEV0") # Fixed Arg0 of the
|
|
| # Device() statement
|
|
|
|
|
|- {(Name statement (ObjectNode))} # Variable Arg of the
|
|
\ # Device() statement
|
|
|
|
|
|- [0] - Name statement(DataNode)(="VAR0") # Fixed Arg0 of the
|
|
| # Name() statement
|
|
|- [1] - Value(DataNode)(=0x6) # Fixed Arg1 of the
|
|
# Name() statement
|
|
*/
|
|
|
|
// Forward declaration.
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlParseStream (
|
|
IN AML_NODE_HEADER *Node,
|
|
IN OUT AML_STREAM *FStream,
|
|
IN OUT LIST_ENTRY *NameSpaceRefList
|
|
);
|
|
|
|
/** Function pointer to parse an AML construct.
|
|
|
|
The expected format of the AML construct is passed in the
|
|
ExpectedFormat argument. The available formats are available in
|
|
the AML_PARSE_FORMAT enum definition.
|
|
|
|
An object node or a data node is created in the function,
|
|
and returned through the OutNode parameter. This node should
|
|
be attached after this function returns.
|
|
|
|
@param [in] ParentNode Parent node to which the parsed
|
|
AML construct will be attached.
|
|
@param [in] ExpectedFormat Format of the AML construct to parse.
|
|
@param [in, out] FStream Forward stream containing the AML bytecode
|
|
to parse.
|
|
The stream must not be at its end.
|
|
@param [out] OutNode Pointer holding the node created from the
|
|
parsed AML bytecode.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
**/
|
|
typedef
|
|
EFI_STATUS
|
|
EFIAPI
|
|
(*AML_PARSE_FUNCTION) (
|
|
IN CONST AML_NODE_HEADER *Node,
|
|
IN AML_PARSE_FORMAT ExpectedFormat,
|
|
IN OUT AML_STREAM *FStream,
|
|
OUT AML_NODE_HEADER **OutNode
|
|
);
|
|
|
|
/** Parse a UInt<X> (where X=8, 16, 32 or 64).
|
|
|
|
A data node is created and returned through the OutNode parameter.
|
|
|
|
@param [in] ParentNode Parent node to which the parsed
|
|
AML construct will be attached.
|
|
@param [in] ExpectedFormat Format of the AML construct to parse.
|
|
@param [in, out] FStream Forward stream containing the AML bytecode
|
|
to parse.
|
|
The stream must not be at its end.
|
|
@param [out] OutNode Pointer holding the node created from the
|
|
parsed AML bytecode.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlParseUIntX (
|
|
IN CONST AML_NODE_HEADER *ParentNode,
|
|
IN AML_PARSE_FORMAT ExpectedFormat,
|
|
IN OUT AML_STREAM *FStream,
|
|
OUT AML_NODE_HEADER **OutNode
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 UIntXSize;
|
|
|
|
if ((!IS_AML_ROOT_NODE (ParentNode) &&
|
|
!IS_AML_OBJECT_NODE (ParentNode)) ||
|
|
((ExpectedFormat != EAmlUInt8) &&
|
|
(ExpectedFormat != EAmlUInt16) &&
|
|
(ExpectedFormat != EAmlUInt32) &&
|
|
(ExpectedFormat != EAmlUInt64)) ||
|
|
!IS_STREAM (FStream) ||
|
|
IS_END_OF_STREAM (FStream) ||
|
|
!IS_STREAM_FORWARD (FStream) ||
|
|
(OutNode == NULL))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
switch (ExpectedFormat) {
|
|
case EAmlUInt8:
|
|
UIntXSize = 1;
|
|
break;
|
|
case EAmlUInt16:
|
|
UIntXSize = 2;
|
|
break;
|
|
case EAmlUInt32:
|
|
UIntXSize = 4;
|
|
break;
|
|
case EAmlUInt64:
|
|
UIntXSize = 8;
|
|
break;
|
|
default:
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = AmlCreateDataNode (
|
|
AmlTypeToNodeDataType (ExpectedFormat),
|
|
AmlStreamGetCurrPos (FStream),
|
|
UIntXSize,
|
|
(AML_DATA_NODE **)OutNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
AMLDBG_DUMP_RAW (AmlStreamGetCurrPos (FStream), UIntXSize);
|
|
|
|
// Move stream forward by the size of UIntX.
|
|
Status = AmlStreamProgress (FStream, UIntXSize);
|
|
if (EFI_ERROR (Status)) {
|
|
AmlDeleteTree (*OutNode);
|
|
ASSERT (0);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Parse an AML NameString.
|
|
|
|
A data node is created and returned through the OutNode parameter.
|
|
|
|
@param [in] ParentNode Parent node to which the parsed
|
|
AML construct will be attached.
|
|
@param [in] ExpectedFormat Format of the AML construct to parse.
|
|
@param [in, out] FStream Forward stream containing the AML bytecode
|
|
to parse.
|
|
The stream must not be at its end.
|
|
@param [out] OutNode Pointer holding the node created from the
|
|
parsed AML bytecode.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlParseNameString (
|
|
IN CONST AML_NODE_HEADER *ParentNode,
|
|
IN AML_PARSE_FORMAT ExpectedFormat,
|
|
IN OUT AML_STREAM *FStream,
|
|
OUT AML_NODE_HEADER **OutNode
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
CONST UINT8 *Buffer;
|
|
CONST AML_BYTE_ENCODING *ByteEncoding;
|
|
UINT32 StrSize;
|
|
|
|
if ((!IS_AML_ROOT_NODE (ParentNode) &&
|
|
!IS_AML_OBJECT_NODE (ParentNode)) ||
|
|
(ExpectedFormat != EAmlName) ||
|
|
!IS_STREAM (FStream) ||
|
|
IS_END_OF_STREAM (FStream) ||
|
|
!IS_STREAM_FORWARD (FStream) ||
|
|
(OutNode == NULL))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Buffer = (CONST UINT8 *)AmlStreamGetCurrPos (FStream);
|
|
ByteEncoding = AmlGetByteEncoding (Buffer);
|
|
if ((ByteEncoding == NULL) ||
|
|
((ByteEncoding->Attribute & AML_IS_NAME_CHAR) == 0))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Parse the NameString.
|
|
Status = AmlGetNameStringSize ((CONST CHAR8 *)Buffer, &StrSize);
|
|
if ((EFI_ERROR (Status)) ||
|
|
(StrSize > AmlStreamGetFreeSpace (FStream)))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = AmlCreateDataNode (
|
|
EAmlNodeDataTypeNameString,
|
|
Buffer,
|
|
StrSize,
|
|
(AML_DATA_NODE **)OutNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
AMLDBG_DUMP_RAW (AmlStreamGetCurrPos (FStream), StrSize);
|
|
|
|
// Move the stream forward by StrSize.
|
|
Status = AmlStreamProgress (FStream, StrSize);
|
|
if (EFI_ERROR (Status)) {
|
|
AmlDeleteTree (*OutNode);
|
|
ASSERT (0);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Parse an AML String.
|
|
|
|
A data node is created and returned through the OutNode parameter.
|
|
|
|
@param [in] ParentNode Parent node to which the parsed
|
|
AML construct will be attached.
|
|
@param [in] ExpectedFormat Format of the AML construct to parse.
|
|
@param [in, out] FStream Forward stream containing the AML bytecode
|
|
to parse.
|
|
The stream must not be at its end.
|
|
@param [out] OutNode Pointer holding the node created from the
|
|
parsed AML bytecode.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlParseString (
|
|
IN CONST AML_NODE_HEADER *ParentNode,
|
|
IN AML_PARSE_FORMAT ExpectedFormat,
|
|
IN OUT AML_STREAM *FStream,
|
|
OUT AML_NODE_HEADER **OutNode
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 StrSize;
|
|
UINT8 Byte;
|
|
CONST UINT8 *Buffer;
|
|
|
|
if ((!IS_AML_ROOT_NODE (ParentNode) &&
|
|
!IS_AML_OBJECT_NODE (ParentNode)) ||
|
|
(ExpectedFormat != EAmlString) ||
|
|
!IS_STREAM (FStream) ||
|
|
IS_END_OF_STREAM (FStream) ||
|
|
!IS_STREAM_FORWARD (FStream) ||
|
|
(OutNode == NULL))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Buffer = (CONST UINT8 *)AmlStreamGetCurrPos (FStream);
|
|
StrSize = 0;
|
|
// AML String is NULL terminated.
|
|
do {
|
|
// Reading the stream moves the stream forward aswell.
|
|
Status = AmlStreamReadByte (FStream, &Byte);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
StrSize++;
|
|
} while (Byte != '\0');
|
|
|
|
AMLDBG_DUMP_RAW (Buffer, StrSize);
|
|
|
|
Status = AmlCreateDataNode (
|
|
AmlTypeToNodeDataType (ExpectedFormat),
|
|
Buffer,
|
|
StrSize,
|
|
(AML_DATA_NODE **)OutNode
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Parse an AML object.
|
|
|
|
An object can be resolved as an AML object with an OpCode,
|
|
or a NameString. An object node or a data node is created
|
|
and returned through the OutNode parameter.
|
|
|
|
@param [in] ParentNode Parent node to which the parsed
|
|
AML construct will be attached.
|
|
@param [in] ExpectedFormat Format of the AML construct to parse.
|
|
@param [in, out] FStream Forward stream containing the AML bytecode
|
|
to parse.
|
|
The stream must not be at its end.
|
|
@param [out] OutNode Pointer holding the node created from the
|
|
parsed AML bytecode.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlParseObject (
|
|
IN CONST AML_NODE_HEADER *ParentNode,
|
|
IN AML_PARSE_FORMAT ExpectedFormat,
|
|
IN OUT AML_STREAM *FStream,
|
|
OUT AML_NODE_HEADER **OutNode
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
UINT8 OpCodeSize;
|
|
UINT32 PkgLength;
|
|
UINT32 PkgOffset;
|
|
UINT32 FreeSpace;
|
|
|
|
CONST AML_BYTE_ENCODING *AmlByteEncoding;
|
|
CONST UINT8 *Buffer;
|
|
|
|
if ((!IS_AML_ROOT_NODE (ParentNode) &&
|
|
!IS_AML_OBJECT_NODE (ParentNode)) ||
|
|
(ExpectedFormat != EAmlObject) ||
|
|
!IS_STREAM (FStream) ||
|
|
IS_END_OF_STREAM (FStream) ||
|
|
!IS_STREAM_FORWARD (FStream) ||
|
|
(OutNode == NULL))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
PkgLength = 0;
|
|
|
|
// 0. Get the AML Byte encoding.
|
|
AmlByteEncoding = AmlGetByteEncoding (AmlStreamGetCurrPos (FStream));
|
|
if (AmlByteEncoding == NULL) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// 1. Check for NameString.
|
|
// Indeed a NameString can be found when an AML object is expected.
|
|
// e.g. VAR0 = 3 // VAR0 is assigned an object which is a UINT.
|
|
// VAR1 = VAR2 // VAR2 is a NameString.
|
|
// If this is a NameString, return. A NameString can be a variable, a
|
|
// method invocation, etc.
|
|
if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
|
|
Status = AmlParseNameString (
|
|
ParentNode,
|
|
EAmlName,
|
|
FStream,
|
|
OutNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
// 2. Determine the OpCode size to move the stream forward.
|
|
Buffer = (CONST UINT8 *)AmlStreamGetCurrPos (FStream);
|
|
if (*Buffer == AML_EXT_OP) {
|
|
OpCodeSize = 2;
|
|
} else {
|
|
OpCodeSize = 1;
|
|
}
|
|
|
|
Status = AmlStreamProgress (FStream, OpCodeSize);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// Print the opcode.
|
|
AMLDBG_DUMP_RAW (Buffer, OpCodeSize);
|
|
|
|
if (!IS_END_OF_STREAM (FStream)) {
|
|
// 3. Parse the PkgLength field, if present.
|
|
if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
|
|
Buffer = (CONST UINT8 *)AmlStreamGetCurrPos (FStream);
|
|
PkgOffset = AmlGetPkgLength (Buffer, &PkgLength);
|
|
if (PkgOffset == 0) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Print the package length.
|
|
AMLDBG_DUMP_RAW (Buffer, PkgOffset);
|
|
|
|
// Adjust the size of the stream if it is valid package length.
|
|
FreeSpace = AmlStreamGetFreeSpace (FStream);
|
|
if (FreeSpace > PkgLength) {
|
|
// Reduce the stream size by (FreeSpace - PkgLength) bytes.
|
|
AmlStreamReduceMaxBufferSize (FStream, FreeSpace - PkgLength);
|
|
} else if (FreeSpace != PkgLength) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = AmlStreamProgress (FStream, PkgOffset);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
}
|
|
} else if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
|
|
// The stream terminated unexpectedly. A PkgLen had to be parsed.
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// 4. Create an Object Node.
|
|
Status = AmlCreateObjectNode (
|
|
AmlByteEncoding,
|
|
PkgLength,
|
|
(AML_OBJECT_NODE **)OutNode
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Parse a FieldPkgLen.
|
|
|
|
A FieldPkgLen can only be found in a field list, i.e. in a NamedField field
|
|
element. The PkgLen is otherwise part of the object node structure.
|
|
A data node is created and returned through the OutNode parameter.
|
|
|
|
@param [in] ParentNode Parent node to which the parsed
|
|
AML construct will be attached.
|
|
@param [in] ExpectedFormat Format of the AML construct to parse.
|
|
@param [in, out] FStream Forward stream containing the AML bytecode
|
|
to parse.
|
|
The stream must not be at its end.
|
|
@param [out] OutNode Pointer holding the node created from the
|
|
parsed AML bytecode.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlParseFieldPkgLen (
|
|
IN CONST AML_NODE_HEADER *ParentNode,
|
|
IN AML_PARSE_FORMAT ExpectedFormat,
|
|
IN OUT AML_STREAM *FStream,
|
|
OUT AML_NODE_HEADER **OutNode
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_STATUS Status1;
|
|
CONST UINT8 *Buffer;
|
|
UINT32 PkgOffset;
|
|
UINT32 PkgLength;
|
|
|
|
if (!AmlNodeHasAttribute (
|
|
(CONST AML_OBJECT_NODE *)ParentNode,
|
|
AML_IS_FIELD_ELEMENT
|
|
) ||
|
|
(ExpectedFormat != EAmlFieldPkgLen) ||
|
|
!IS_STREAM (FStream) ||
|
|
IS_END_OF_STREAM (FStream) ||
|
|
!IS_STREAM_FORWARD (FStream) ||
|
|
(OutNode == NULL))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Buffer = (CONST UINT8 *)AmlStreamGetCurrPos (FStream);
|
|
|
|
PkgOffset = AmlGetPkgLength (Buffer, &PkgLength);
|
|
if (PkgOffset == 0) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Warning: Since, updating of field elements is not supported, store the
|
|
// FieldPkgLength in a Data Node as a raw buffer.
|
|
Status = AmlCreateDataNode (
|
|
AmlTypeToNodeDataType (ExpectedFormat),
|
|
Buffer,
|
|
PkgOffset,
|
|
(AML_DATA_NODE **)OutNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
AMLDBG_DUMP_RAW (Buffer, PkgOffset);
|
|
|
|
Status = AmlStreamProgress (FStream, PkgOffset);
|
|
if (EFI_ERROR (Status)) {
|
|
Status1 = AmlDeleteNode (*OutNode);
|
|
ASSERT_EFI_ERROR (Status1);
|
|
ASSERT (0);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Array of functions pointers to parse the AML constructs.
|
|
|
|
The AML Byte encoding tables in Aml.c describe the format of the AML
|
|
statements. The AML_PARSE_FORMAT enum definition lists these constructs
|
|
and the corresponding parsing functions.
|
|
*/
|
|
AML_PARSE_FUNCTION mParseType[EAmlParseFormatMax] = {
|
|
NULL, // EAmlNone
|
|
AmlParseUIntX, // EAmlUInt8
|
|
AmlParseUIntX, // EAmlUInt16
|
|
AmlParseUIntX, // EAmlUInt32
|
|
AmlParseUIntX, // EAmlUInt64
|
|
AmlParseObject, // EAmlObject
|
|
AmlParseNameString, // EAmlName
|
|
AmlParseString, // EAmlString
|
|
AmlParseFieldPkgLen // EAmlFieldPkgLen
|
|
};
|
|
|
|
/** Check whether the NameString stored in the data node is a method invocation.
|
|
If so, create a method invocation node and return it.
|
|
|
|
@param [in] ParentNode Node to which the parsed AML construct
|
|
will be attached.
|
|
@param [in] DataNode Data node containing a NameString,
|
|
potentially being a method invocation.
|
|
@param [in, out] NameSpaceRefList List of namespace reference nodes.
|
|
@param [out] OutNode Pointer holding the method invocation
|
|
node if the NameString contained in the
|
|
data node is a method invocation.
|
|
NULL otherwise.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlCheckAndParseMethodInvoc (
|
|
IN CONST AML_NODE_HEADER *ParentNode,
|
|
IN AML_DATA_NODE *DataNode,
|
|
IN OUT LIST_ENTRY *NameSpaceRefList,
|
|
OUT AML_OBJECT_NODE **OutNode
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
AML_NAMESPACE_REF_NODE *NameSpaceRefNode;
|
|
AML_OBJECT_NODE *MethodInvocationNode;
|
|
AML_STREAM FStream;
|
|
|
|
if ((!IS_AML_ROOT_NODE (ParentNode) &&
|
|
!IS_AML_OBJECT_NODE (ParentNode)) ||
|
|
!IS_AML_DATA_NODE (DataNode) ||
|
|
(DataNode->DataType != EAmlNodeDataTypeNameString) ||
|
|
(NameSpaceRefList == NULL) ||
|
|
(OutNode == NULL))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Initialize a stream containing the NameString which is checked.
|
|
Status = AmlStreamInit (
|
|
&FStream,
|
|
DataNode->Buffer,
|
|
DataNode->Size,
|
|
EAmlStreamDirectionForward
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// Check whether the NameString is a method invocation.
|
|
NameSpaceRefNode = NULL;
|
|
Status = AmlIsMethodInvocation (
|
|
ParentNode,
|
|
&FStream,
|
|
NameSpaceRefList,
|
|
&NameSpaceRefNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
MethodInvocationNode = NULL;
|
|
if (NameSpaceRefNode != NULL) {
|
|
// A matching method definition has been found.
|
|
// Create a method invocation node.
|
|
Status = AmlCreateMethodInvocationNode (
|
|
NameSpaceRefNode,
|
|
(AML_DATA_NODE *)DataNode,
|
|
&MethodInvocationNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
*OutNode = MethodInvocationNode;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Call the appropriate function to parse the AML construct in the stream.
|
|
|
|
The ExpectedFormat parameter allows to choose the right parsing function.
|
|
An object node or a data node is created according to format.
|
|
|
|
@param [in] ParentNode Node to which the parsed AML construct
|
|
will be attached.
|
|
@param [in] ExpectedFormat Format of the AML construct to parse.
|
|
@param [in, out] FStream Forward stream containing the AML
|
|
bytecode to parse.
|
|
The stream must not be at its end.
|
|
@param [in, out] NameSpaceRefList List of namespace reference nodes.
|
|
@param [out] OutNode Pointer holding the node created from the
|
|
parsed AML bytecode.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlParseArgument (
|
|
IN CONST AML_NODE_HEADER *ParentNode,
|
|
IN AML_PARSE_FORMAT ExpectedFormat,
|
|
IN OUT AML_STREAM *FStream,
|
|
IN OUT LIST_ENTRY *NameSpaceRefList,
|
|
OUT AML_NODE_HEADER **OutNode
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
AML_PARSE_FUNCTION ParsingFunction;
|
|
AML_DATA_NODE *DataNode;
|
|
AML_OBJECT_NODE *MethodInvocationNode;
|
|
|
|
if ((!IS_AML_ROOT_NODE (ParentNode) &&
|
|
!IS_AML_OBJECT_NODE (ParentNode)) ||
|
|
(ExpectedFormat >= EAmlParseFormatMax) ||
|
|
!IS_STREAM (FStream) ||
|
|
IS_END_OF_STREAM (FStream) ||
|
|
!IS_STREAM_FORWARD (FStream) ||
|
|
(NameSpaceRefList == NULL) ||
|
|
(OutNode == NULL))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ParsingFunction = mParseType[ExpectedFormat];
|
|
if (ParsingFunction == NULL) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Note: The ParsingFunction moves the stream forward as it
|
|
// consumes the AML bytecode
|
|
Status = ParsingFunction (
|
|
ParentNode,
|
|
ExpectedFormat,
|
|
FStream,
|
|
OutNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// Check whether the parsed argument is a NameString when an object
|
|
// is expected. In such case, it could be a method invocation.
|
|
DataNode = (AML_DATA_NODE *)*OutNode;
|
|
if (IS_AML_DATA_NODE (DataNode) &&
|
|
(DataNode->DataType == EAmlNodeDataTypeNameString) &&
|
|
(ExpectedFormat == EAmlObject))
|
|
{
|
|
Status = AmlCheckAndParseMethodInvoc (
|
|
ParentNode,
|
|
(AML_DATA_NODE *)*OutNode,
|
|
NameSpaceRefList,
|
|
&MethodInvocationNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// A method invocation node has been created and the DataNode containing
|
|
// the NameString has been attached to the MethodInvocationNode.
|
|
// Replace the OutNode with the MethodInvocationNode.
|
|
if (MethodInvocationNode != NULL) {
|
|
*OutNode = (AML_NODE_HEADER *)MethodInvocationNode;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Parse the Bytelist in the stream.
|
|
According to the content of the stream, create data node(s)
|
|
and add them to the variable list of arguments.
|
|
The byte list may be a list of resource data element or a simple byte list.
|
|
|
|
@param [in] BufferNode Object node having a byte list.
|
|
@param [in, out] FStream Forward stream containing the AML bytecode
|
|
to parse.
|
|
The stream must not be at its end.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlParseByteList (
|
|
IN AML_OBJECT_NODE *BufferNode,
|
|
IN OUT AML_STREAM *FStream
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
AML_NODE_HEADER *NewNode;
|
|
CONST UINT8 *Buffer;
|
|
UINT32 BufferSize;
|
|
|
|
// Check whether the node is an Object Node and has byte list.
|
|
if (!AmlNodeHasAttribute (BufferNode, AML_HAS_BYTE_LIST) ||
|
|
!IS_STREAM (FStream) ||
|
|
IS_END_OF_STREAM (FStream) ||
|
|
!IS_STREAM_FORWARD (FStream))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// The buffer contains a list of resource data elements.
|
|
if (AmlRdIsResourceDataBuffer (FStream)) {
|
|
// Parse the resource data elements and add them as data nodes.
|
|
// AmlParseResourceData() moves the stream forward.
|
|
Status = AmlParseResourceData (BufferNode, FStream);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
}
|
|
} else {
|
|
// The buffer doesn't contain a list of resource data elements.
|
|
// Create a single node holding the whole buffer data.
|
|
|
|
// CreateDataNode checks the Buffer and BufferSize values.
|
|
Buffer = (CONST UINT8 *)AmlStreamGetCurrPos (FStream);
|
|
BufferSize = AmlStreamGetFreeSpace (FStream);
|
|
|
|
Status = AmlCreateDataNode (
|
|
EAmlNodeDataTypeRaw,
|
|
Buffer,
|
|
BufferSize,
|
|
(AML_DATA_NODE **)&NewNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
Status = AmlVarListAddTailInternal (
|
|
(AML_NODE_HEADER *)BufferNode,
|
|
NewNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
AmlDeleteTree (NewNode);
|
|
return Status;
|
|
}
|
|
|
|
AMLDBG_DUMP_RAW (Buffer, BufferSize);
|
|
|
|
// Move the stream forward as we have consumed the Buffer.
|
|
Status = AmlStreamProgress (FStream, BufferSize);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Parse the list of fixed arguments of the input ObjectNode.
|
|
|
|
For each argument, create a node and add it to the fixed argument list
|
|
of the Node.
|
|
If a fixed argument has children, parse them.
|
|
|
|
@param [in] ObjectNode Object node to parse the fixed arguments
|
|
from.
|
|
@param [in] FStream Forward stream containing the AML
|
|
bytecode to parse.
|
|
The stream must not be at its end.
|
|
@param [in] NameSpaceRefList List of namespace reference nodes.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlParseFixedArguments (
|
|
IN AML_OBJECT_NODE *ObjectNode,
|
|
IN AML_STREAM *FStream,
|
|
IN LIST_ENTRY *NameSpaceRefList
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
AML_NODE_HEADER *FixedArgNode;
|
|
AML_STREAM FixedArgFStream;
|
|
|
|
EAML_PARSE_INDEX TermIndex;
|
|
EAML_PARSE_INDEX MaxIndex;
|
|
CONST AML_PARSE_FORMAT *Format;
|
|
|
|
// Fixed arguments of method invocations node are handled differently.
|
|
if (!IS_AML_OBJECT_NODE (ObjectNode) ||
|
|
AmlNodeCompareOpCode (ObjectNode, AML_METHOD_INVOC_OP, 0) ||
|
|
!IS_STREAM (FStream) ||
|
|
IS_END_OF_STREAM (FStream) ||
|
|
!IS_STREAM_FORWARD (FStream) ||
|
|
(NameSpaceRefList == NULL))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
TermIndex = EAmlParseIndexTerm0;
|
|
MaxIndex = (EAML_PARSE_INDEX)AmlGetFixedArgumentCount (
|
|
(AML_OBJECT_NODE *)ObjectNode
|
|
);
|
|
if ((ObjectNode->AmlByteEncoding != NULL) &&
|
|
(ObjectNode->AmlByteEncoding->Format != NULL))
|
|
{
|
|
Format = ObjectNode->AmlByteEncoding->Format;
|
|
} else {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Parse all the FixedArgs.
|
|
while ((TermIndex < MaxIndex) &&
|
|
!IS_END_OF_STREAM (FStream) &&
|
|
(Format[TermIndex] != EAmlNone))
|
|
{
|
|
// Initialize a FixedArgStream to parse the current fixed argument.
|
|
Status = AmlStreamInitSubStream (FStream, &FixedArgFStream);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// Parse the current fixed argument.
|
|
Status = AmlParseArgument (
|
|
(CONST AML_NODE_HEADER *)ObjectNode,
|
|
Format[TermIndex],
|
|
&FixedArgFStream,
|
|
NameSpaceRefList,
|
|
&FixedArgNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// Add the fixed argument to the parent node's fixed argument list.
|
|
// FixedArgNode can be an object or data node.
|
|
Status = AmlSetFixedArgument (
|
|
(AML_OBJECT_NODE *)ObjectNode,
|
|
TermIndex,
|
|
FixedArgNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
// Delete the sub-tree if the insertion failed.
|
|
// Otherwise its reference will be lost.
|
|
// Use DeleteTree because if the argument was a method invocation,
|
|
// multiple nodes have been created.
|
|
AmlDeleteTree (FixedArgNode);
|
|
return Status;
|
|
}
|
|
|
|
// Parse the AML bytecode of the FixedArgNode if this is an object node.
|
|
if (IS_AML_OBJECT_NODE (FixedArgNode) &&
|
|
!IS_END_OF_STREAM (&FixedArgFStream))
|
|
{
|
|
Status = AmlParseStream (
|
|
FixedArgNode,
|
|
&FixedArgFStream,
|
|
NameSpaceRefList
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
// Move the stream forward as we have consumed the sub-stream.
|
|
Status = AmlStreamProgress (
|
|
FStream,
|
|
AmlStreamGetIndex (&FixedArgFStream)
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
TermIndex++;
|
|
} // while
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Parse the variable list of arguments of the input ObjectNode.
|
|
|
|
For each variable argument, create a node and add it to the variable list of
|
|
arguments of the Node.
|
|
If a variable argument has children, parse them recursively.
|
|
|
|
The arguments of method invocation nodes are added to the variable list of
|
|
arguments of the method invocation node. It is necessary to first get
|
|
the number of arguments to parse for this kind of node. A method invocation
|
|
can have at most 7 fixed arguments.
|
|
|
|
@param [in] Node Node to parse the variable arguments
|
|
from.
|
|
@param [in] FStream Forward stream containing the AML
|
|
bytecode to parse.
|
|
The stream must not be at its end.
|
|
@param [in] NameSpaceRefList List of namespace reference nodes.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlParseVariableArguments (
|
|
IN AML_NODE_HEADER *Node,
|
|
IN AML_STREAM *FStream,
|
|
IN LIST_ENTRY *NameSpaceRefList
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
BOOLEAN IsMethodInvocation;
|
|
UINT8 MethodInvocationArgCount;
|
|
|
|
AML_NODE_HEADER *VarArgNode;
|
|
AML_STREAM VarArgFStream;
|
|
|
|
if ((!AmlNodeHasAttribute (
|
|
(CONST AML_OBJECT_NODE *)Node,
|
|
AML_HAS_CHILD_OBJ
|
|
) &&
|
|
!IS_AML_ROOT_NODE (Node)) ||
|
|
!IS_STREAM (FStream) ||
|
|
IS_END_OF_STREAM (FStream) ||
|
|
!IS_STREAM_FORWARD (FStream) ||
|
|
(NameSpaceRefList == NULL))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = AmlGetMethodInvocationArgCount (
|
|
(CONST AML_OBJECT_NODE *)Node,
|
|
&IsMethodInvocation,
|
|
&MethodInvocationArgCount
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// Parse variable arguments while the Stream is not empty.
|
|
while (!IS_END_OF_STREAM (FStream)) {
|
|
// If the number of variable arguments are counted, decrement the counter.
|
|
if ((IsMethodInvocation) && (MethodInvocationArgCount-- == 0)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
// Initialize a VarArgStream to parse the current variable argument.
|
|
Status = AmlStreamInitSubStream (FStream, &VarArgFStream);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// Parse the current variable argument.
|
|
Status = AmlParseArgument (
|
|
Node,
|
|
EAmlObject,
|
|
&VarArgFStream,
|
|
NameSpaceRefList,
|
|
&VarArgNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// Add the variable argument to its parent variable list of arguments.
|
|
// VarArgNode can be an object or data node.
|
|
Status = AmlVarListAddTailInternal (
|
|
(AML_NODE_HEADER *)Node,
|
|
VarArgNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
// Delete the sub-tree if the insertion failed.
|
|
// Otherwise its reference will be lost.
|
|
// Use DeleteTree because if the argument was a method invocation,
|
|
// multiple nodes have been created.
|
|
AmlDeleteTree (VarArgNode);
|
|
return Status;
|
|
}
|
|
|
|
// Parse the AML bytecode of the VarArgNode if this is an object node.
|
|
if (IS_AML_OBJECT_NODE (VarArgNode) &&
|
|
(!IS_END_OF_STREAM (&VarArgFStream)))
|
|
{
|
|
Status = AmlParseStream (VarArgNode, &VarArgFStream, NameSpaceRefList);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
// Move the stream forward as we have consumed the sub-stream.
|
|
Status = AmlStreamProgress (
|
|
FStream,
|
|
AmlStreamGetIndex (&VarArgFStream)
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
} // while
|
|
|
|
// If the number of variable arguments are counted, check all the
|
|
// MethodInvocationArgCount have been parsed.
|
|
if (IsMethodInvocation && (MethodInvocationArgCount != 0)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Parse the AML stream and populate the root node.
|
|
|
|
@param [in] RootNode RootNode to which the children are
|
|
added.
|
|
@param [in, out] FStream Forward stream containing the AML
|
|
bytecode to parse.
|
|
The stream must not be at its end.
|
|
@param [in, out] NameSpaceRefList List of namespace reference nodes.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlPopulateRootNode (
|
|
IN AML_ROOT_NODE *RootNode,
|
|
IN OUT AML_STREAM *FStream,
|
|
IN OUT LIST_ENTRY *NameSpaceRefList
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
if (!IS_AML_ROOT_NODE (RootNode) ||
|
|
!IS_STREAM (FStream) ||
|
|
IS_END_OF_STREAM (FStream) ||
|
|
!IS_STREAM_FORWARD (FStream) ||
|
|
(NameSpaceRefList == NULL))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// A Root Node only has variable arguments.
|
|
Status = AmlParseVariableArguments (
|
|
(AML_NODE_HEADER *)RootNode,
|
|
FStream,
|
|
NameSpaceRefList
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Parse the AML stream an populate the object node.
|
|
|
|
@param [in] ObjectNode ObjectNode to which the children are
|
|
added.
|
|
@param [in, out] FStream Forward stream containing the AML
|
|
bytecode to parse.
|
|
The stream must not be at its end.
|
|
@param [in, out] NameSpaceRefList List of namespace reference nodes.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlPopulateObjectNode (
|
|
IN AML_OBJECT_NODE *ObjectNode,
|
|
IN OUT AML_STREAM *FStream,
|
|
IN OUT LIST_ENTRY *NameSpaceRefList
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
if (!IS_AML_OBJECT_NODE (ObjectNode) ||
|
|
!IS_STREAM (FStream) ||
|
|
IS_END_OF_STREAM (FStream) ||
|
|
!IS_STREAM_FORWARD (FStream) ||
|
|
(NameSpaceRefList == NULL))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
// Don't parse the fixed arguments of method invocation nodes.
|
|
// The AML encoding for method invocations in the ACPI specification 6.3 is:
|
|
// MethodInvocation := NameString TermArgList
|
|
// Since the AML specification does not define an OpCode for method
|
|
// invocation, this AML parser defines a pseudo opcode and redefines the
|
|
// grammar for simplicity as:
|
|
// MethodInvocation := MethodInvocationOp NameString ArgumentCount TermArgList
|
|
// ArgumentCount := ByteData
|
|
// Due to this difference, the MethodInvocationOp and the fixed argument
|
|
// i.e. ArgumentCount is not available in the AML stream and need to be
|
|
// handled differently.
|
|
if (!AmlNodeCompareOpCode (ObjectNode, AML_METHOD_INVOC_OP, 0)) {
|
|
// Parse the fixed list of arguments.
|
|
Status = AmlParseFixedArguments (
|
|
ObjectNode,
|
|
FStream,
|
|
NameSpaceRefList
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
// Save the association [node reference/pathname] in the NameSpaceRefList.
|
|
// This allows to identify method invocations from other namespace
|
|
// paths. Method invocation need to be parsed differently.
|
|
if (AmlNodeHasAttribute (
|
|
(CONST AML_OBJECT_NODE *)ObjectNode,
|
|
AML_IN_NAMESPACE
|
|
))
|
|
{
|
|
Status = AmlAddNameSpaceReference (
|
|
(CONST AML_OBJECT_NODE *)ObjectNode,
|
|
NameSpaceRefList
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
if (!IS_END_OF_STREAM (FStream)) {
|
|
// Parse the variable list of arguments if present.
|
|
if (AmlNodeHasAttribute (ObjectNode, AML_HAS_CHILD_OBJ)) {
|
|
Status = AmlParseVariableArguments (
|
|
(AML_NODE_HEADER *)ObjectNode,
|
|
FStream,
|
|
NameSpaceRefList
|
|
);
|
|
} else if (AmlNodeHasAttribute (ObjectNode, AML_HAS_BYTE_LIST)) {
|
|
// Parse the byte list if present.
|
|
Status = AmlParseByteList (
|
|
ObjectNode,
|
|
FStream
|
|
);
|
|
} else if (AmlNodeHasAttribute (ObjectNode, AML_HAS_FIELD_LIST)) {
|
|
// Parse the field list if present.
|
|
Status = AmlParseFieldList (
|
|
ObjectNode,
|
|
FStream,
|
|
NameSpaceRefList
|
|
);
|
|
}
|
|
|
|
// Check status and assert
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Invoke the appropriate parsing functions based on the Node type.
|
|
|
|
@param [in] Node Node from which the children are parsed.
|
|
Must be a root node or an object node.
|
|
@param [in] FStream Forward stream containing the AML
|
|
bytecode to parse.
|
|
The stream must not be at its end.
|
|
@param [in] NameSpaceRefList List of namespace reference nodes.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlParseStream (
|
|
IN AML_NODE_HEADER *Node,
|
|
IN AML_STREAM *FStream,
|
|
IN LIST_ENTRY *NameSpaceRefList
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
if (IS_AML_ROOT_NODE (Node)) {
|
|
Status = AmlPopulateRootNode (
|
|
(AML_ROOT_NODE *)Node,
|
|
FStream,
|
|
NameSpaceRefList
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
}
|
|
} else if (IS_AML_OBJECT_NODE (Node)) {
|
|
Status = AmlPopulateObjectNode (
|
|
(AML_OBJECT_NODE *)Node,
|
|
FStream,
|
|
NameSpaceRefList
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
}
|
|
} else {
|
|
// Data node or other.
|
|
ASSERT (0);
|
|
Status = EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Parse the definition block.
|
|
|
|
This function parses the whole AML blob. It starts with the ACPI DSDT/SSDT
|
|
header and then parses the AML bytestream.
|
|
A tree structure is returned via the RootPtr.
|
|
The tree must be deleted with the AmlDeleteTree function.
|
|
|
|
@param [in] DefinitionBlock Pointer to the definition block.
|
|
@param [out] RootPtr Pointer to the root node of the tree.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlParseDefinitionBlock (
|
|
IN CONST EFI_ACPI_DESCRIPTION_HEADER *DefinitionBlock,
|
|
OUT AML_ROOT_NODE **RootPtr
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_STATUS Status1;
|
|
AML_STREAM Stream;
|
|
AML_ROOT_NODE *Root;
|
|
|
|
LIST_ENTRY NameSpaceRefList;
|
|
|
|
UINT8 *Buffer;
|
|
UINT32 MaxBufferSize;
|
|
|
|
if ((DefinitionBlock == NULL) ||
|
|
(RootPtr == NULL))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Buffer = (UINT8 *)DefinitionBlock + sizeof (EFI_ACPI_DESCRIPTION_HEADER);
|
|
if (DefinitionBlock->Length < sizeof (EFI_ACPI_DESCRIPTION_HEADER)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
MaxBufferSize = DefinitionBlock->Length -
|
|
(UINT32)sizeof (EFI_ACPI_DESCRIPTION_HEADER);
|
|
|
|
// Create a root node.
|
|
Status = AmlCreateRootNode (
|
|
(EFI_ACPI_DESCRIPTION_HEADER *)DefinitionBlock,
|
|
&Root
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
*RootPtr = Root;
|
|
|
|
if (MaxBufferSize == 0) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
// Initialize a stream to parse the AML bytecode.
|
|
Status = AmlStreamInit (
|
|
&Stream,
|
|
Buffer,
|
|
MaxBufferSize,
|
|
EAmlStreamDirectionForward
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto error_handler;
|
|
}
|
|
|
|
// Initialize the NameSpaceRefList, holding references to nodes declaring
|
|
// a name in the AML namespace.
|
|
InitializeListHead (&NameSpaceRefList);
|
|
|
|
// Parse the whole AML blob.
|
|
Status = AmlParseStream (
|
|
(AML_NODE_HEADER *)Root,
|
|
&Stream,
|
|
&NameSpaceRefList
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto error_handler;
|
|
}
|
|
|
|
// Check the whole AML blob has been parsed.
|
|
if (!IS_END_OF_STREAM (&Stream)) {
|
|
ASSERT (0);
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto error_handler;
|
|
}
|
|
|
|
// Print the list of NameSpace reference nodes.
|
|
// AmlDbgPrintNameSpaceRefList (&NameSpaceRefList);
|
|
|
|
// Delete the NameSpaceRefList
|
|
goto exit_handler;
|
|
|
|
error_handler:
|
|
if (Root != NULL) {
|
|
AmlDeleteTree ((AML_NODE_HEADER *)Root);
|
|
}
|
|
|
|
exit_handler:
|
|
Status1 = AmlDeleteNameSpaceRefList (&NameSpaceRefList);
|
|
if (EFI_ERROR (Status1)) {
|
|
ASSERT (0);
|
|
if (!EFI_ERROR (Status)) {
|
|
return Status1;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|