mirror of https://github.com/acidanthera/audk.git
DynamicTablesPkg: AML tree/node cloning
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>
This commit is contained in:
parent
e2c1104c50
commit
0414377c02
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue