summaryrefslogtreecommitdiffstats
path: root/DynamicTablesPkg
diff options
context:
space:
mode:
authorPierre Gondois <pierre.gondois@arm.com>2020-08-03 16:30:06 +0100
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2020-08-13 18:00:06 +0000
commitf96dd8185d6ba79de57fc6c4f9ccc4d7482b1200 (patch)
tree16c72fc17938867baacfed77e8b564ab330a816b /DynamicTablesPkg
parent5764abda7c64bf0fe0061638e80cd195ebe45279 (diff)
downloadedk2-f96dd8185d6ba79de57fc6c4f9ccc4d7482b1200.tar.gz
edk2-f96dd8185d6ba79de57fc6c4f9ccc4d7482b1200.tar.bz2
edk2-f96dd8185d6ba79de57fc6c4f9ccc4d7482b1200.zip
DynamicTablesPkg: AML tree traversal
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>
Diffstat (limited to 'DynamicTablesPkg')
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlTreeTraversal.c548
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlTreeTraversal.h138
2 files changed, 686 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlTreeTraversal.c b/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlTreeTraversal.c
new file mode 100644
index 0000000000..9d0c794dbe
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlTreeTraversal.c
@@ -0,0 +1,548 @@
+/** @file
+ AML Tree Traversal.
+
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Tree/AmlTreeTraversal.h>
+
+#include <AmlCoreInterface.h>
+#include <Tree/AmlTree.h>
+
+/** Get the sibling node among the nodes being in
+ the same variable argument list.
+
+ (ParentNode) /-i # Child of fixed argument b
+ \ /
+ |- [a][b][c][d] # Fixed Arguments
+ |- {(VarArgNode)->(f)->(g)} # Variable Arguments
+ \
+ \-h # Child of variable argument e
+
+ Node must be in a variable list of arguments.
+ Traversal Order: VarArgNode, f, g, NULL
+
+ @ingroup CoreNavigationApis
+
+ @param [in] VarArgNode Pointer to a node.
+ Must be in a variable list of arguments.
+
+ @return The next node after VarArgNode in the variable list of arguments.
+ Return NULL if
+ - VarArgNode is the last node of the list, or
+ - VarArgNode is not part of a variable list of arguments.
+**/
+AML_NODE_HEADER *
+EFIAPI
+AmlGetSiblingVariableArgument (
+ IN AML_NODE_HEADER * VarArgNode
+ )
+{
+ EAML_PARSE_INDEX Index;
+ AML_NODE_HEADER * ParentNode;
+
+ // VarArgNode must be an object node or a data node,
+ // and be in a variable list of arguments.
+ if ((!IS_AML_OBJECT_NODE (VarArgNode) &&
+ !IS_AML_DATA_NODE (VarArgNode)) ||
+ AmlIsNodeFixedArgument (VarArgNode, &Index)) {
+ ASSERT (0);
+ return NULL;
+ }
+
+ ParentNode = AmlGetParent (VarArgNode);
+ if (!IS_AML_NODE_VALID (ParentNode)) {
+ ASSERT (0);
+ return NULL;
+ }
+
+ return AmlGetNextVariableArgument (ParentNode, VarArgNode);
+}
+
+/** Get the next variable argument.
+
+ (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: e, f, g, NULL
+
+ @param [in] Node Pointer to a Root node or Object Node.
+ @param [in] CurrVarArg Pointer to the Current Variable Argument.
+
+ @return The node after the CurrVarArg in the variable list of arguments.
+ If CurrVarArg is NULL, return the first node of the
+ variable argument list.
+ Return NULL if
+ - CurrVarArg is the last node of the list, or
+ - Node does not have a variable list of arguments.
+**/
+AML_NODE_HEADER *
+EFIAPI
+AmlGetNextVariableArgument (
+ IN AML_NODE_HEADER * Node,
+ IN AML_NODE_HEADER * CurrVarArg
+ )
+{
+ CONST LIST_ENTRY * StartLink;
+ CONST LIST_ENTRY * NextLink;
+
+ // Node must be a RootNode or an Object Node
+ // and the CurrVarArg must not be a Root Node.
+ if ((!IS_AML_ROOT_NODE (Node) &&
+ !IS_AML_OBJECT_NODE (Node)) ||
+ ((CurrVarArg != NULL) &&
+ (!IS_AML_OBJECT_NODE (CurrVarArg) &&
+ !IS_AML_DATA_NODE (CurrVarArg)))) {
+ ASSERT (0);
+ return NULL;
+ }
+
+ StartLink = AmlNodeGetVariableArgList (Node);
+ if (StartLink == NULL) {
+ return NULL;
+ }
+
+ // Get the first child of the variable list of arguments.
+ if (CurrVarArg == NULL) {
+ NextLink = StartLink->ForwardLink;
+ if (NextLink != StartLink) {
+ return (AML_NODE_HEADER*)NextLink;
+ }
+ // List is empty.
+ return NULL;
+ }
+
+ // Check if CurrVarArg is in the VariableArgument List.
+ if (!IsNodeInList (StartLink, &CurrVarArg->Link)) {
+ ASSERT (0);
+ return NULL;
+ }
+
+ // Get the node following the CurrVarArg.
+ NextLink = CurrVarArg->Link.ForwardLink;
+ if (NextLink != StartLink) {
+ return (AML_NODE_HEADER*)NextLink;
+ }
+
+ // End of the list has been reached.
+ return NULL;
+}
+
+/** Get the previous variable argument.
+
+ (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: g, f, e, NULL
+
+ @param [in] Node Pointer to a root node or an object node.
+ @param [in] CurrVarArg Pointer to the Current Variable Argument.
+
+ @return The node before the CurrVarArg in the variable list of
+ arguments.
+ If CurrVarArg is NULL, return the last node of the
+ variable list of arguments.
+ Return NULL if:
+ - CurrVarArg is the first node of the list, or
+ - Node doesn't have a variable list of arguments.
+**/
+AML_NODE_HEADER *
+EFIAPI
+AmlGetPreviousVariableArgument (
+ IN AML_NODE_HEADER * Node,
+ IN AML_NODE_HEADER * CurrVarArg
+ )
+{
+ CONST LIST_ENTRY * StartLink;
+ CONST LIST_ENTRY * PreviousLink;
+
+ // Node must be a RootNode or an Object Node
+ // and the CurrVarArg must not be a Root Node.
+ if ((!IS_AML_ROOT_NODE (Node) &&
+ !IS_AML_OBJECT_NODE (Node)) ||
+ ((CurrVarArg != NULL) &&
+ (!IS_AML_OBJECT_NODE (CurrVarArg) &&
+ !IS_AML_DATA_NODE (CurrVarArg)))) {
+ ASSERT (0);
+ return NULL;
+ }
+
+ StartLink = AmlNodeGetVariableArgList (Node);
+ if (StartLink == NULL) {
+ return NULL;
+ }
+
+ // Get the last child of the variable list of arguments.
+ if (CurrVarArg == NULL) {
+ PreviousLink = StartLink->BackLink;
+ if (PreviousLink != StartLink) {
+ return (AML_NODE_HEADER*)PreviousLink;
+ }
+ // List is empty.
+ return NULL;
+ }
+
+ // Check if CurrVarArg is in the VariableArgument List.
+ if (!IsNodeInList (StartLink, &CurrVarArg->Link)) {
+ ASSERT (0);
+ return NULL;
+ }
+
+ // Get the node before the CurrVarArg.
+ PreviousLink = CurrVarArg->Link.BackLink;
+ if (PreviousLink != StartLink) {
+ return (AML_NODE_HEADER*)PreviousLink;
+ }
+
+ // We have reached the beginning of the list.
+ return NULL;
+}
+
+/** Get the next sibling node among the children of the input Node.
+
+ This function traverses the FixedArguments followed by the
+ VariableArguments at the same level in the hierarchy.
+
+ Fixed arguments are before variable arguments.
+
+ (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: a, b, c, d, e, f, g, NULL
+
+
+ @param [in] Node Pointer to a root node or an object node.
+ @param [in] ChildNode Get the node after the ChildNode.
+
+ @return The node after the ChildNode among the children of the input Node.
+ - If ChildNode is NULL, return the first available node among
+ the fixed argument list then variable list of arguments;
+ - If ChildNode is the last node of the fixed argument list,
+ return the first argument of the variable list of arguments;
+ - If ChildNode is the last node of the variable list of arguments,
+ return NULL.
+
+**/
+AML_NODE_HEADER *
+EFIAPI
+AmlGetNextSibling (
+ IN CONST AML_NODE_HEADER * Node,
+ IN CONST AML_NODE_HEADER * ChildNode
+ )
+{
+ EAML_PARSE_INDEX Index;
+ AML_NODE_HEADER * CandidateNode;
+
+ // Node must be a RootNode or an Object Node
+ // and the CurrVarArg must not be a Root Node.
+ if ((!IS_AML_ROOT_NODE (Node) &&
+ !IS_AML_OBJECT_NODE (Node)) ||
+ ((ChildNode != NULL) &&
+ (!IS_AML_OBJECT_NODE (ChildNode) &&
+ !IS_AML_DATA_NODE (ChildNode)))) {
+ ASSERT (0);
+ return NULL;
+ }
+
+ if (IS_AML_OBJECT_NODE (Node)) {
+ if (ChildNode == NULL) {
+ // Get the fixed argument at index 0 of the ChildNode.
+ CandidateNode = AmlGetFixedArgument (
+ (AML_OBJECT_NODE*)Node,
+ EAmlParseIndexTerm0
+ );
+ if (CandidateNode != NULL) {
+ return CandidateNode;
+ }
+ } else {
+ // (ChildNode != NULL)
+ if (AmlIsNodeFixedArgument (ChildNode, &Index)) {
+ // Increment index to point to the next fixed argument.
+ Index++;
+ // The node is part of the list of fixed arguments.
+ if (Index == (EAML_PARSE_INDEX)AmlGetFixedArgumentCount (
+ (AML_OBJECT_NODE*)Node)
+ ) {
+ // It is at the last argument of the fixed argument list.
+ // Get the first argument of the variable list of arguments.
+ ChildNode = NULL;
+ } else {
+ // Else return the next node in the list of fixed arguments.
+ return AmlGetFixedArgument ((AML_OBJECT_NODE*)Node, Index);
+ }
+ }
+ }
+ } // IS_AML_OBJECT_NODE (Node)
+
+ // Else, get the next node in the variable list of arguments.
+ return AmlGetNextVariableArgument (
+ (AML_NODE_HEADER*)Node,
+ (AML_NODE_HEADER*)ChildNode
+ );
+}
+
+/** Get the previous sibling node among the children of the input Node.
+
+ This function traverses the FixedArguments followed by the
+ VariableArguments at the same level in the hierarchy.
+
+ Fixed arguments are before variable arguments.
+
+ (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: g, f, e, d, c, b, a, NULL
+
+ @param [in] Node The node to get the fixed argument from.
+ @param [in] ChildNode Get the node before the ChildNode.
+
+ @return The node before the ChildNode among the children of the input Node.
+ - If ChildNode is NULL, return the last available node among
+ the variable list of arguments then fixed argument list;
+ - If ChildNode is the first node of the variable list of arguments,
+ return the last argument of the fixed argument list;
+ - If ChildNode is the first node of the fixed argument list,
+ return NULL.
+**/
+AML_NODE_HEADER *
+EFIAPI
+AmlGetPreviousSibling (
+ IN CONST AML_NODE_HEADER * Node,
+ IN CONST AML_NODE_HEADER * ChildNode
+ )
+{
+ EAML_PARSE_INDEX Index;
+ EAML_PARSE_INDEX MaxIndex;
+
+ AML_NODE_HEADER * CandidateNode;
+
+ // Node must be a Root Node or an Object Node
+ // and the ChildNode must not be a Root Node.
+ if ((!IS_AML_ROOT_NODE (Node) &&
+ !IS_AML_OBJECT_NODE (Node)) ||
+ ((ChildNode != NULL) &&
+ (!IS_AML_OBJECT_NODE (ChildNode) &&
+ !IS_AML_DATA_NODE (ChildNode)))) {
+ ASSERT (0);
+ return NULL;
+ }
+
+ MaxIndex = (EAML_PARSE_INDEX)AmlGetFixedArgumentCount (
+ (AML_OBJECT_NODE*)Node
+ );
+
+ // Get the last variable argument if no ChildNode.
+ // Otherwise the fixed argument list is checked first.
+ if ((ChildNode != NULL) &&
+ IS_AML_OBJECT_NODE (Node) &&
+ (MaxIndex != EAmlParseIndexTerm0)) {
+ if (AmlIsNodeFixedArgument (ChildNode, &Index)) {
+ // The node is part of the list of fixed arguments.
+ if (Index == EAmlParseIndexTerm0) {
+ // The node is the first fixed argument, return NULL.
+ return NULL;
+ } else {
+ // Return the previous node in the fixed argument list.
+ return AmlGetFixedArgument (
+ (AML_OBJECT_NODE*)Node,
+ (EAML_PARSE_INDEX)(Index - 1)
+ );
+ }
+ }
+ }
+
+ // ChildNode is in the variable list of arguments.
+ CandidateNode = AmlGetPreviousVariableArgument (
+ (AML_NODE_HEADER*)Node,
+ (AML_NODE_HEADER*)ChildNode
+ );
+ if (CandidateNode != NULL) {
+ if (!IS_AML_NODE_VALID (CandidateNode)) {
+ ASSERT (0);
+ return NULL;
+ }
+ // A Node has been found
+ return CandidateNode;
+ } else if (MaxIndex != EAmlParseIndexTerm0) {
+ // ChildNode was the first node of the variable list of arguments.
+ return AmlGetFixedArgument (
+ (AML_OBJECT_NODE*)Node,
+ (EAML_PARSE_INDEX)(MaxIndex - 1)
+ );
+ } else {
+ // No fixed arguments or variable arguments.
+ return NULL;
+ }
+}
+
+/** Iterate through the nodes in the same order as the AML bytestream.
+
+ The iteration is similar to a depth-first path.
+
+ (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: a, b, i, c, d, e, h, f, g, NULL
+ Note: The branch i and h will be traversed if it has any children.
+
+ @param [in] Node Pointer to a node.
+
+ @return The next node in the AML bytestream order.
+ Return NULL if Node is the Node corresponding to the last
+ bytecode of the tree.
+**/
+AML_NODE_HEADER *
+EFIAPI
+AmlGetNextNode (
+ IN CONST AML_NODE_HEADER * Node
+ )
+{
+ AML_NODE_HEADER * ParentNode;
+ AML_NODE_HEADER * CandidateNode;
+
+ if (!IS_AML_NODE_VALID (Node)) {
+ ASSERT (0);
+ return NULL;
+ }
+
+ if (IS_AML_ROOT_NODE (Node) || IS_AML_OBJECT_NODE (Node)) {
+ // The node has children. Get the first child.
+ CandidateNode = AmlGetNextSibling (Node, NULL);
+ if (CandidateNode != NULL) {
+ if (!IS_AML_NODE_VALID (CandidateNode)) {
+ ASSERT (0);
+ return NULL;
+ }
+ // A Node has been found
+ return CandidateNode;
+ } else if (IS_AML_ROOT_NODE (Node)) {
+ // The node is the root node and it doesn't have children.
+ return NULL;
+ }
+ }
+
+ // We have traversed the current branch, go to the parent node
+ // and start traversing the next branch.
+ // Keep going up the tree until you reach the root node.
+ while (1) {
+ if (IS_AML_ROOT_NODE (Node)) {
+ // This is the last node of the tree.
+ return NULL;
+ }
+
+ ParentNode = AmlGetParent ((AML_NODE_HEADER*)Node);
+ if (!IS_AML_NODE_VALID (ParentNode)) {
+ ASSERT (0);
+ return NULL;
+ }
+
+ CandidateNode = AmlGetNextSibling (ParentNode, Node);
+ if (CandidateNode != NULL) {
+ if (!IS_AML_NODE_VALID (CandidateNode)) {
+ ASSERT (0);
+ return NULL;
+ }
+ // A Node has been found
+ return CandidateNode;
+ }
+
+ Node = ParentNode;
+ } // while
+
+ return NULL;
+}
+
+/** Iterate through the nodes in the reverse order of the AML bytestream.
+
+ The iteration is similar to a depth-first path,
+ but done in a reverse order.
+
+ (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: g, f, h, e, d, c, i, b, a, NULL
+ Note: The branch i and h will be traversed if it has any children.
+
+ @param [in] Node Pointer to a node.
+
+ @return The previous node in the AML bytestream order.
+ Return NULL if Node is the Node corresponding to the last
+ bytecode of the tree.
+**/
+AML_NODE_HEADER *
+EFIAPI
+AmlGetPreviousNode (
+ IN CONST AML_NODE_HEADER * Node
+ )
+{
+ AML_NODE_HEADER * ParentNode;
+ AML_NODE_HEADER * CandidateNode;
+ AML_NODE_HEADER * PreviousNode;
+
+ if (!IS_AML_NODE_VALID (Node)) {
+ ASSERT (0);
+ return NULL;
+ }
+
+ while (1) {
+
+ if (IS_AML_ROOT_NODE (Node)) {
+ // This is the root node.
+ return NULL;
+ }
+
+ ParentNode = AmlGetParent ((AML_NODE_HEADER*)Node);
+ CandidateNode = AmlGetPreviousSibling (ParentNode, Node);
+
+ if (CandidateNode == NULL) {
+ // Node is the first child of its parent.
+ return ParentNode;
+ } else if (IS_AML_DATA_NODE (CandidateNode)) {
+ // CandidateNode is a data node, thus it has no children.
+ return CandidateNode;
+ } else if (IS_AML_OBJECT_NODE (CandidateNode)) {
+ // Get the previous node in the list of children of ParentNode,
+ // then get the last child of this node.
+ // If this node has children, get its last child, etc.
+ while (1) {
+ PreviousNode = CandidateNode;
+ CandidateNode = AmlGetPreviousSibling (PreviousNode, NULL);
+ if (CandidateNode == NULL) {
+ return PreviousNode;
+ } else if (IS_AML_DATA_NODE (CandidateNode)) {
+ return CandidateNode;
+ }
+ } // while
+
+ } else {
+ ASSERT (0);
+ return NULL;
+ }
+ } // while
+}
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlTreeTraversal.h b/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlTreeTraversal.h
new file mode 100644
index 0000000000..a4980b716d
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlTreeTraversal.h
@@ -0,0 +1,138 @@
+/** @file
+ AML Tree Traversal.
+
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef AML_TREE_TRAVERSAL_H_
+#define AML_TREE_TRAVERSAL_H_
+
+#include <AmlNodeDefines.h>
+
+/** Get the next sibling node among the children of the input Node.
+
+ This function traverses the FixedArguments followed by the
+ VariableArguments at the same level in the hierarchy.
+
+ Fixed arguments are before variable arguments.
+
+ (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: a, b, c, d, e, f, g, NULL
+
+
+ @param [in] Node Pointer to a root node or an object node.
+ @param [in] ChildNode Get the node after the ChildNode.
+
+ @return The node after the ChildNode among the children of the input Node.
+ - If ChildNode is NULL, return the first available node among
+ the fixed argument list then variable list of arguments;
+ - If ChildNode is the last node of the fixed argument list,
+ return the first argument of the variable list of arguments;
+ - If ChildNode is the last node of the variable list of arguments,
+ return NULL.
+
+**/
+AML_NODE_HEADER *
+EFIAPI
+AmlGetNextSibling (
+ IN CONST AML_NODE_HEADER * Node,
+ IN CONST AML_NODE_HEADER * ChildNode
+ );
+
+/** Get the previous sibling node among the children of the input Node.
+
+ This function traverses the FixedArguments followed by the
+ VariableArguments at the same level in the hierarchy.
+
+ Fixed arguments are before variable arguments.
+
+ (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: g, f, e, d, c, b, a, NULL
+
+ @param [in] Node The node to get the fixed argument from.
+ @param [in] ChildNode Get the node before the ChildNode.
+
+ @return The node before the ChildNode among the children of the input Node.
+ - If ChildNode is NULL, return the last available node among
+ the variable list of arguments then fixed argument list;
+ - If ChildNode is the first node of the variable list of arguments,
+ return the last argument of the fixed argument list;
+ - If ChildNode is the first node of the fixed argument list,
+ return NULL.
+**/
+AML_NODE_HEADER *
+EFIAPI
+AmlGetPreviousSibling (
+ IN CONST AML_NODE_HEADER * Node,
+ IN CONST AML_NODE_HEADER * ChildNode
+ );
+
+/** Iterate through the nodes in the same order as the AML bytestream.
+
+ The iteration is similar to a depth-first path.
+
+ (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: a, b, i, c, d, e, h, f, g, NULL
+ Note: The branch i and h will be traversed if it has any children.
+
+ @param [in] Node Pointer to a node.
+
+ @return The next node in the AML bytestream order.
+ Return NULL if Node is the Node corresponding to the last
+ bytecode of the tree.
+**/
+AML_NODE_HEADER *
+EFIAPI
+AmlGetNextNode (
+ IN CONST AML_NODE_HEADER * Node
+ );
+
+/** Iterate through the nodes in the reverse order of the AML bytestream.
+
+ The iteration is similar to a depth-first path,
+ but done in a reverse order.
+
+ (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: g, f, h, e, d, c, i, b, a, NULL
+ Note: The branch i and h will be traversed if it has any children.
+
+ @param [in] Node Pointer to a node.
+
+ @return The previous node in the AML bytestream order.
+ Return NULL if Node is the Node corresponding to the last
+ bytecode of the tree.
+**/
+AML_NODE_HEADER *
+EFIAPI
+AmlGetPreviousNode (
+ IN CONST AML_NODE_HEADER * Node
+ );
+
+#endif // AML_TREE_TRAVERSAL_H_
+