mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-10-30 18:53:45 +01:00 
			
		
		
		
	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>
		
			
				
	
	
		
			206 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			206 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @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;
 | |
| }
 |