From: Pierre Gondois Date: Mon, 3 Aug 2020 18:40:54 +0000 (+0100) Subject: DynamicTablesPkg: AML tree/node cloning X-Git-Tag: edk2-stable202008~126 X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;ds=sidebyside;h=0414377c021e624dba9d01314464620db3ec3744;p=mirror_edk2.git DynamicTablesPkg: AML tree/node cloning 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 Signed-off-by: Sami Mujawar Reviewed-by: Alexei Fedorov --- diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlClone.c b/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlClone.c new file mode 100644 index 0000000000..e09372b039 --- /dev/null +++ b/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlClone.c @@ -0,0 +1,205 @@ +/** @file + AML Clone. + + Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +#include +#include +#include + +/** Clone a node. + + This function does not clone the children nodes. + The cloned node returned is not attached to any tree. + + @param [in] Node Pointer to a node. + @param [out] ClonedNode Pointer holding the cloned node. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Could not allocate memory. +**/ +EFI_STATUS +EFIAPI +AmlCloneNode ( + IN AML_NODE_HEADER * Node, + OUT AML_NODE_HEADER ** ClonedNode + ) +{ + EFI_STATUS Status; + + AML_OBJECT_NODE * ObjectNode; + AML_DATA_NODE * DataNode; + AML_ROOT_NODE * RootNode; + + if (!IS_AML_NODE_VALID (Node) || + (ClonedNode == NULL)) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + *ClonedNode = NULL; + + if (IS_AML_DATA_NODE (Node)) { + DataNode = (AML_DATA_NODE*)Node; + Status = AmlCreateDataNode ( + DataNode->DataType, + DataNode->Buffer, + DataNode->Size, + (AML_DATA_NODE**)ClonedNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + } + } else if (IS_AML_OBJECT_NODE (Node)) { + ObjectNode = (AML_OBJECT_NODE*)Node; + + Status = AmlCreateObjectNode ( + ObjectNode->AmlByteEncoding, + ObjectNode->PkgLen, + (AML_OBJECT_NODE**)ClonedNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + } + } else if (IS_AML_ROOT_NODE (Node)) { + RootNode = (AML_ROOT_NODE*)Node; + + Status = AmlCreateRootNode ( + RootNode->SdtHeader, + (AML_ROOT_NODE**)ClonedNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + } + } else { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + return Status; +} + +/** Clone a node and its children (clone a tree branch). + + The cloned branch returned is not attached to any tree. + + @param [in] Node Pointer to a node. + Node is the head of the branch to clone. + @param [out] ClonedNode Pointer holding the head of the created cloned + branch. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Could not allocate memory. +**/ +EFI_STATUS +EFIAPI +AmlCloneTree ( + IN AML_NODE_HEADER * Node, + OUT AML_NODE_HEADER ** ClonedNode + ) +{ + EFI_STATUS Status; + + AML_NODE_HEADER * HeadNode; + AML_NODE_HEADER * ClonedChildNode; + AML_NODE_HEADER * FixedArgNode; + + EAML_PARSE_INDEX Index; + EAML_PARSE_INDEX MaxIndex; + + LIST_ENTRY * StartLink; + LIST_ENTRY * CurrentLink; + + if (!IS_AML_NODE_VALID (Node) || + (ClonedNode == NULL)) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + Status = AmlCloneNode (Node, &HeadNode); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + + // Clone the fixed arguments and bind them to their parent. + MaxIndex = (EAML_PARSE_INDEX)AmlGetFixedArgumentCount ( + (AML_OBJECT_NODE*)Node + ); + for (Index = EAmlParseIndexTerm0; Index < MaxIndex; Index++) { + FixedArgNode = AmlGetFixedArgument ((AML_OBJECT_NODE*)Node, Index); + if (FixedArgNode == NULL) { + Status = EFI_INVALID_PARAMETER; + ASSERT (0); + goto error_handler; + } + + // Clone child. + Status = AmlCloneTree ( + FixedArgNode, + &ClonedChildNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler; + } + + // Bind child. + Status = AmlSetFixedArgument ( + (AML_OBJECT_NODE*)HeadNode, + Index, + ClonedChildNode + ); + if (EFI_ERROR (Status)) { + AmlDeleteTree (ClonedChildNode); + ASSERT (0); + goto error_handler; + } + } // for + + // Clone the variable arguments and bind them to their parent. + StartLink = AmlNodeGetVariableArgList (Node); + if (StartLink != NULL) { + CurrentLink = StartLink->ForwardLink; + while (CurrentLink != StartLink) { + // Clone child. + Status = AmlCloneTree ((AML_NODE_HEADER*)CurrentLink, &ClonedChildNode); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler; + } + + // Bind child. + Status = AmlVarListAddTailInternal ( + HeadNode, + ClonedChildNode + ); + if (EFI_ERROR (Status)) { + AmlDeleteTree (ClonedChildNode); + ASSERT (0); + goto error_handler; + } + + CurrentLink = CurrentLink->ForwardLink; + } // while + } + + *ClonedNode = HeadNode; + return Status; + +error_handler: + *ClonedNode = NULL; + + if (HeadNode != NULL) { + AmlDeleteTree (HeadNode); + } + + return Status; +}