mirror of https://github.com/acidanthera/audk.git
354 lines
10 KiB
C
354 lines
10 KiB
C
/** @file
|
|
AML Tree Iterator.
|
|
|
|
Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
|
|
#include <AmlNodeDefines.h>
|
|
#include <Tree/AmlTreeIterator.h>
|
|
|
|
#include <AmlCoreInterface.h>
|
|
#include <Tree/AmlTreeTraversal.h>
|
|
|
|
/** Iterator to traverse the tree.
|
|
|
|
This is an internal structure.
|
|
*/
|
|
typedef struct AmlTreeInternalIterator {
|
|
/// External iterator structure, containing the external APIs.
|
|
/// Must be the first field.
|
|
AML_TREE_ITERATOR Iterator;
|
|
|
|
// Note: The following members of this structure are opaque to the users
|
|
// of the Tree iterator APIs.
|
|
|
|
/// Pointer to the node on which the iterator has been initialized.
|
|
CONST AML_NODE_HEADER * InitialNode;
|
|
|
|
/// Pointer to the current node.
|
|
CONST AML_NODE_HEADER * CurrentNode;
|
|
|
|
/// Iteration mode.
|
|
/// Allow to choose how to traverse the tree/choose which node is next.
|
|
EAML_ITERATOR_MODE Mode;
|
|
} AML_TREE_ITERATOR_INTERNAL;
|
|
|
|
/** Get the current node of an iterator.
|
|
|
|
@param [in] Iterator Pointer to an iterator.
|
|
@param [out] OutNode Pointer holding the current node.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlIteratorGetNode (
|
|
IN AML_TREE_ITERATOR * Iterator,
|
|
OUT AML_NODE_HEADER ** OutNode
|
|
)
|
|
{
|
|
AML_TREE_ITERATOR_INTERNAL * InternalIterator;
|
|
|
|
InternalIterator = (AML_TREE_ITERATOR_INTERNAL*)Iterator;
|
|
|
|
// CurrentNode can be NULL, but InitialNode cannot.
|
|
if ((OutNode == NULL) ||
|
|
(InternalIterator == NULL) ||
|
|
(InternalIterator->Mode <= EAmlIteratorUnknown) ||
|
|
(InternalIterator->Mode >= EAmlIteratorModeMax) ||
|
|
!IS_AML_NODE_VALID (InternalIterator->InitialNode) ||
|
|
((InternalIterator->CurrentNode != NULL) &&
|
|
!IS_AML_NODE_VALID (InternalIterator->CurrentNode))) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*OutNode = (AML_NODE_HEADER*)InternalIterator->CurrentNode;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Move the current node of the iterator to the next node,
|
|
according to the iteration mode selected.
|
|
|
|
If NextNode is not NULL, return the next node.
|
|
|
|
@param [in] Iterator Pointer to an iterator.
|
|
@param [out] NextNode If not NULL, updated to the next node.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlIteratorGetNextLinear (
|
|
IN AML_TREE_ITERATOR * Iterator,
|
|
OUT AML_NODE_HEADER ** NextNode
|
|
)
|
|
{
|
|
AML_TREE_ITERATOR_INTERNAL * InternalIterator;
|
|
|
|
InternalIterator = (AML_TREE_ITERATOR_INTERNAL*)Iterator;
|
|
|
|
// CurrentNode can be NULL, but InitialNode cannot.
|
|
if ((InternalIterator == NULL) ||
|
|
(InternalIterator->Mode != EAmlIteratorLinear) ||
|
|
!IS_AML_NODE_VALID (InternalIterator->InitialNode) ||
|
|
!IS_AML_NODE_VALID (InternalIterator->CurrentNode)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Get the next node according to the iteration mode.
|
|
InternalIterator->CurrentNode = AmlGetNextNode (
|
|
InternalIterator->CurrentNode
|
|
);
|
|
|
|
if (NextNode != NULL) {
|
|
*NextNode = (AML_NODE_HEADER*)InternalIterator->CurrentNode;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Move the current node of the iterator to the previous node,
|
|
according to the iteration mode selected.
|
|
|
|
If PrevNode is not NULL, return the previous node.
|
|
|
|
@param [in] Iterator Pointer to an iterator.
|
|
@param [out] PrevNode If not NULL, updated to the previous node.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlIteratorGetPreviousLinear (
|
|
IN AML_TREE_ITERATOR * Iterator,
|
|
OUT AML_NODE_HEADER ** PrevNode
|
|
)
|
|
{
|
|
AML_TREE_ITERATOR_INTERNAL * InternalIterator;
|
|
|
|
InternalIterator = (AML_TREE_ITERATOR_INTERNAL*)Iterator;
|
|
|
|
// CurrentNode can be NULL, but InitialNode cannot.
|
|
if ((InternalIterator == NULL) ||
|
|
(InternalIterator->Mode != EAmlIteratorLinear) ||
|
|
!IS_AML_NODE_VALID (InternalIterator->InitialNode) ||
|
|
!IS_AML_NODE_VALID (InternalIterator->CurrentNode)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Get the previous node according to the iteration mode.
|
|
InternalIterator->CurrentNode = AmlGetPreviousNode (
|
|
InternalIterator->CurrentNode
|
|
);
|
|
if (PrevNode != NULL) {
|
|
*PrevNode = (AML_NODE_HEADER*)InternalIterator->CurrentNode;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Move the current node of the iterator to the next node,
|
|
according to the iteration mode selected.
|
|
|
|
If NextNode is not NULL, return the next node.
|
|
|
|
@param [in] Iterator Pointer to an iterator.
|
|
@param [out] NextNode If not NULL, updated to the next node.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlIteratorGetNextBranch (
|
|
IN AML_TREE_ITERATOR * Iterator,
|
|
OUT AML_NODE_HEADER ** NextNode
|
|
)
|
|
{
|
|
AML_TREE_ITERATOR_INTERNAL * InternalIterator;
|
|
AML_NODE_HEADER * Node;
|
|
|
|
InternalIterator = (AML_TREE_ITERATOR_INTERNAL*)Iterator;
|
|
|
|
// CurrentNode can be NULL, but InitialNode cannot.
|
|
if ((InternalIterator == NULL) ||
|
|
(InternalIterator->Mode != EAmlIteratorBranch) ||
|
|
!IS_AML_NODE_VALID (InternalIterator->InitialNode) ||
|
|
!IS_AML_NODE_VALID (InternalIterator->CurrentNode)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Node = AmlGetNextNode (InternalIterator->CurrentNode);
|
|
// Check whether NextNode is a sibling of InitialNode.
|
|
if (AmlGetParent (Node) ==
|
|
AmlGetParent ((AML_NODE_HEADER*)InternalIterator->InitialNode)) {
|
|
Node = NULL;
|
|
}
|
|
|
|
InternalIterator->CurrentNode = Node;
|
|
|
|
if (NextNode != NULL) {
|
|
*NextNode = Node;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Move the current node of the iterator to the previous node,
|
|
according to the iteration mode selected.
|
|
|
|
If PrevNode is not NULL, return the previous node.
|
|
|
|
@param [in] Iterator Pointer to an iterator.
|
|
@param [out] PrevNode If not NULL, updated to the previous node.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlIteratorGetPreviousBranch (
|
|
IN AML_TREE_ITERATOR * Iterator,
|
|
OUT AML_NODE_HEADER ** PrevNode
|
|
)
|
|
{
|
|
AML_TREE_ITERATOR_INTERNAL * InternalIterator;
|
|
AML_NODE_HEADER * Node;
|
|
|
|
InternalIterator = (AML_TREE_ITERATOR_INTERNAL*)Iterator;
|
|
|
|
// CurrentNode can be NULL, but InitialNode cannot.
|
|
if ((InternalIterator == NULL) ||
|
|
(InternalIterator->Mode != EAmlIteratorBranch) ||
|
|
!IS_AML_NODE_VALID (InternalIterator->InitialNode) ||
|
|
!IS_AML_NODE_VALID (InternalIterator->CurrentNode)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Node = AmlGetPreviousNode (InternalIterator->CurrentNode);
|
|
// Check whether PreviousNode is a sibling of InitialNode.
|
|
if (AmlGetParent (Node) ==
|
|
AmlGetParent ((AML_NODE_HEADER*)InternalIterator->InitialNode)) {
|
|
Node = NULL;
|
|
}
|
|
|
|
InternalIterator->CurrentNode = Node;
|
|
|
|
if (PrevNode != NULL) {
|
|
*PrevNode = Node;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Initialize an iterator.
|
|
|
|
Note: The caller must call AmlDeleteIterator () to free the memory
|
|
allocated for the iterator.
|
|
|
|
@param [in] Node Pointer to the node.
|
|
@param [in] IteratorMode Selected mode to traverse the tree.
|
|
@param [out] IteratorPtr Pointer holding the created iterator.
|
|
|
|
@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
|
|
AmlInitializeIterator (
|
|
IN AML_NODE_HEADER * Node,
|
|
IN EAML_ITERATOR_MODE IteratorMode,
|
|
OUT AML_TREE_ITERATOR ** IteratorPtr
|
|
)
|
|
{
|
|
AML_TREE_ITERATOR_INTERNAL * InternalIterator;
|
|
|
|
if (!IS_AML_NODE_VALID (Node) ||
|
|
(IteratorMode <= EAmlIteratorUnknown) ||
|
|
(IteratorMode >= EAmlIteratorModeMax) ||
|
|
(IteratorPtr == NULL)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*IteratorPtr = NULL;
|
|
InternalIterator = (AML_TREE_ITERATOR_INTERNAL*)AllocateZeroPool (
|
|
sizeof (
|
|
AML_TREE_ITERATOR_INTERNAL
|
|
)
|
|
);
|
|
if (InternalIterator == NULL) {
|
|
ASSERT (0);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
InternalIterator->InitialNode = Node;
|
|
InternalIterator->CurrentNode = Node;
|
|
InternalIterator->Mode = IteratorMode;
|
|
InternalIterator->Iterator.GetNode = AmlIteratorGetNode;
|
|
|
|
switch (InternalIterator->Mode) {
|
|
case EAmlIteratorLinear:
|
|
{
|
|
InternalIterator->Iterator.GetNext = AmlIteratorGetNextLinear;
|
|
InternalIterator->Iterator.GetPrevious = AmlIteratorGetPreviousLinear;
|
|
break;
|
|
}
|
|
case EAmlIteratorBranch:
|
|
{
|
|
InternalIterator->Iterator.GetNext = AmlIteratorGetNextBranch;
|
|
InternalIterator->Iterator.GetPrevious = AmlIteratorGetPreviousBranch;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
ASSERT (0);
|
|
FreePool (InternalIterator);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
} // switch
|
|
|
|
*IteratorPtr = &InternalIterator->Iterator;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Delete an iterator.
|
|
|
|
Note: The caller must have first initialized the iterator with the
|
|
AmlInitializeIterator () function.
|
|
|
|
@param [in] Iterator Pointer to an iterator.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlDeleteIterator (
|
|
IN AML_TREE_ITERATOR * Iterator
|
|
)
|
|
{
|
|
if (Iterator == NULL) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
FreePool (Iterator);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|