summaryrefslogtreecommitdiffstats
path: root/DynamicTablesPkg
diff options
context:
space:
mode:
Diffstat (limited to 'DynamicTablesPkg')
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.c1448
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.h72
2 files changed, 1520 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.c b/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.c
new file mode 100644
index 0000000000..380ac9bbce
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.c
@@ -0,0 +1,1448 @@
+/** @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;
+ }
+
+ DumpRaw (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;
+ }
+
+ DumpRaw (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');
+
+ DumpRaw (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.
+ DumpRaw (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.
+ DumpRaw (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;
+ }
+
+ DumpRaw (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;
+ }
+
+ DumpRaw (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;
+}
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.h b/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.h
new file mode 100644
index 0000000000..096a9596e1
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.h
@@ -0,0 +1,72 @@
+/** @file
+ AML Parser.
+
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef AML_PARSER_H_
+#define AML_PARSER_H_
+
+#include <AmlNodeDefines.h>
+#include <Stream/AmlStream.h>
+
+/** 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
+ );
+
+/** 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
+ );
+
+#endif // AML_PARSER_H_