--- /dev/null
+/** @file\r
+ AML Clone.\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 <AmlNodeDefines.h>\r
+\r
+#include <AmlCoreInterface.h>\r
+#include <Tree/AmlNode.h>\r
+#include <Tree/AmlTree.h>\r
+\r
+/** Clone a node.\r
+\r
+ This function does not clone the children nodes.\r
+ The cloned node returned is not attached to any tree.\r
+\r
+ @param [in] Node Pointer to a node.\r
+ @param [out] ClonedNode Pointer holding the cloned node.\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
+EFI_STATUS\r
+EFIAPI\r
+AmlCloneNode (\r
+ IN AML_NODE_HEADER * Node,\r
+ OUT AML_NODE_HEADER ** ClonedNode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ AML_OBJECT_NODE * ObjectNode;\r
+ AML_DATA_NODE * DataNode;\r
+ AML_ROOT_NODE * RootNode;\r
+\r
+ if (!IS_AML_NODE_VALID (Node) ||\r
+ (ClonedNode == NULL)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *ClonedNode = NULL;\r
+\r
+ if (IS_AML_DATA_NODE (Node)) {\r
+ DataNode = (AML_DATA_NODE*)Node;\r
+ Status = AmlCreateDataNode (\r
+ DataNode->DataType,\r
+ DataNode->Buffer,\r
+ DataNode->Size,\r
+ (AML_DATA_NODE**)ClonedNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ }\r
+ } else if (IS_AML_OBJECT_NODE (Node)) {\r
+ ObjectNode = (AML_OBJECT_NODE*)Node;\r
+\r
+ Status = AmlCreateObjectNode (\r
+ ObjectNode->AmlByteEncoding,\r
+ ObjectNode->PkgLen,\r
+ (AML_OBJECT_NODE**)ClonedNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ }\r
+ } else if (IS_AML_ROOT_NODE (Node)) {\r
+ RootNode = (AML_ROOT_NODE*)Node;\r
+\r
+ Status = AmlCreateRootNode (\r
+ RootNode->SdtHeader,\r
+ (AML_ROOT_NODE**)ClonedNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ }\r
+ } else {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/** Clone a node and its children (clone a tree branch).\r
+\r
+ The cloned branch returned is not attached to any tree.\r
+\r
+ @param [in] Node Pointer to a node.\r
+ Node is the head of the branch to clone.\r
+ @param [out] ClonedNode Pointer holding the head of the created cloned\r
+ branch.\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
+EFI_STATUS\r
+EFIAPI\r
+AmlCloneTree (\r
+ IN AML_NODE_HEADER * Node,\r
+ OUT AML_NODE_HEADER ** ClonedNode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ AML_NODE_HEADER * HeadNode;\r
+ AML_NODE_HEADER * ClonedChildNode;\r
+ AML_NODE_HEADER * FixedArgNode;\r
+\r
+ EAML_PARSE_INDEX Index;\r
+ EAML_PARSE_INDEX MaxIndex;\r
+\r
+ LIST_ENTRY * StartLink;\r
+ LIST_ENTRY * CurrentLink;\r
+\r
+ if (!IS_AML_NODE_VALID (Node) ||\r
+ (ClonedNode == NULL)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = AmlCloneNode (Node, &HeadNode);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ // Clone the fixed arguments and bind them to their parent.\r
+ MaxIndex = (EAML_PARSE_INDEX)AmlGetFixedArgumentCount (\r
+ (AML_OBJECT_NODE*)Node\r
+ );\r
+ for (Index = EAmlParseIndexTerm0; Index < MaxIndex; Index++) {\r
+ FixedArgNode = AmlGetFixedArgument ((AML_OBJECT_NODE*)Node, Index);\r
+ if (FixedArgNode == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+\r
+ // Clone child.\r
+ Status = AmlCloneTree (\r
+ FixedArgNode,\r
+ &ClonedChildNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+\r
+ // Bind child.\r
+ Status = AmlSetFixedArgument (\r
+ (AML_OBJECT_NODE*)HeadNode,\r
+ Index,\r
+ ClonedChildNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ AmlDeleteTree (ClonedChildNode);\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+ } // for\r
+\r
+ // Clone the variable arguments and bind them to their parent.\r
+ StartLink = AmlNodeGetVariableArgList (Node);\r
+ if (StartLink != NULL) {\r
+ CurrentLink = StartLink->ForwardLink;\r
+ while (CurrentLink != StartLink) {\r
+ // Clone child.\r
+ Status = AmlCloneTree ((AML_NODE_HEADER*)CurrentLink, &ClonedChildNode);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+\r
+ // Bind child.\r
+ Status = AmlVarListAddTailInternal (\r
+ HeadNode,\r
+ ClonedChildNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ AmlDeleteTree (ClonedChildNode);\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+\r
+ CurrentLink = CurrentLink->ForwardLink;\r
+ } // while\r
+ }\r
+\r
+ *ClonedNode = HeadNode;\r
+ return Status;\r
+\r
+error_handler:\r
+ *ClonedNode = NULL;\r
+\r
+ if (HeadNode != NULL) {\r
+ AmlDeleteTree (HeadNode);\r
+ }\r
+\r
+ return Status;\r
+}\r