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