4 Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <Tree/AmlTree.h>
11 #include <AmlCoreInterface.h>
12 #include <Tree/AmlNode.h>
13 #include <Tree/AmlTreeTraversal.h>
14 #include <Utils/AmlUtility.h>
16 /** Get the parent node of the input Node.
18 @param [in] Node Pointer to a node.
20 @return The parent node of the input Node.
26 IN AML_NODE_HEADER
* Node
29 if (IS_AML_DATA_NODE (Node
) ||
30 IS_AML_OBJECT_NODE (Node
)) {
37 /** Get the root node from any node of the tree.
38 This is done by climbing up the tree until the root node is reached.
40 @param [in] Node Pointer to a node.
42 @return The root node of the tree.
48 IN CONST AML_NODE_HEADER
* Node
51 if (!IS_AML_NODE_VALID (Node
)) {
56 while (!IS_AML_ROOT_NODE (Node
)) {
58 if (!IS_AML_NODE_VALID (Node
)) {
63 return (AML_ROOT_NODE
*)Node
;
66 /** Get the node at the input Index in the fixed argument list of the input
69 @param [in] ObjectNode Pointer to an object node.
70 @param [in] Index The Index of the fixed argument to get.
72 @return The node at the input Index in the fixed argument list
73 of the input ObjectNode.
74 NULL otherwise, e.g. if the node is not an object node, or no
75 node is available at this Index.
80 IN AML_OBJECT_NODE
* ObjectNode
,
81 IN EAML_PARSE_INDEX Index
84 if (IS_AML_OBJECT_NODE (ObjectNode
)) {
85 if (Index
< (EAML_PARSE_INDEX
)AmlGetFixedArgumentCount (ObjectNode
)) {
86 return ObjectNode
->FixedArgs
[Index
];
93 /** Check whether the input Node is in the fixed argument list of its parent
96 If so, IndexPtr contains this Index.
98 @param [in] Node Pointer to a Node.
99 @param [out] IndexPtr Pointer holding the Index of the Node in
100 its parent's fixed argument list.
102 @retval TRUE The node is a fixed argument and the index
103 in IndexPtr is valid.
104 @retval FALSE The node is not a fixed argument.
108 AmlIsNodeFixedArgument (
109 IN CONST AML_NODE_HEADER
* Node
,
110 OUT EAML_PARSE_INDEX
* IndexPtr
113 AML_NODE_HEADER
* ParentNode
;
115 EAML_PARSE_INDEX Index
;
116 EAML_PARSE_INDEX MaxIndex
;
118 if ((IndexPtr
== NULL
) ||
119 (!IS_AML_DATA_NODE (Node
) &&
120 !IS_AML_OBJECT_NODE (Node
))) {
125 ParentNode
= AmlGetParent ((AML_NODE_HEADER
*)Node
);
126 if (IS_AML_ROOT_NODE (ParentNode
)) {
128 } else if (IS_AML_DATA_NODE (ParentNode
)) {
129 // Tree is inconsistent.
134 // Check whether the Node is in the fixed argument list.
135 MaxIndex
= (EAML_PARSE_INDEX
)AmlGetFixedArgumentCount (
136 (AML_OBJECT_NODE
*)ParentNode
138 for (Index
= EAmlParseIndexTerm0
; Index
< MaxIndex
; Index
++) {
139 if (AmlGetFixedArgument ((AML_OBJECT_NODE
*)ParentNode
, Index
) == Node
) {
148 /** Set the fixed argument of the ObjectNode at the Index to the NewNode.
150 It is the caller's responsibility to save the old node, if desired,
151 otherwise the reference to the old node will be lost.
152 If NewNode is not NULL, set its parent to ObjectNode.
154 @param [in] ObjectNode Pointer to an object node.
155 @param [in] Index Index in the fixed argument list of
156 the ObjectNode to set.
157 @param [in] NewNode Pointer to the NewNode.
158 Can be NULL, a data node or an object node.
160 @retval EFI_SUCCESS The function completed successfully.
161 @retval EFI_INVALID_PARAMETER Invalid parameter.
165 AmlSetFixedArgument (
166 IN AML_OBJECT_NODE
* ObjectNode
,
167 IN EAML_PARSE_INDEX Index
,
168 IN AML_NODE_HEADER
* NewNode
171 if (IS_AML_OBJECT_NODE (ObjectNode
) &&
172 (Index
<= (EAML_PARSE_INDEX
)AmlGetFixedArgumentCount (ObjectNode
)) &&
173 ((NewNode
== NULL
) ||
174 IS_AML_OBJECT_NODE (NewNode
) ||
175 IS_AML_DATA_NODE (NewNode
))) {
176 ObjectNode
->FixedArgs
[Index
] = NewNode
;
178 // If NewNode is a data node or an object node, set its parent.
179 if (NewNode
!= NULL
) {
180 NewNode
->Parent
= (AML_NODE_HEADER
*)ObjectNode
;
187 return EFI_INVALID_PARAMETER
;
190 /** If the given AML_NODE_HEADER has a variable list of arguments,
191 return a pointer to this list.
192 Return NULL otherwise.
194 @param [in] Node Pointer to the AML_NODE_HEADER to check.
196 @return The list of variable arguments if there is one.
201 AmlNodeGetVariableArgList (
202 IN CONST AML_NODE_HEADER
* Node
205 if (IS_AML_ROOT_NODE (Node
)) {
206 return &(((AML_ROOT_NODE
*)Node
)->VariableArgs
);
207 } else if (IS_AML_OBJECT_NODE (Node
)) {
208 return &(((AML_OBJECT_NODE
*)Node
)->VariableArgs
);
213 /** Remove the Node from its parent's variable list of arguments.
215 The function will fail if the Node is in its parent's fixed
217 The Node is not deleted. The deletion is done separately
220 @param [in] Node Pointer to a Node.
221 Must be a data node or an object node.
223 @retval EFI_SUCCESS The function completed successfully.
224 @retval EFI_INVALID_PARAMETER Invalid parameter.
228 AmlRemoveNodeFromVarArgList (
229 IN AML_NODE_HEADER
* Node
233 AML_NODE_HEADER
* ParentNode
;
236 if ((!IS_AML_DATA_NODE (Node
) &&
237 !IS_AML_OBJECT_NODE (Node
))) {
239 return EFI_INVALID_PARAMETER
;
242 ParentNode
= AmlGetParent (Node
);
243 if (!IS_AML_ROOT_NODE (ParentNode
) &&
244 !IS_AML_OBJECT_NODE (ParentNode
)) {
246 return EFI_INVALID_PARAMETER
;
249 // Check the node is in its parent variable list of arguments.
251 AmlNodeGetVariableArgList (ParentNode
),
254 return EFI_INVALID_PARAMETER
;
257 // Unlink Node from the tree.
258 RemoveEntryList (&Node
->Link
);
259 InitializeListHead (&Node
->Link
);
262 // Get the size of the node removed.
263 Status
= AmlComputeSize (Node
, &Size
);
264 if (EFI_ERROR (Status
)) {
269 // Propagate the information.
270 Status
= AmlPropagateInformation (ParentNode
, FALSE
, Size
, 1);
271 ASSERT_EFI_ERROR (Status
);
276 /** Detach the Node from the tree.
278 The function will fail if the Node is in its parent's fixed
280 The Node is not deleted. The deletion is done separately
283 @param [in] Node Pointer to a Node.
284 Must be a data node or an object node.
286 @retval EFI_SUCCESS The function completed successfully.
287 @retval EFI_INVALID_PARAMETER Invalid parameter.
292 IN AML_NODE_HEADER
* Node
295 return AmlRemoveNodeFromVarArgList (Node
);
298 /** Add the NewNode to the head of the variable list of arguments
301 @param [in] ParentNode Pointer to the parent node.
302 Must be a root or an object node.
303 @param [in] NewNode Pointer to the node to add.
305 @retval EFI_SUCCESS The function completed successfully.
306 @retval EFI_INVALID_PARAMETER Invalid parameter.
311 IN AML_NODE_HEADER
* ParentNode
,
312 IN AML_NODE_HEADER
* NewNode
317 LIST_ENTRY
* ChildrenList
;
319 // Check arguments and that NewNode is not already attached to a tree.
320 // ParentNode != Data Node AND NewNode != Root Node AND NewNode != attached.
321 if ((!IS_AML_ROOT_NODE (ParentNode
) &&
322 !IS_AML_OBJECT_NODE (ParentNode
)) ||
323 (!IS_AML_DATA_NODE (NewNode
) &&
324 !IS_AML_OBJECT_NODE (NewNode
)) ||
325 !AML_NODE_IS_DETACHED (NewNode
)) {
327 return EFI_INVALID_PARAMETER
;
330 // Insert it at the head of the list.
331 ChildrenList
= AmlNodeGetVariableArgList (ParentNode
);
332 if (ChildrenList
== NULL
) {
334 return EFI_INVALID_PARAMETER
;
337 InsertHeadList (ChildrenList
, &NewNode
->Link
);
338 NewNode
->Parent
= ParentNode
;
340 // Get the size of the NewNode.
341 Status
= AmlComputeSize (NewNode
, &NewSize
);
342 if (EFI_ERROR (Status
)) {
347 // Propagate the new information.
348 Status
= AmlPropagateInformation (ParentNode
, TRUE
, NewSize
, 1);
349 ASSERT_EFI_ERROR (Status
);
354 /** Add the NewNode to the tail of the variable list of arguments
357 NOTE: This is an internal function which does not propagate the size
358 when a new node is added.
360 @param [in] ParentNode Pointer to the parent node.
361 Must be a root or an object node.
362 @param [in] NewNode Pointer to the node to add.
364 @retval EFI_SUCCESS The function completed successfully.
365 @retval EFI_INVALID_PARAMETER Invalid parameter.
369 AmlVarListAddTailInternal (
370 IN AML_NODE_HEADER
* ParentNode
,
371 IN AML_NODE_HEADER
* NewNode
374 LIST_ENTRY
* ChildrenList
;
376 // Check arguments and that NewNode is not already attached to a tree.
377 // ParentNode != Data Node AND NewNode != Root Node AND NewNode != attached.
378 if ((!IS_AML_ROOT_NODE (ParentNode
) &&
379 !IS_AML_OBJECT_NODE (ParentNode
)) ||
380 (!IS_AML_DATA_NODE (NewNode
) &&
381 !IS_AML_OBJECT_NODE (NewNode
)) ||
382 !AML_NODE_IS_DETACHED (NewNode
)) {
384 return EFI_INVALID_PARAMETER
;
387 // Insert it at the tail of the list.
388 ChildrenList
= AmlNodeGetVariableArgList (ParentNode
);
389 if (ChildrenList
== NULL
) {
391 return EFI_INVALID_PARAMETER
;
394 InsertTailList (ChildrenList
, &NewNode
->Link
);
395 NewNode
->Parent
= ParentNode
;
400 /** Add the NewNode to the tail of the variable list of arguments
403 @param [in] ParentNode Pointer to the parent node.
404 Must be a root or an object node.
405 @param [in] NewNode Pointer to the node to add.
407 @retval EFI_SUCCESS The function completed successfully.
408 @retval EFI_INVALID_PARAMETER Invalid parameter.
413 IN AML_NODE_HEADER
* ParentNode
,
414 IN AML_NODE_HEADER
* NewNode
420 // Add the NewNode and check arguments.
421 Status
= AmlVarListAddTailInternal (ParentNode
, NewNode
);
422 if (EFI_ERROR (Status
)) {
427 // Get the size of the NewNode.
428 Status
= AmlComputeSize (NewNode
, &NewSize
);
429 if (EFI_ERROR (Status
)) {
434 // Propagate the new information.
435 Status
= AmlPropagateInformation (ParentNode
, TRUE
, NewSize
, 1);
436 ASSERT_EFI_ERROR (Status
);
441 /** Add the NewNode before the Node in the list of variable
442 arguments of the Node's parent.
444 @param [in] Node Pointer to a node.
445 Must be a root or an object node.
446 @param [in] NewNode Pointer to the node to add.
448 @retval EFI_SUCCESS The function completed successfully.
449 @retval EFI_INVALID_PARAMETER Invalid parameter.
453 AmlVarListAddBefore (
454 IN AML_NODE_HEADER
* Node
,
455 IN AML_NODE_HEADER
* NewNode
459 AML_NODE_HEADER
* ParentNode
;
462 // Check arguments and that NewNode is not already attached to a tree.
463 if ((!IS_AML_DATA_NODE (NewNode
) &&
464 !IS_AML_OBJECT_NODE (NewNode
)) ||
465 !AML_NODE_IS_DETACHED (NewNode
)) {
467 return EFI_INVALID_PARAMETER
;
470 ParentNode
= AmlGetParent (Node
);
471 if (!IS_AML_ROOT_NODE (ParentNode
) &&
472 !IS_AML_OBJECT_NODE (ParentNode
)) {
474 return EFI_INVALID_PARAMETER
;
477 // Insert it before the input Node.
478 InsertTailList (&Node
->Link
, &NewNode
->Link
);
479 NewNode
->Parent
= ParentNode
;
481 // Get the size of the NewNode.
482 Status
= AmlComputeSize (NewNode
, &NewSize
);
483 if (EFI_ERROR (Status
)) {
488 // Propagate the new information.
489 Status
= AmlPropagateInformation (ParentNode
, TRUE
, NewSize
, 1);
490 ASSERT_EFI_ERROR (Status
);
495 /** Add the NewNode after the Node in the variable list of arguments
496 of the Node's parent.
498 @param [in] Node Pointer to a node.
499 Must be a root or an object node.
500 @param [in] NewNode Pointer to the node to add.
502 @retval EFI_SUCCESS The function completed successfully.
503 @retval EFI_INVALID_PARAMETER Invalid parameter.
508 IN AML_NODE_HEADER
* Node
,
509 IN AML_NODE_HEADER
* NewNode
513 AML_NODE_HEADER
* ParentNode
;
516 // Check arguments and that NewNode is not already attached to a tree.
517 if ((!IS_AML_DATA_NODE (NewNode
) &&
518 !IS_AML_OBJECT_NODE (NewNode
)) ||
519 !AML_NODE_IS_DETACHED (NewNode
)) {
521 return EFI_INVALID_PARAMETER
;
524 ParentNode
= AmlGetParent (Node
);
525 if (!IS_AML_ROOT_NODE (ParentNode
) &&
526 !IS_AML_OBJECT_NODE (ParentNode
)) {
528 return EFI_INVALID_PARAMETER
;
531 // Insert the new node after the input Node.
532 InsertHeadList (&Node
->Link
, &NewNode
->Link
);
533 NewNode
->Parent
= ParentNode
;
535 // Get the size of the NewNode.
536 Status
= AmlComputeSize (NewNode
, &NewSize
);
537 if (EFI_ERROR (Status
)) {
542 // Propagate the new information.
543 Status
= AmlPropagateInformation (ParentNode
, TRUE
, NewSize
, 1);
544 ASSERT_EFI_ERROR (Status
);
549 /** Append a Resource Data node to the BufferOpNode.
551 The Resource Data node is added at the end of the variable
552 list of arguments of the BufferOpNode, but before the End Tag.
553 If no End Tag is found, the function returns an error.
555 @param [in] BufferOpNode Buffer node containing resource data elements.
556 @param [in] NewRdNode The new Resource Data node to add.
558 @retval EFI_SUCCESS The function completed successfully.
559 @retval EFI_INVALID_PARAMETER Invalid parameter.
564 IN AML_OBJECT_NODE
* BufferOpNode
,
565 IN AML_DATA_NODE
* NewRdNode
569 AML_DATA_NODE
* LastRdNode
;
571 if (!AmlNodeCompareOpCode (BufferOpNode
, AML_BUFFER_OP
, 0) ||
572 !IS_AML_DATA_NODE (NewRdNode
) ||
573 (NewRdNode
->DataType
!= EAmlNodeDataTypeResourceData
)) {
575 return EFI_INVALID_PARAMETER
;
578 // To avoid re-computing checksums, if a new resource data elements is
579 // added/removed/modified in a list of resource data elements, the AmlLib
580 // resets the checksum to 0.
581 // It is possible to have only one Resource Data in a BufferOp with
582 // no EndTag, but it should not be possible to add a new Resource Data
583 // in the list in this case.
584 Status
= AmlSetRdListCheckSum (BufferOpNode
, 0);
585 if (EFI_ERROR (Status
)) {
590 // Get the last Resource data node in the variable list of argument of the
591 // BufferOp node. This must be an EndTag, otherwise setting the checksum
592 // would have failed.
593 LastRdNode
= (AML_DATA_NODE
*)AmlGetPreviousVariableArgument (
594 (AML_NODE_HEADER
*)BufferOpNode
,
597 if ((LastRdNode
== NULL
) ||
598 !IS_AML_DATA_NODE (LastRdNode
) ||
599 (LastRdNode
->DataType
!= EAmlNodeDataTypeResourceData
)) {
601 return EFI_INVALID_PARAMETER
;
604 // Add NewRdNode before the EndTag.
605 Status
= AmlVarListAddBefore (
606 (AML_NODE_HEADER
*)LastRdNode
,
607 (AML_NODE_HEADER
*)NewRdNode
)
609 ASSERT_EFI_ERROR (Status
);
613 /** Replace the fixed argument at the Index of the ParentNode with the NewNode.
615 Note: This function unlinks the OldNode from the tree. It is the callers
616 responsibility to delete the OldNode if needed.
618 @param [in] ParentNode Pointer to the parent node.
619 Must be an object node.
620 @param [in] Index Index of the fixed argument to replace.
621 @param [in] NewNode The new node to insert.
622 Must be an object node or a data node.
624 @retval EFI_SUCCESS The function completed successfully.
625 @retval EFI_INVALID_PARAMETER Invalid parameter.
630 AmlReplaceFixedArgument (
631 IN AML_OBJECT_NODE
* ParentNode
,
632 IN EAML_PARSE_INDEX Index
,
633 IN AML_NODE_HEADER
* NewNode
638 AML_NODE_HEADER
* OldNode
;
641 AML_PARSE_FORMAT FixedArgType
;
643 // Check arguments and that NewNode is not already attached to a tree.
644 if (!IS_AML_OBJECT_NODE (ParentNode
) ||
645 (!IS_AML_DATA_NODE (NewNode
) &&
646 !IS_AML_OBJECT_NODE (NewNode
)) ||
647 !AML_NODE_IS_DETACHED (NewNode
)) {
649 return EFI_INVALID_PARAMETER
;
652 // Perform some compatibility checks between NewNode and OldNode.
653 FixedArgType
= ParentNode
->AmlByteEncoding
->Format
[Index
];
654 switch (FixedArgType
) {
655 case EAmlFieldPkgLen
:
657 // A FieldPkgLen can only have a parent node with the
658 // AML_IS_FIELD_ELEMENT flag.
659 if (!AmlNodeHasAttribute (
660 (AML_OBJECT_NODE
*)ParentNode
,
661 AML_HAS_FIELD_LIST
)) {
663 return EFI_INVALID_PARAMETER
;
675 // A uint, a name, a string and a FieldPkgLen can only be replaced by a
676 // data node of the same type.
677 // Note: This condition might be too strict, but safer.
678 if (!IS_AML_DATA_NODE (NewNode
) ||
679 (((AML_DATA_NODE
*)NewNode
)->DataType
!=
680 AmlTypeToNodeDataType (FixedArgType
))) {
682 return EFI_INVALID_PARAMETER
;
689 // If it's an object node, the grammar is too complex to do any check.
697 return EFI_INVALID_PARAMETER
;
702 // Replace the OldNode with the NewNode.
703 OldNode
= AmlGetFixedArgument (ParentNode
, Index
);
704 if (!IS_AML_NODE_VALID (OldNode
)) {
706 return EFI_INVALID_PARAMETER
;
709 // Unlink the old node.
710 // Note: This function unlinks the OldNode from the tree. It is the callers
711 // responsibility to delete the OldNode if needed.
712 OldNode
->Parent
= NULL
;
714 Status
= AmlSetFixedArgument (ParentNode
, Index
, NewNode
);
715 if (EFI_ERROR (Status
)) {
720 // Get the size of the OldNode.
721 Status
= AmlComputeSize (OldNode
, &OldSize
);
722 if (EFI_ERROR (Status
)) {
727 // Get the size of the NewNode.
728 Status
= AmlComputeSize (NewNode
, &NewSize
);
729 if (EFI_ERROR (Status
)) {
734 // Propagate the new information.
735 Status
= AmlPropagateInformation (
736 (AML_NODE_HEADER
*)ParentNode
,
737 (NewSize
> OldSize
) ? TRUE
: FALSE
,
738 (NewSize
> OldSize
) ? (NewSize
- OldSize
) : (OldSize
- NewSize
),
741 ASSERT_EFI_ERROR (Status
);
746 /** Replace the OldNode, which is in a variable list of arguments,
749 Note: This function unlinks the OldNode from the tree. It is the callers
750 responsibility to delete the OldNode if needed.
752 @param [in] OldNode Pointer to the node to replace.
753 Must be a data node or an object node.
754 @param [in] NewNode The new node to insert.
755 Must be a data node or an object node.
757 @retval EFI_SUCCESS The function completed successfully.
758 @retval EFI_INVALID_PARAMETER Invalid parameter.
762 AmlReplaceVariableArgument (
763 IN AML_NODE_HEADER
* OldNode
,
764 IN AML_NODE_HEADER
* NewNode
770 EAML_PARSE_INDEX Index
;
772 AML_DATA_NODE
* NewDataNode
;
773 AML_NODE_HEADER
* ParentNode
;
774 LIST_ENTRY
* NextLink
;
776 // Check arguments, that NewNode is not already attached to a tree,
777 // and that OldNode is attached and not in a fixed list of arguments.
778 if ((!IS_AML_DATA_NODE (OldNode
) &&
779 !IS_AML_OBJECT_NODE (OldNode
)) ||
780 (!IS_AML_DATA_NODE (NewNode
) &&
781 !IS_AML_OBJECT_NODE (NewNode
)) ||
782 !AML_NODE_IS_DETACHED (NewNode
) ||
783 AML_NODE_IS_DETACHED (OldNode
) ||
784 AmlIsNodeFixedArgument (OldNode
, &Index
)) {
786 return EFI_INVALID_PARAMETER
;
789 ParentNode
= AmlGetParent (OldNode
);
790 if (!IS_AML_ROOT_NODE (ParentNode
) &&
791 !IS_AML_OBJECT_NODE (ParentNode
)) {
793 return EFI_INVALID_PARAMETER
;
796 NewDataNode
= (AML_DATA_NODE
*)NewNode
;
798 // Check attributes if the parent node is an object node.
799 if (IS_AML_OBJECT_NODE (ParentNode
)) {
800 // A child node of a node with the HAS_CHILD flag must be either a
801 // data node or an object node. This has already been checked. So,
802 // check for other cases.
804 if (AmlNodeHasAttribute ((AML_OBJECT_NODE
*)ParentNode
, AML_HAS_BYTE_LIST
)) {
805 if (!IS_AML_DATA_NODE (NewNode
) ||
806 ((NewDataNode
->DataType
!= EAmlNodeDataTypeRaw
) &&
807 (NewDataNode
->DataType
!= EAmlNodeDataTypeResourceData
))) {
808 // A child node of a node with the BYTE_LIST flag must be a data node,
809 // containing raw data or a resource data.
811 return EFI_INVALID_PARAMETER
;
813 } else if (AmlNodeHasAttribute (
814 (AML_OBJECT_NODE
*)ParentNode
,
815 AML_HAS_FIELD_LIST
)) {
816 if (!AmlNodeHasAttribute (
817 (CONST AML_OBJECT_NODE
*)NewNode
,
818 AML_IS_FIELD_ELEMENT
)) {
819 // A child node of a node with the FIELD_LIST flag must be an object
820 // node with AML_IS_FIELD_ELEMENT flag.
822 return EFI_INVALID_PARAMETER
;
826 // Parent node is a root node.
827 // A root node cannot have a data node as its child.
828 if (!IS_AML_DATA_NODE (NewNode
)) {
830 return EFI_INVALID_PARAMETER
;
834 // Unlink OldNode from the tree.
835 NextLink
= RemoveEntryList (&OldNode
->Link
);
836 InitializeListHead (&OldNode
->Link
);
837 OldNode
->Parent
= NULL
;
840 InsertHeadList (NextLink
, &NewNode
->Link
);
841 NewNode
->Parent
= ParentNode
;
843 // Get the size of the OldNode.
844 Status
= AmlComputeSize (OldNode
, &OldSize
);
845 if (EFI_ERROR (Status
)) {
850 // Get the size of the NewNode.
851 Status
= AmlComputeSize (NewNode
, &NewSize
);
852 if (EFI_ERROR (Status
)) {
857 // Propagate the new information.
858 Status
= AmlPropagateInformation (
860 (NewSize
> OldSize
) ? TRUE
: FALSE
,
861 (NewSize
> OldSize
) ? (NewSize
- OldSize
) : (OldSize
- NewSize
),
864 ASSERT_EFI_ERROR (Status
);
869 /** Replace the OldNode by the NewNode.
871 Note: This function unlinks the OldNode from the tree. It is the callers
872 responsibility to delete the OldNode if needed.
874 @param [in] OldNode Pointer to the node to replace.
875 Must be a data node or an object node.
876 @param [in] NewNode The new node to insert.
877 Must be a data node or an object node.
879 @retval EFI_SUCCESS The function completed successfully.
880 @retval EFI_INVALID_PARAMETER Invalid parameter.
885 IN AML_NODE_HEADER
* OldNode
,
886 IN AML_NODE_HEADER
* NewNode
890 AML_NODE_HEADER
* ParentNode
;
891 EAML_PARSE_INDEX Index
;
893 // Check arguments and that NewNode is not already attached to a tree.
894 if ((!IS_AML_DATA_NODE (OldNode
) &&
895 !IS_AML_OBJECT_NODE (OldNode
)) ||
896 (!IS_AML_DATA_NODE (NewNode
) &&
897 !IS_AML_OBJECT_NODE (NewNode
)) ||
898 !AML_NODE_IS_DETACHED (NewNode
)) {
900 return EFI_INVALID_PARAMETER
;
903 // ParentNode can be a root node or an object node.
904 ParentNode
= AmlGetParent (OldNode
);
905 if (!IS_AML_ROOT_NODE (ParentNode
) &&
906 !IS_AML_OBJECT_NODE (ParentNode
)) {
908 return EFI_INVALID_PARAMETER
;
911 if (AmlIsNodeFixedArgument (OldNode
, &Index
)) {
912 // OldNode is in its parent's fixed argument list at the Index.
913 Status
= AmlReplaceFixedArgument (
914 (AML_OBJECT_NODE
*)ParentNode
,
918 if (EFI_ERROR (Status
)) {
923 // OldNode is not in its parent's fixed argument list.
924 // It must be in its variable list of arguments.
925 Status
= AmlReplaceVariableArgument (OldNode
, NewNode
);
926 ASSERT_EFI_ERROR (Status
);
932 /** Delete a Node and its children.
934 The Node must be removed from the tree first,
935 or must be the root node.
937 @param [in] Node Pointer to the node to delete.
939 @retval EFI_SUCCESS The function completed successfully.
940 @retval EFI_INVALID_PARAMETER Invalid parameter.
945 IN AML_NODE_HEADER
* Node
950 EAML_PARSE_INDEX Index
;
951 EAML_PARSE_INDEX MaxIndex
;
953 AML_NODE_HEADER
* Arg
;
954 LIST_ENTRY
* StartLink
;
955 LIST_ENTRY
* CurrentLink
;
956 LIST_ENTRY
* NextLink
;
958 // Check that the node being deleted is unlinked.
959 // When removing the node, its parent pointer and
960 // its lists data structure are reset with
961 // InitializeListHead. Thus it must be detached
962 // from the tree to avoid memory leaks.
963 if (!IS_AML_NODE_VALID (Node
) ||
964 !AML_NODE_IS_DETACHED (Node
)) {
966 return EFI_INVALID_PARAMETER
;
969 // 1. Recursively detach and delete the fixed arguments.
970 // Iterate through the fixed list of arguments.
971 if (IS_AML_OBJECT_NODE (Node
)) {
972 MaxIndex
= (EAML_PARSE_INDEX
)AmlGetFixedArgumentCount (
973 (AML_OBJECT_NODE
*)Node
975 for (Index
= EAmlParseIndexTerm0
; Index
< MaxIndex
; Index
++) {
976 Arg
= AmlGetFixedArgument ((AML_OBJECT_NODE
*)Node
, Index
);
978 // A fixed argument is missing. The tree is inconsistent.
979 // Note: During CodeGeneration, the fixed arguments should be set
980 // with an incrementing index, and then the variable arguments
981 // should be added. This allows to free as many nodes as
982 // possible if a crash occurs.
984 return EFI_INVALID_PARAMETER
;
987 // Remove the node from the fixed argument list.
989 Status
= AmlSetFixedArgument ((AML_OBJECT_NODE
*)Node
, Index
, NULL
);
990 if (EFI_ERROR (Status
)) {
995 Status
= AmlDeleteTree (Arg
);
996 if (EFI_ERROR (Status
)) {
1003 // 2. Recursively detach and delete the variable arguments.
1004 // Iterate through the variable list of arguments.
1005 StartLink
= AmlNodeGetVariableArgList (Node
);
1006 if (StartLink
!= NULL
) {
1007 NextLink
= StartLink
->ForwardLink
;
1008 while (NextLink
!= StartLink
) {
1009 CurrentLink
= NextLink
;
1011 // Unlink the node from the tree.
1012 NextLink
= RemoveEntryList (CurrentLink
);
1013 InitializeListHead (CurrentLink
);
1014 ((AML_NODE_HEADER
*)CurrentLink
)->Parent
= NULL
;
1016 Status
= AmlDeleteTree ((AML_NODE_HEADER
*)CurrentLink
);
1017 if (EFI_ERROR (Status
)) {
1024 // 3. Delete the node.
1025 Status
= AmlDeleteNode (Node
);
1026 ASSERT_EFI_ERROR (Status
);