]> git.proxmox.com Git - mirror_edk2.git/commitdiff
DynamicTablesPkg: AML tree/node cloning
authorPierre Gondois <pierre.gondois@arm.com>
Mon, 3 Aug 2020 18:40:54 +0000 (19:40 +0100)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Thu, 13 Aug 2020 18:00:06 +0000 (18:00 +0000)
It is often desirable to clone an AML branch/tree
or an AML node. An example of could be to clone
an AML template before fixup so that the original
AML template remains unmodified. Another example
would be replicating a device branch in the AML
tree and fixing up the device information.

To facilitate such scenarios the AmlLib library
provides functions that can be used to clone an
AML branch/tree or an AML node.

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/AmlClone.c [new file with mode: 0644]

diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlClone.c b/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlClone.c
new file mode 100644 (file)
index 0000000..e09372b
--- /dev/null
@@ -0,0 +1,205 @@
+/** @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