]> git.proxmox.com Git - mirror_edk2.git/commitdiff
DynamicTablesPkg: AML tree traversal
authorPierre Gondois <pierre.gondois@arm.com>
Mon, 3 Aug 2020 15:30:06 +0000 (16:30 +0100)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Thu, 13 Aug 2020 18:00:06 +0000 (18:00 +0000)
The AML tree traversal provides interfaces to traverse the
nodes in the AML tree.

It provides interfaces to traverse the AML tree in the
following order:

  - Traverse sibling nodes.

    (Node)        /-i           # Child of fixed argument b
        \        /
         |- [a][b][c][d]        # Fixed Arguments
         |- {(e)->(f)->(g)}     # Variable Arguments
               \
                \-h             # Child of variable argument e

    Traversal Order:
      - AmlGetNextSibling() : a, b, c, d, e, f, g, NULL
      - AmlGetPreviousSibling(): g, f, e, d, c, b, a, NULL

  - Iterate depth-first path (follow AML byte stream).
    (Node)        /-i           # Child of fixed argument b
        \        /
         |- [a][b][c][d]        # Fixed Arguments
         |- {(e)->(f)->(g)}     # Variable Arguments
               \
                \-h             # Child of variable argument e

    Traversal Order:
      - AmlGetNextNode(): a, b, i, c, d, e, h, f, g, NULL
      - AmlGetPreviousNode() g, f, h, e, d, c, i, b, a, NULL
        Note: The branch i and h will be traversed if it has
              any children.

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/Tree/AmlTreeTraversal.c [new file with mode: 0644]
DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlTreeTraversal.h [new file with mode: 0644]

diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlTreeTraversal.c b/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlTreeTraversal.c
new file mode 100644 (file)
index 0000000..9d0c794
--- /dev/null
@@ -0,0 +1,548 @@
+/** @file\r
+  AML Tree Traversal.\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 <Tree/AmlTreeTraversal.h>\r
+\r
+#include <AmlCoreInterface.h>\r
+#include <Tree/AmlTree.h>\r
+\r
+/** Get the sibling node among the nodes being in\r
+    the same variable argument list.\r
+\r
+  (ParentNode)  /-i                 # Child of fixed argument b\r
+      \        /\r
+       |- [a][b][c][d]              # Fixed Arguments\r
+       |- {(VarArgNode)->(f)->(g)}  # Variable Arguments\r
+             \\r
+              \-h                   # Child of variable argument e\r
+\r
+  Node must be in a variable list of arguments.\r
+  Traversal Order: VarArgNode, f, g, NULL\r
+\r
+  @ingroup CoreNavigationApis\r
+\r
+  @param  [in]  VarArgNode  Pointer to a node.\r
+                            Must be in a variable list of arguments.\r
+\r
+  @return The next node after VarArgNode in the variable list of arguments.\r
+          Return NULL if\r
+          - VarArgNode is the last node of the list, or\r
+          - VarArgNode is not part of a variable list of arguments.\r
+**/\r
+AML_NODE_HEADER *\r
+EFIAPI\r
+AmlGetSiblingVariableArgument (\r
+  IN  AML_NODE_HEADER   * VarArgNode\r
+  )\r
+{\r
+  EAML_PARSE_INDEX    Index;\r
+  AML_NODE_HEADER   * ParentNode;\r
+\r
+  // VarArgNode must be an object node or a data node,\r
+  // and be in a variable list of arguments.\r
+  if ((!IS_AML_OBJECT_NODE (VarArgNode) &&\r
+       !IS_AML_DATA_NODE (VarArgNode))  ||\r
+      AmlIsNodeFixedArgument (VarArgNode, &Index)) {\r
+    ASSERT (0);\r
+    return NULL;\r
+  }\r
+\r
+  ParentNode = AmlGetParent (VarArgNode);\r
+  if (!IS_AML_NODE_VALID (ParentNode)) {\r
+    ASSERT (0);\r
+    return NULL;\r
+  }\r
+\r
+  return AmlGetNextVariableArgument (ParentNode, VarArgNode);\r
+}\r
+\r
+/** Get the next variable argument.\r
+\r
+  (Node)        /-i           # Child of fixed argument b\r
+      \        /\r
+       |- [a][b][c][d]        # Fixed Arguments\r
+       |- {(e)->(f)->(g)}     # Variable Arguments\r
+             \\r
+              \-h             # Child of variable argument e\r
+\r
+  Traversal Order: e, f, g, NULL\r
+\r
+  @param  [in]  Node        Pointer to a Root node or Object Node.\r
+  @param  [in]  CurrVarArg  Pointer to the Current Variable Argument.\r
+\r
+  @return The node after the CurrVarArg in the variable list of arguments.\r
+          If CurrVarArg is NULL, return the first node of the\r
+          variable argument list.\r
+          Return NULL if\r
+          - CurrVarArg is the last node of the list, or\r
+          - Node does not have a variable list of arguments.\r
+**/\r
+AML_NODE_HEADER *\r
+EFIAPI\r
+AmlGetNextVariableArgument (\r
+  IN  AML_NODE_HEADER  * Node,\r
+  IN  AML_NODE_HEADER  * CurrVarArg\r
+  )\r
+{\r
+  CONST LIST_ENTRY       * StartLink;\r
+  CONST LIST_ENTRY       * NextLink;\r
+\r
+  // Node must be a RootNode or an Object Node\r
+  // and the CurrVarArg must not be a Root Node.\r
+  if ((!IS_AML_ROOT_NODE (Node)           &&\r
+       !IS_AML_OBJECT_NODE (Node))        ||\r
+      ((CurrVarArg != NULL)               &&\r
+       (!IS_AML_OBJECT_NODE (CurrVarArg)  &&\r
+        !IS_AML_DATA_NODE (CurrVarArg)))) {\r
+    ASSERT (0);\r
+    return NULL;\r
+  }\r
+\r
+  StartLink = AmlNodeGetVariableArgList (Node);\r
+  if (StartLink == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  // Get the first child of the variable list of arguments.\r
+  if (CurrVarArg == NULL) {\r
+    NextLink = StartLink->ForwardLink;\r
+    if (NextLink != StartLink) {\r
+      return (AML_NODE_HEADER*)NextLink;\r
+    }\r
+    // List is empty.\r
+    return NULL;\r
+  }\r
+\r
+  // Check if CurrVarArg is in the VariableArgument List.\r
+  if (!IsNodeInList (StartLink, &CurrVarArg->Link)) {\r
+    ASSERT (0);\r
+    return NULL;\r
+  }\r
+\r
+  // Get the node following the CurrVarArg.\r
+  NextLink = CurrVarArg->Link.ForwardLink;\r
+  if (NextLink != StartLink) {\r
+    return (AML_NODE_HEADER*)NextLink;\r
+  }\r
+\r
+  // End of the list has been reached.\r
+  return NULL;\r
+}\r
+\r
+/** Get the previous variable argument.\r
+\r
+  (Node)        /-i           # Child of fixed argument b\r
+      \        /\r
+       |- [a][b][c][d]        # Fixed Arguments\r
+       |- {(e)->(f)->(g)}     # Variable Arguments\r
+             \\r
+              \-h             # Child of variable argument e\r
+\r
+  Traversal Order: g, f, e, NULL\r
+\r
+  @param  [in]  Node        Pointer to a root node or an object node.\r
+  @param  [in]  CurrVarArg  Pointer to the Current Variable Argument.\r
+\r
+  @return The node before the CurrVarArg in the variable list of\r
+          arguments.\r
+          If CurrVarArg is NULL, return the last node of the\r
+          variable list of arguments.\r
+          Return NULL if:\r
+          - CurrVarArg is the first node of the list, or\r
+          - Node doesn't have a variable list of arguments.\r
+**/\r
+AML_NODE_HEADER *\r
+EFIAPI\r
+AmlGetPreviousVariableArgument (\r
+  IN  AML_NODE_HEADER  * Node,\r
+  IN  AML_NODE_HEADER  * CurrVarArg\r
+  )\r
+{\r
+  CONST LIST_ENTRY       * StartLink;\r
+  CONST LIST_ENTRY       * PreviousLink;\r
+\r
+  // Node must be a RootNode or an Object Node\r
+  // and the CurrVarArg must not be a Root Node.\r
+  if ((!IS_AML_ROOT_NODE (Node)           &&\r
+       !IS_AML_OBJECT_NODE (Node))        ||\r
+      ((CurrVarArg != NULL)               &&\r
+       (!IS_AML_OBJECT_NODE (CurrVarArg)  &&\r
+        !IS_AML_DATA_NODE (CurrVarArg)))) {\r
+    ASSERT (0);\r
+    return NULL;\r
+  }\r
+\r
+  StartLink = AmlNodeGetVariableArgList (Node);\r
+  if (StartLink == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  // Get the last child of the variable list of arguments.\r
+  if (CurrVarArg == NULL) {\r
+    PreviousLink = StartLink->BackLink;\r
+    if (PreviousLink != StartLink) {\r
+      return (AML_NODE_HEADER*)PreviousLink;\r
+    }\r
+    // List is empty.\r
+    return NULL;\r
+  }\r
+\r
+  // Check if CurrVarArg is in the VariableArgument List.\r
+  if (!IsNodeInList (StartLink, &CurrVarArg->Link)) {\r
+    ASSERT (0);\r
+    return NULL;\r
+  }\r
+\r
+  // Get the node before the CurrVarArg.\r
+  PreviousLink = CurrVarArg->Link.BackLink;\r
+  if (PreviousLink != StartLink) {\r
+    return (AML_NODE_HEADER*)PreviousLink;\r
+  }\r
+\r
+  // We have reached the beginning of the list.\r
+  return NULL;\r
+}\r
+\r
+/** Get the next sibling node among the children of the input Node.\r
+\r
+  This function traverses the FixedArguments followed by the\r
+  VariableArguments at the same level in the hierarchy.\r
+\r
+  Fixed arguments are before variable arguments.\r
+\r
+  (Node)        /-i           # Child of fixed argument b\r
+      \        /\r
+       |- [a][b][c][d]        # Fixed Arguments\r
+       |- {(e)->(f)->(g)}     # Variable Arguments\r
+             \\r
+              \-h             # Child of variable argument e\r
+\r
+  Traversal Order: a, b, c, d, e, f, g, NULL\r
+\r
+\r
+  @param  [in]  Node        Pointer to a root node or an object node.\r
+  @param  [in]  ChildNode   Get the node after the ChildNode.\r
+\r
+  @return The node after the ChildNode among the children of the input Node.\r
+           - If ChildNode is NULL, return the first available node among\r
+             the fixed argument list then variable list of arguments;\r
+           - If ChildNode is the last node of the fixed argument list,\r
+             return the first argument of the variable list of arguments;\r
+           - If ChildNode is the last node of the variable list of arguments,\r
+             return NULL.\r
+\r
+**/\r
+AML_NODE_HEADER *\r
+EFIAPI\r
+AmlGetNextSibling (\r
+  IN  CONST AML_NODE_HEADER   * Node,\r
+  IN  CONST AML_NODE_HEADER   * ChildNode\r
+  )\r
+{\r
+  EAML_PARSE_INDEX    Index;\r
+  AML_NODE_HEADER   * CandidateNode;\r
+\r
+  // Node must be a RootNode or an Object Node\r
+  // and the CurrVarArg must not be a Root Node.\r
+  if ((!IS_AML_ROOT_NODE (Node)           &&\r
+       !IS_AML_OBJECT_NODE (Node))        ||\r
+      ((ChildNode != NULL)                &&\r
+       (!IS_AML_OBJECT_NODE (ChildNode)   &&\r
+        !IS_AML_DATA_NODE (ChildNode)))) {\r
+    ASSERT (0);\r
+    return NULL;\r
+  }\r
+\r
+  if (IS_AML_OBJECT_NODE (Node)) {\r
+    if (ChildNode == NULL) {\r
+      // Get the fixed argument at index 0 of the ChildNode.\r
+      CandidateNode = AmlGetFixedArgument (\r
+                        (AML_OBJECT_NODE*)Node,\r
+                        EAmlParseIndexTerm0\r
+                        );\r
+      if (CandidateNode != NULL) {\r
+        return CandidateNode;\r
+      }\r
+    } else {\r
+      // (ChildNode != NULL)\r
+      if (AmlIsNodeFixedArgument (ChildNode, &Index)) {\r
+        // Increment index to point to the next fixed argument.\r
+        Index++;\r
+        // The node is part of the list of fixed arguments.\r
+        if (Index == (EAML_PARSE_INDEX)AmlGetFixedArgumentCount (\r
+                                         (AML_OBJECT_NODE*)Node)\r
+                                         ) {\r
+        // It is at the last argument of the fixed argument list.\r
+        // Get the first argument of the variable list of arguments.\r
+          ChildNode = NULL;\r
+        } else {\r
+          // Else return the next node in the list of fixed arguments.\r
+          return AmlGetFixedArgument ((AML_OBJECT_NODE*)Node, Index);\r
+        }\r
+      }\r
+    }\r
+  } // IS_AML_OBJECT_NODE (Node)\r
+\r
+  // Else, get the next node in the variable list of arguments.\r
+  return AmlGetNextVariableArgument (\r
+           (AML_NODE_HEADER*)Node,\r
+           (AML_NODE_HEADER*)ChildNode\r
+           );\r
+}\r
+\r
+/** Get the previous sibling node among the children of the input Node.\r
+\r
+  This function traverses the FixedArguments followed by the\r
+  VariableArguments at the same level in the hierarchy.\r
+\r
+  Fixed arguments are before variable arguments.\r
+\r
+  (Node)        /-i           # Child of fixed argument b\r
+      \        /\r
+       |- [a][b][c][d]        # Fixed Arguments\r
+       |- {(e)->(f)->(g)}     # Variable Arguments\r
+             \\r
+              \-h             # Child of variable argument e\r
+\r
+  Traversal Order: g, f, e, d, c, b, a, NULL\r
+\r
+  @param  [in]  Node        The node to get the fixed argument from.\r
+  @param  [in]  ChildNode   Get the node before the ChildNode.\r
+\r
+  @return The node before the ChildNode among the children of the input Node.\r
+           - If ChildNode is NULL, return the last available node among\r
+             the variable list of arguments then fixed argument list;\r
+           - If ChildNode is the first node of the variable list of arguments,\r
+             return the last argument of the fixed argument list;\r
+           - If ChildNode is the first node of the fixed argument list,\r
+             return NULL.\r
+**/\r
+AML_NODE_HEADER *\r
+EFIAPI\r
+AmlGetPreviousSibling (\r
+  IN  CONST  AML_NODE_HEADER  * Node,\r
+  IN  CONST  AML_NODE_HEADER  * ChildNode\r
+  )\r
+{\r
+  EAML_PARSE_INDEX    Index;\r
+  EAML_PARSE_INDEX    MaxIndex;\r
+\r
+  AML_NODE_HEADER   * CandidateNode;\r
+\r
+  // Node must be a Root Node or an Object Node\r
+  // and the ChildNode must not be a Root Node.\r
+  if ((!IS_AML_ROOT_NODE (Node)           &&\r
+       !IS_AML_OBJECT_NODE (Node))        ||\r
+      ((ChildNode != NULL)                &&\r
+       (!IS_AML_OBJECT_NODE (ChildNode)   &&\r
+        !IS_AML_DATA_NODE (ChildNode)))) {\r
+    ASSERT (0);\r
+    return NULL;\r
+  }\r
+\r
+  MaxIndex = (EAML_PARSE_INDEX)AmlGetFixedArgumentCount (\r
+                                 (AML_OBJECT_NODE*)Node\r
+                                 );\r
+\r
+  // Get the last variable argument if no ChildNode.\r
+  // Otherwise the fixed argument list is checked first.\r
+  if ((ChildNode != NULL)         &&\r
+      IS_AML_OBJECT_NODE (Node)   &&\r
+      (MaxIndex != EAmlParseIndexTerm0)) {\r
+    if (AmlIsNodeFixedArgument (ChildNode, &Index)) {\r
+      // The node is part of the list of fixed arguments.\r
+      if (Index == EAmlParseIndexTerm0) {\r
+        // The node is the first fixed argument, return NULL.\r
+        return NULL;\r
+      } else {\r
+        // Return the previous node in the fixed argument list.\r
+        return AmlGetFixedArgument (\r
+                 (AML_OBJECT_NODE*)Node,\r
+                 (EAML_PARSE_INDEX)(Index - 1)\r
+                 );\r
+      }\r
+    }\r
+  }\r
+\r
+  // ChildNode is in the variable list of arguments.\r
+  CandidateNode = AmlGetPreviousVariableArgument (\r
+                    (AML_NODE_HEADER*)Node,\r
+                    (AML_NODE_HEADER*)ChildNode\r
+                    );\r
+  if (CandidateNode != NULL) {\r
+    if (!IS_AML_NODE_VALID (CandidateNode)) {\r
+      ASSERT (0);\r
+      return NULL;\r
+    }\r
+    // A Node has been found\r
+    return CandidateNode;\r
+  } else if (MaxIndex != EAmlParseIndexTerm0) {\r
+    // ChildNode was the first node of the variable list of arguments.\r
+    return AmlGetFixedArgument (\r
+             (AML_OBJECT_NODE*)Node,\r
+             (EAML_PARSE_INDEX)(MaxIndex - 1)\r
+             );\r
+  } else {\r
+    // No fixed arguments or variable arguments.\r
+    return NULL;\r
+  }\r
+}\r
+\r
+/** Iterate through the nodes in the same order as the AML bytestream.\r
+\r
+  The iteration is similar to a depth-first path.\r
+\r
+  (Node)        /-i           # Child of fixed argument b\r
+      \        /\r
+       |- [a][b][c][d]        # Fixed Arguments\r
+       |- {(e)->(f)->(g)}     # Variable Arguments\r
+             \\r
+              \-h             # Child of variable argument e\r
+\r
+  Traversal Order: a, b, i, c, d, e, h, f, g, NULL\r
+  Note: The branch i and h will be traversed if it has any children.\r
+\r
+  @param  [in]  Node  Pointer to a node.\r
+\r
+  @return The next node in the AML bytestream order.\r
+          Return NULL if Node is the Node corresponding to the last\r
+          bytecode of the tree.\r
+**/\r
+AML_NODE_HEADER *\r
+EFIAPI\r
+AmlGetNextNode (\r
+  IN  CONST AML_NODE_HEADER   * Node\r
+  )\r
+{\r
+  AML_NODE_HEADER   * ParentNode;\r
+  AML_NODE_HEADER   * CandidateNode;\r
+\r
+  if (!IS_AML_NODE_VALID (Node)) {\r
+    ASSERT (0);\r
+    return NULL;\r
+  }\r
+\r
+  if (IS_AML_ROOT_NODE (Node) || IS_AML_OBJECT_NODE (Node)) {\r
+    // The node has children. Get the first child.\r
+    CandidateNode = AmlGetNextSibling (Node, NULL);\r
+    if (CandidateNode != NULL) {\r
+      if (!IS_AML_NODE_VALID (CandidateNode)) {\r
+        ASSERT (0);\r
+        return NULL;\r
+      }\r
+      // A Node has been found\r
+      return CandidateNode;\r
+    } else if (IS_AML_ROOT_NODE (Node)) {\r
+      // The node is the root node and it doesn't have children.\r
+      return NULL;\r
+    }\r
+  }\r
+\r
+  // We have traversed the current branch, go to the parent node\r
+  // and start traversing the next branch.\r
+  // Keep going up the tree until you reach the root node.\r
+  while (1) {\r
+    if (IS_AML_ROOT_NODE (Node)) {\r
+      // This is the last node of the tree.\r
+      return NULL;\r
+    }\r
+\r
+    ParentNode = AmlGetParent ((AML_NODE_HEADER*)Node);\r
+    if (!IS_AML_NODE_VALID (ParentNode)) {\r
+      ASSERT (0);\r
+      return NULL;\r
+    }\r
+\r
+    CandidateNode = AmlGetNextSibling (ParentNode, Node);\r
+    if (CandidateNode != NULL) {\r
+      if (!IS_AML_NODE_VALID (CandidateNode)) {\r
+        ASSERT (0);\r
+        return NULL;\r
+      }\r
+      // A Node has been found\r
+      return CandidateNode;\r
+    }\r
+\r
+    Node = ParentNode;\r
+  } // while\r
+\r
+  return NULL;\r
+}\r
+\r
+/** Iterate through the nodes in the reverse order of the AML bytestream.\r
+\r
+  The iteration is similar to a depth-first path,\r
+  but done in a reverse order.\r
+\r
+  (Node)        /-i           # Child of fixed argument b\r
+      \        /\r
+       |- [a][b][c][d]        # Fixed Arguments\r
+       |- {(e)->(f)->(g)}     # Variable Arguments\r
+             \\r
+              \-h             # Child of variable argument e\r
+\r
+  Traversal Order: g, f, h, e, d, c, i, b, a, NULL\r
+  Note: The branch i and h will be traversed if it has any children.\r
+\r
+  @param  [in]  Node  Pointer to a node.\r
+\r
+  @return The previous node in the AML bytestream order.\r
+          Return NULL if Node is the Node corresponding to the last\r
+          bytecode of the tree.\r
+**/\r
+AML_NODE_HEADER *\r
+EFIAPI\r
+AmlGetPreviousNode (\r
+  IN  CONST  AML_NODE_HEADER * Node\r
+  )\r
+{\r
+  AML_NODE_HEADER  * ParentNode;\r
+  AML_NODE_HEADER  * CandidateNode;\r
+  AML_NODE_HEADER  * PreviousNode;\r
+\r
+  if (!IS_AML_NODE_VALID (Node)) {\r
+    ASSERT (0);\r
+    return NULL;\r
+  }\r
+\r
+  while (1) {\r
+\r
+    if (IS_AML_ROOT_NODE (Node)) {\r
+      // This is the root node.\r
+      return NULL;\r
+    }\r
+\r
+    ParentNode = AmlGetParent ((AML_NODE_HEADER*)Node);\r
+    CandidateNode = AmlGetPreviousSibling (ParentNode, Node);\r
+\r
+    if (CandidateNode == NULL) {\r
+      // Node is the first child of its parent.\r
+      return ParentNode;\r
+    } else if (IS_AML_DATA_NODE (CandidateNode)) {\r
+      // CandidateNode is a data node, thus it has no children.\r
+      return CandidateNode;\r
+    } else if (IS_AML_OBJECT_NODE (CandidateNode)) {\r
+      // Get the previous node in the list of children of ParentNode,\r
+      // then get the last child of this node.\r
+      // If this node has children, get its last child, etc.\r
+      while (1) {\r
+        PreviousNode = CandidateNode;\r
+        CandidateNode = AmlGetPreviousSibling (PreviousNode, NULL);\r
+        if (CandidateNode == NULL) {\r
+          return PreviousNode;\r
+        } else if (IS_AML_DATA_NODE (CandidateNode)) {\r
+          return CandidateNode;\r
+        }\r
+      } // while\r
+\r
+    } else {\r
+      ASSERT (0);\r
+      return NULL;\r
+    }\r
+  } // while\r
+}\r
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlTreeTraversal.h b/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlTreeTraversal.h
new file mode 100644 (file)
index 0000000..a4980b7
--- /dev/null
@@ -0,0 +1,138 @@
+/** @file\r
+  AML Tree Traversal.\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_TREE_TRAVERSAL_H_\r
+#define AML_TREE_TRAVERSAL_H_\r
+\r
+#include <AmlNodeDefines.h>\r
+\r
+/** Get the next sibling node among the children of the input Node.\r
+\r
+  This function traverses the FixedArguments followed by the\r
+  VariableArguments at the same level in the hierarchy.\r
+\r
+  Fixed arguments are before variable arguments.\r
+\r
+  (Node)        /-i           # Child of fixed argument b\r
+      \        /\r
+       |- [a][b][c][d]        # Fixed Arguments\r
+       |- {(e)->(f)->(g)}     # Variable Arguments\r
+             \\r
+              \-h             # Child of variable argument e\r
+\r
+  Traversal Order: a, b, c, d, e, f, g, NULL\r
+\r
+\r
+  @param  [in]  Node        Pointer to a root node or an object node.\r
+  @param  [in]  ChildNode   Get the node after the ChildNode.\r
+\r
+  @return The node after the ChildNode among the children of the input Node.\r
+           - If ChildNode is NULL, return the first available node among\r
+             the fixed argument list then variable list of arguments;\r
+           - If ChildNode is the last node of the fixed argument list,\r
+             return the first argument of the variable list of arguments;\r
+           - If ChildNode is the last node of the variable list of arguments,\r
+             return NULL.\r
+\r
+**/\r
+AML_NODE_HEADER *\r
+EFIAPI\r
+AmlGetNextSibling (\r
+  IN  CONST AML_NODE_HEADER   * Node,\r
+  IN  CONST AML_NODE_HEADER   * ChildNode\r
+  );\r
+\r
+/** Get the previous sibling node among the children of the input Node.\r
+\r
+  This function traverses the FixedArguments followed by the\r
+  VariableArguments at the same level in the hierarchy.\r
+\r
+  Fixed arguments are before variable arguments.\r
+\r
+  (Node)        /-i           # Child of fixed argument b\r
+      \        /\r
+       |- [a][b][c][d]        # Fixed Arguments\r
+       |- {(e)->(f)->(g)}     # Variable Arguments\r
+             \\r
+              \-h             # Child of variable argument e\r
+\r
+  Traversal Order: g, f, e, d, c, b, a, NULL\r
+\r
+  @param  [in]  Node        The node to get the fixed argument from.\r
+  @param  [in]  ChildNode   Get the node before the ChildNode.\r
+\r
+  @return The node before the ChildNode among the children of the input Node.\r
+           - If ChildNode is NULL, return the last available node among\r
+             the variable list of arguments then fixed argument list;\r
+           - If ChildNode is the first node of the variable list of arguments,\r
+             return the last argument of the fixed argument list;\r
+           - If ChildNode is the first node of the fixed argument list,\r
+             return NULL.\r
+**/\r
+AML_NODE_HEADER *\r
+EFIAPI\r
+AmlGetPreviousSibling (\r
+  IN  CONST  AML_NODE_HEADER  * Node,\r
+  IN  CONST  AML_NODE_HEADER  * ChildNode\r
+  );\r
+\r
+/** Iterate through the nodes in the same order as the AML bytestream.\r
+\r
+  The iteration is similar to a depth-first path.\r
+\r
+  (Node)        /-i           # Child of fixed argument b\r
+      \        /\r
+       |- [a][b][c][d]        # Fixed Arguments\r
+       |- {(e)->(f)->(g)}     # Variable Arguments\r
+             \\r
+              \-h             # Child of variable argument e\r
+\r
+  Traversal Order: a, b, i, c, d, e, h, f, g, NULL\r
+  Note: The branch i and h will be traversed if it has any children.\r
+\r
+  @param  [in]  Node  Pointer to a node.\r
+\r
+  @return The next node in the AML bytestream order.\r
+          Return NULL if Node is the Node corresponding to the last\r
+          bytecode of the tree.\r
+**/\r
+AML_NODE_HEADER *\r
+EFIAPI\r
+AmlGetNextNode (\r
+  IN  CONST AML_NODE_HEADER   * Node\r
+  );\r
+\r
+/** Iterate through the nodes in the reverse order of the AML bytestream.\r
+\r
+  The iteration is similar to a depth-first path,\r
+  but done in a reverse order.\r
+\r
+  (Node)        /-i           # Child of fixed argument b\r
+      \        /\r
+       |- [a][b][c][d]        # Fixed Arguments\r
+       |- {(e)->(f)->(g)}     # Variable Arguments\r
+             \\r
+              \-h             # Child of variable argument e\r
+\r
+  Traversal Order: g, f, h, e, d, c, i, b, a, NULL\r
+  Note: The branch i and h will be traversed if it has any children.\r
+\r
+  @param  [in]  Node  Pointer to a node.\r
+\r
+  @return The previous node in the AML bytestream order.\r
+          Return NULL if Node is the Node corresponding to the last\r
+          bytecode of the tree.\r
+**/\r
+AML_NODE_HEADER *\r
+EFIAPI\r
+AmlGetPreviousNode (\r
+  IN  CONST  AML_NODE_HEADER * Node\r
+  );\r
+\r
+#endif // AML_TREE_TRAVERSAL_H_\r
+\r