]> git.proxmox.com Git - mirror_edk2.git/commitdiff
DynamicTablesPkg: AML Parser
authorPierre Gondois <pierre.gondois@arm.com>
Wed, 5 Aug 2020 09:40:22 +0000 (10:40 +0100)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Thu, 13 Aug 2020 18:00:06 +0000 (18:00 +0000)
Both ASL and AML are declarative language. The ASL code
is compiled to AML bytecode. The AML bytecode is processed
by the ACPI AML interpreter that runs as part of an OS.
AML has a complex encoding making dynamic generation of
Definition Block tables difficult.

Dynamic AML generation involves techniques like AML Fixup
and AML Codegen, both requiring parsing of AML bytecode.

The AML parser is a module that parses an AML byte stream
and represents it as an AML tree. Representing the AML
bytecode as an AML tree is key to reducing the complexity
and enabling Dynamic AML generation.

In an AML Tree each AML statement (that also corresponds
to an ASL statement) is represented as an 'Object Node'.
Each Object Node has an OpCode and up to 6 Fixed Arguments
followed by a list of Variable Arguments.

(ObjectNode)
    \
    |- [0][1][2][3][4][5]             # Fixed Arguments
    |- {(VarArg1)->(VarArg2)->...N}   # Variable Arguments

A Fixed Argument or Variable Argument can be either an
Object Node or a Data Node.

A 'Data Node' consists of a data buffer.

A 'Root Node' is a special type of Object Node that does
not have an Opcode or Fixed Arguments. It only has a list
of Variable Arguments. The Root Node is at the top of the
AML tree and contains the Definition Block Header.

The AML parser uses the 'AML Encoding' to parse an AML byte
stream and represents it as an AML Tree. Representing in the
form of an AML tree simplifies modification, addition and
removal of the tree nodes. The modified tree can then be
serialised to a buffer representing a Definition Block table.

Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
Reviewed-by: Alexei Fedorov <Alexei.Fedorov@arm.com>
DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.c [new file with mode: 0644]
DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.h [new file with mode: 0644]

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