From: Pierre Gondois <pierre.gond...@arm.com> 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.gond...@arm.com> Signed-off-by: Sami Mujawar <sami.muja...@arm.com> --- DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlClone.c | 205 ++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlClone.c b/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlClone.c new file mode 100644 index 0000000000000000000000000000000000000000..e09372b039f1f232de500effae7d403d56c989cd --- /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.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <AmlNodeDefines.h> + +#include <AmlCoreInterface.h> +#include <Tree/AmlNode.h> +#include <Tree/AmlTree.h> + +/** 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; +} -- 'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)' -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#64086): https://edk2.groups.io/g/devel/message/64086 Mute This Topic: https://groups.io/mt/76149154/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-