--- /dev/null
+/** @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
--- /dev/null
+/** @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