audk/DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlClone.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;
}