/** @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; } 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; }