4 Copyright (c) 2019 - 2021, Arm Limited. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <Utils/AmlUtility.h>
11 #include <AmlCoreInterface.h>
12 #include <Tree/AmlNode.h>
13 #include <Tree/AmlTree.h>
15 /** This function computes and updates the ACPI table checksum.
17 @param [in] AcpiTable Pointer to an Acpi table.
19 @retval EFI_SUCCESS The function completed successfully.
20 @retval EFI_INVALID_PARAMETER Invalid parameter.
24 AcpiPlatformChecksum (
25 IN EFI_ACPI_DESCRIPTION_HEADER
*AcpiTable
32 if (AcpiTable
== NULL
) {
34 return EFI_INVALID_PARAMETER
;
37 Ptr
= (UINT8
*)AcpiTable
;
38 Size
= AcpiTable
->Length
;
41 // Set the checksum field to 0 first.
42 AcpiTable
->Checksum
= 0;
44 // Compute the checksum.
45 while ((Size
--) != 0) {
46 Sum
= (UINT8
)(Sum
+ (*Ptr
++));
50 AcpiTable
->Checksum
= (UINT8
)(0xFF - Sum
+ 1);
55 /** A callback function that computes the size of a Node and adds it to the
56 Size pointer stored in the Context.
57 Calling this function on the root node will compute the total size of the
60 @param [in] Node Node to compute the size.
61 @param [in, out] Context Pointer holding the computed size.
63 @param [in, out] Status Pointer holding:
64 - At entry, the Status returned by the
65 last call to this exact function during
67 - At exit, he returned status of the
68 call to this function.
69 Optional, can be NULL.
71 @retval TRUE if the enumeration can continue or has finished without
73 @retval FALSE if the enumeration needs to stopped or has stopped.
78 AmlComputeSizeCallback (
79 IN AML_NODE_HEADER
*Node
,
81 IN OUT EFI_STATUS
*Status OPTIONAL
85 EAML_PARSE_INDEX IndexPtr
;
86 CONST AML_OBJECT_NODE
*ParentNode
;
88 if (!IS_AML_NODE_VALID (Node
) ||
93 *Status
= EFI_INVALID_PARAMETER
;
99 // Ignore the second fixed argument of method invocation nodes
100 // as the information stored there (the argument count) is not in the
101 // ACPI specification.
102 ParentNode
= (CONST AML_OBJECT_NODE
*)AmlGetParent (Node
);
103 if (IS_AML_OBJECT_NODE (ParentNode
) &&
104 AmlNodeCompareOpCode (ParentNode
, AML_METHOD_INVOC_OP
, 0) &&
105 AmlIsNodeFixedArgument (Node
, &IndexPtr
))
107 if (IndexPtr
== EAmlParseIndexTerm1
) {
108 if (Status
!= NULL
) {
109 *Status
= EFI_SUCCESS
;
116 Size
= *((UINT32
*)Context
);
118 if (IS_AML_DATA_NODE (Node
)) {
119 Size
+= ((AML_DATA_NODE
*)Node
)->Size
;
120 } else if (IS_AML_OBJECT_NODE (Node
) &&
121 !AmlNodeHasAttribute (
122 (CONST AML_OBJECT_NODE
*)Node
,
126 // Ignore pseudo-opcodes as they are not part of the
127 // ACPI specification.
129 Size
+= (((AML_OBJECT_NODE
*)Node
)->AmlByteEncoding
->OpCode
==
132 // Add the size of the PkgLen.
133 if (AmlNodeHasAttribute (
134 (AML_OBJECT_NODE
*)Node
,
138 Size
+= AmlComputePkgLengthWidth (((AML_OBJECT_NODE
*)Node
)->PkgLen
);
142 // Check for overflow.
143 // The root node has a null size, thus the strict comparison.
144 if (*((UINT32
*)Context
) > Size
) {
146 *Status
= EFI_INVALID_PARAMETER
;
150 *((UINT32
*)Context
) = Size
;
152 if (Status
!= NULL
) {
153 *Status
= EFI_SUCCESS
;
159 /** Compute the size of a tree/sub-tree.
161 @param [in] Node Node to compute the size.
162 @param [in, out] Size Pointer holding the computed size.
164 @retval EFI_SUCCESS The function completed successfully.
165 @retval EFI_INVALID_PARAMETER Invalid parameter.
170 IN CONST AML_NODE_HEADER
*Node
,
176 if (!IS_AML_NODE_VALID (Node
) ||
180 return EFI_INVALID_PARAMETER
;
186 (AML_NODE_HEADER
*)Node
,
187 AmlComputeSizeCallback
,
195 /** Get the value contained in an integer node.
197 @param [in] Node Pointer to an integer node.
198 Must be an object node.
199 @param [out] Value Value contained in the integer node.
201 @retval EFI_SUCCESS The function completed successfully.
202 @retval EFI_INVALID_PARAMETER Invalid parameter.
206 AmlNodeGetIntegerValue (
207 IN AML_OBJECT_NODE
*Node
,
211 AML_DATA_NODE
*DataNode
;
213 if ((!IsIntegerNode (Node
) &&
214 !IsSpecialIntegerNode (Node
)) ||
218 return EFI_INVALID_PARAMETER
;
221 // For ZeroOp and OneOp, there is no data node.
222 if (IsSpecialIntegerNode (Node
)) {
223 if (AmlNodeCompareOpCode (Node
, AML_ZERO_OP
, 0)) {
225 } else if (AmlNodeCompareOpCode (Node
, AML_ONE_OP
, 0)) {
228 // OnesOp cannot be handled: it represents a maximum value.
230 return EFI_INVALID_PARAMETER
;
236 // For integer nodes, the value is in the first fixed argument.
237 DataNode
= (AML_DATA_NODE
*)Node
->FixedArgs
[EAmlParseIndexTerm0
];
238 if (!IS_AML_DATA_NODE (DataNode
) ||
239 (DataNode
->DataType
!= EAmlNodeDataTypeUInt
))
242 return EFI_INVALID_PARAMETER
;
245 switch (DataNode
->Size
) {
248 *Value
= *((UINT8
*)(DataNode
->Buffer
));
253 *Value
= *((UINT16
*)(DataNode
->Buffer
));
258 *Value
= *((UINT32
*)(DataNode
->Buffer
));
263 *Value
= *((UINT64
*)(DataNode
->Buffer
));
269 return EFI_INVALID_PARAMETER
;
276 /** Replace a Zero (AML_ZERO_OP) or One (AML_ONE_OP) object node
277 with a byte integer (AML_BYTE_PREFIX) object node having the same value.
279 @param [in] Node Pointer to an integer node.
280 Must be an object node having ZeroOp or OneOp.
282 @retval EFI_SUCCESS The function completed successfully.
283 @retval EFI_INVALID_PARAMETER Invalid parameter.
288 AmlUnwindSpecialInteger (
289 IN AML_OBJECT_NODE
*Node
294 AML_DATA_NODE
*NewDataNode
;
296 CONST AML_BYTE_ENCODING
*ByteEncoding
;
298 if (!IsSpecialIntegerNode (Node
)) {
300 return EFI_INVALID_PARAMETER
;
304 if (AmlNodeCompareOpCode (Node
, AML_ZERO_OP
, 0)) {
306 } else if (AmlNodeCompareOpCode (Node
, AML_ONE_OP
, 0)) {
309 // OnesOp cannot be handled: it represents a maximum value.
311 return EFI_INVALID_PARAMETER
;
314 Status
= AmlCreateDataNode (
315 EAmlNodeDataTypeUInt
,
318 (AML_DATA_NODE
**)&NewDataNode
320 if (EFI_ERROR (Status
)) {
325 // Change the encoding of the special node to a ByteOp encoding.
326 ByteEncoding
= AmlGetByteEncodingByOpCode (AML_BYTE_PREFIX
, 0);
327 if (ByteEncoding
== NULL
) {
329 Status
= EFI_INVALID_PARAMETER
;
333 // Update the ByteEncoding from ZERO_OP/ONE_OP to AML_BYTE_PREFIX.
334 Node
->AmlByteEncoding
= ByteEncoding
;
336 // Add the data node as the first fixed argument of the ByteOp object.
337 Status
= AmlSetFixedArgument (
338 (AML_OBJECT_NODE
*)Node
,
340 (AML_NODE_HEADER
*)NewDataNode
342 if (EFI_ERROR (Status
)) {
350 AmlDeleteTree ((AML_NODE_HEADER
*)NewDataNode
);
354 /** Set the value contained in an integer node.
356 The OpCode is updated accordingly to the new value
357 (e.g.: If the original value was a UINT8 value, then the OpCode
358 would be AML_BYTE_PREFIX. If it the new value is a UINT16
359 value then the OpCode will be updated to AML_WORD_PREFIX).
361 @param [in] Node Pointer to an integer node.
362 Must be an object node.
363 @param [in] NewValue New value to write in the integer node.
364 @param [out] ValueWidthDiff Difference in number of bytes used to store
368 @retval EFI_SUCCESS The function completed successfully.
369 @retval EFI_INVALID_PARAMETER Invalid parameter.
370 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
374 AmlNodeSetIntegerValue (
375 IN AML_OBJECT_NODE
*Node
,
377 OUT INT8
*ValueWidthDiff
381 AML_DATA_NODE
*DataNode
;
386 if ((!IsIntegerNode (Node
) &&
387 !IsSpecialIntegerNode (Node
)) ||
388 (ValueWidthDiff
== NULL
))
391 return EFI_INVALID_PARAMETER
;
395 // For ZeroOp and OneOp, there is no data node.
396 // Thus the object node is converted to a byte object node holding 0 or 1.
397 if (IsSpecialIntegerNode (Node
)) {
400 Node
->AmlByteEncoding
= AmlGetByteEncodingByOpCode (AML_ZERO_OP
, 0);
403 Node
->AmlByteEncoding
= AmlGetByteEncodingByOpCode (AML_ONE_OP
, 0);
407 Status
= AmlUnwindSpecialInteger (Node
);
408 if (EFI_ERROR (Status
)) {
413 // The AmlUnwindSpecialInteger functions converts a special integer
414 // node to a UInt8/Byte data node. Thus, the size increments by one:
415 // special integer are encoded as one byte (the opcode only) while byte
416 // integers are encoded as two bytes (the opcode + the value).
417 *ValueWidthDiff
+= sizeof (UINT8
);
420 } // IsSpecialIntegerNode (Node)
422 // For integer nodes, the value is in the first fixed argument.
423 DataNode
= (AML_DATA_NODE
*)Node
->FixedArgs
[EAmlParseIndexTerm0
];
424 if (!IS_AML_DATA_NODE (DataNode
) ||
425 (DataNode
->DataType
!= EAmlNodeDataTypeUInt
))
428 return EFI_INVALID_PARAMETER
;
431 // The value can be encoded with a special 0 or 1 OpCode.
432 // The AML_ONES_OP is not handled.
434 NewOpCode
= (NewValue
== 0) ? AML_ZERO_OP
: AML_ONE_OP
;
435 Node
->AmlByteEncoding
= AmlGetByteEncodingByOpCode (NewOpCode
, 0);
437 // The value is encoded with a AML_ZERO_OP or AML_ONE_OP.
438 // This means there is no need for a DataNode containing the value.
439 // The change in size is equal to the size of the DataNode's buffer.
440 *ValueWidthDiff
= -((INT8
)DataNode
->Size
);
442 // Detach and free the DataNode containing the integer value.
443 DataNode
->NodeHeader
.Parent
= NULL
;
444 Node
->FixedArgs
[EAmlParseIndexTerm0
] = NULL
;
445 Status
= AmlDeleteNode ((AML_NODE_HEADER
*)DataNode
);
446 if (EFI_ERROR (Status
)) {
454 // Check the number of bits needed to represent the value.
455 if (NewValue
> MAX_UINT32
) {
457 NewOpCode
= AML_QWORD_PREFIX
;
459 } else if (NewValue
> MAX_UINT16
) {
461 NewOpCode
= AML_DWORD_PREFIX
;
463 } else if (NewValue
> MAX_UINT8
) {
465 NewOpCode
= AML_WORD_PREFIX
;
469 NewOpCode
= AML_BYTE_PREFIX
;
473 *ValueWidthDiff
+= (INT8
)(NumberOfBytes
- DataNode
->Size
);
475 // Update the ByteEncoding as it may have changed between [8 .. 64] bits.
476 Node
->AmlByteEncoding
= AmlGetByteEncodingByOpCode (NewOpCode
, 0);
477 if (Node
->AmlByteEncoding
== NULL
) {
479 return EFI_INVALID_PARAMETER
;
482 // Free the old DataNode buffer and allocate a buffer with the right size
483 // to store the new data.
484 if (*ValueWidthDiff
!= 0) {
485 FreePool (DataNode
->Buffer
);
486 DataNode
->Buffer
= AllocateZeroPool (NumberOfBytes
);
487 if (DataNode
->Buffer
== NULL
) {
489 return EFI_OUT_OF_RESOURCES
;
492 DataNode
->Size
= NumberOfBytes
;
495 // Write the new value.
496 CopyMem (DataNode
->Buffer
, &NewValue
, NumberOfBytes
);
501 /** Increment/decrement the value contained in the IntegerNode.
503 @param [in] IntegerNode Pointer to an object node containing
505 @param [in] IsIncrement Choose the operation to do:
506 - TRUE: Increment the Node's size and
508 - FALSE: Decrement the Node's size and
510 @param [in] Diff Value to add/subtract to the integer.
511 @param [out] ValueWidthDiff When modifying the integer, it can be
512 promoted/demoted, e.g. from UINT8 to UINT16.
513 Stores the change in width.
516 @retval EFI_SUCCESS The function completed successfully.
517 @retval EFI_INVALID_PARAMETER Invalid parameter.
522 AmlNodeUpdateIntegerValue (
523 IN AML_OBJECT_NODE
*IntegerNode
,
524 IN BOOLEAN IsIncrement
,
526 OUT INT8
*ValueWidthDiff
532 if (ValueWidthDiff
== NULL
) {
534 return EFI_INVALID_PARAMETER
;
537 // Get the current value.
538 // Checks on the IntegerNode are done in the call.
539 Status
= AmlNodeGetIntegerValue (IntegerNode
, &Value
);
540 if (EFI_ERROR (Status
)) {
545 // Check for UINT64 over/underflow.
546 if ((IsIncrement
&& (Value
> (MAX_UINT64
- Diff
))) ||
547 (!IsIncrement
&& (Value
< Diff
)))
550 return EFI_INVALID_PARAMETER
;
553 // Compute the new value.
560 Status
= AmlNodeSetIntegerValue (
565 ASSERT_EFI_ERROR (Status
);
569 /** Propagate the size information up the tree.
571 The length of the ACPI table is updated in the RootNode,
572 but not the checksum.
574 @param [in] Node Pointer to a node.
575 Must be a root node or an object node.
576 @param [in] IsIncrement Choose the operation to do:
577 - TRUE: Increment the Node's size and
579 - FALSE: Decrement the Node's size and
581 @param [in] Diff Value to add/subtract to the Node's size.
583 @retval EFI_SUCCESS The function completed successfully.
584 @retval EFI_INVALID_PARAMETER Invalid parameter.
590 IN AML_NODE_HEADER
*Node
,
591 IN BOOLEAN IsIncrement
,
596 AML_OBJECT_NODE
*ObjectNode
;
597 AML_NODE_HEADER
*ParentNode
;
600 UINT32 InitialPkgLenWidth
;
601 UINT32 NewPkgLenWidth
;
602 UINT32 ReComputedPkgLenWidth
;
603 INT8 FieldWidthChange
;
605 if (!IS_AML_OBJECT_NODE (Node
) &&
606 !IS_AML_ROOT_NODE (Node
))
609 return EFI_INVALID_PARAMETER
;
612 if (IS_AML_OBJECT_NODE (Node
)) {
613 ObjectNode
= (AML_OBJECT_NODE
*)Node
;
615 // For BufferOp, the buffer size is stored in BufferSize. Therefore,
616 // BufferOp needs special handling to update the BufferSize.
617 // BufferSize must be updated before the PkgLen to accommodate any
618 // increment resulting from the update of the BufferSize.
619 // DefBuffer := BufferOp PkgLength BufferSize ByteList
621 // BufferSize := TermArg => Integer
622 if (AmlNodeCompareOpCode (ObjectNode
, AML_BUFFER_OP
, 0)) {
623 // First fixed argument of BufferOp is an integer (BufferSize)
624 // (can be a BYTE, WORD, DWORD or QWORD).
625 // BufferSize is an object node.
626 Status
= AmlNodeUpdateIntegerValue (
627 (AML_OBJECT_NODE
*)AmlGetFixedArgument (
635 if (EFI_ERROR (Status
)) {
640 // FieldWidthChange is an integer.
641 // It must be positive if IsIncrement is TRUE, negative otherwise.
643 (FieldWidthChange
< 0)) ||
645 (FieldWidthChange
> 0)))
648 return EFI_INVALID_PARAMETER
;
651 // Check for UINT32 overflow.
652 if (*Diff
> (MAX_UINT32
- (UINT32
)ABS (FieldWidthChange
))) {
654 return EFI_INVALID_PARAMETER
;
657 // Update Diff if the field width changed.
658 *Diff
= (UINT32
)(*Diff
+ ABS (FieldWidthChange
));
659 } // AML_BUFFER_OP node.
661 // Update the PgkLen.
662 // Needs to be done at last to reflect the potential field width changes.
663 if (AmlNodeHasAttribute (ObjectNode
, AML_HAS_PKG_LENGTH
)) {
664 Value
= ObjectNode
->PkgLen
;
666 // Subtract the size of the PkgLen encoding. The size of the PkgLen
667 // encoding must be computed after having updated Value.
668 InitialPkgLenWidth
= AmlComputePkgLengthWidth (Value
);
669 Value
-= InitialPkgLenWidth
;
671 // Check for an over/underflows.
672 // PkgLen is a 28 bit value, cf 20.2.4 Package Length Encoding
673 // i.e. the maximum value is (2^28 - 1) = ((BIT0 << 28) - 1).
674 if ((IsIncrement
&& ((((BIT0
<< 28) - 1) - Value
) < *Diff
)) ||
675 (!IsIncrement
&& (Value
< *Diff
)))
678 return EFI_INVALID_PARAMETER
;
688 // Compute the new PkgLenWidth.
689 NewPkgLenWidth
= AmlComputePkgLengthWidth (Value
);
690 if (NewPkgLenWidth
== 0) {
692 return EFI_INVALID_PARAMETER
;
695 // Add it to the Value.
696 Value
+= NewPkgLenWidth
;
698 // Check that adding the PkgLenWidth didn't trigger a domino effect,
699 // increasing the encoding width of the PkgLen again.
700 // The PkgLen is encoded on at most 4 bytes. It is possible to increase
701 // the PkgLen width if its encoding is on less than 3 bytes.
702 ReComputedPkgLenWidth
= AmlComputePkgLengthWidth (Value
);
703 if (ReComputedPkgLenWidth
!= NewPkgLenWidth
) {
704 if ((ReComputedPkgLenWidth
!= 0) &&
705 (ReComputedPkgLenWidth
< 4))
707 // No need to recompute the PkgLen since a new threshold cannot
708 // be reached by incrementing the value by one.
712 return EFI_INVALID_PARAMETER
;
716 *Diff
+= (InitialPkgLenWidth
> ReComputedPkgLenWidth
) ?
717 (InitialPkgLenWidth
- ReComputedPkgLenWidth
) :
718 (ReComputedPkgLenWidth
- InitialPkgLenWidth
);
719 ObjectNode
->PkgLen
= Value
;
722 // During CodeGeneration, the tree is incomplete and
723 // there is no root node at the top of the tree. Stop
724 // propagating the new size when finding a root node
725 // OR when a NULL parent is found.
726 ParentNode
= AmlGetParent ((AML_NODE_HEADER
*)Node
);
727 if (ParentNode
!= NULL
) {
728 // Propagate the size up the tree.
729 Status
= AmlPropagateSize (
734 if (EFI_ERROR (Status
)) {
739 } else if (IS_AML_ROOT_NODE (Node
)) {
740 // Update the length field in the SDT header.
741 Value
= ((AML_ROOT_NODE
*)Node
)->SdtHeader
->Length
;
743 // Check for an over/underflows.
744 if ((IsIncrement
&& (Value
> (MAX_UINT32
- *Diff
))) ||
745 (!IsIncrement
&& (Value
< *Diff
)))
748 return EFI_INVALID_PARAMETER
;
758 ((AML_ROOT_NODE
*)Node
)->SdtHeader
->Length
= Value
;
764 /** Propagate the node count information up the tree.
766 @param [in] ObjectNode Pointer to an object node.
767 @param [in] IsIncrement Choose the operation to do:
768 - TRUE: Increment the Node's size and
770 - FALSE: Decrement the Node's size and
772 @param [in] NodeCount Number of nodes added/removed (depends on the
774 @param [out] FieldWidthChange When modifying the integer, it can be
775 promoted/demoted, e.g. from UINT8 to UINT16.
776 Stores the change in width.
779 @retval EFI_SUCCESS The function completed successfully.
780 @retval EFI_INVALID_PARAMETER Invalid parameter.
785 AmlPropagateNodeCount (
786 IN AML_OBJECT_NODE
*ObjectNode
,
787 IN BOOLEAN IsIncrement
,
789 OUT INT8
*FieldWidthChange
794 AML_NODE_HEADER
*NodeCountArg
;
797 // Currently there is no use case where (NodeCount > 1).
798 if (!IS_AML_OBJECT_NODE (ObjectNode
) ||
799 (FieldWidthChange
== NULL
) ||
803 return EFI_INVALID_PARAMETER
;
806 *FieldWidthChange
= 0;
808 // Update the number of elements stored in PackageOp and VarPackageOp.
809 // The number of elements is stored as the first fixed argument.
810 // DefPackage := PackageOp PkgLength NumElements PackageElementList
812 // DefVarPackage := VarPackageOp PkgLength VarNumElements PackageElementList
813 // VarPackageOp := 0x13
814 // NumElements := ByteData
815 // VarNumElements := TermArg => Integer
816 NodeCountArg
= AmlGetFixedArgument (ObjectNode
, EAmlParseIndexTerm0
);
817 if (AmlNodeCompareOpCode (ObjectNode
, AML_PACKAGE_OP
, 0)) {
818 // First fixed argument of PackageOp stores the number of elements
819 // in the package. It is an UINT8.
821 // Check for over/underflow.
822 CurrNodeCount
= *(((AML_DATA_NODE
*)NodeCountArg
)->Buffer
);
823 if ((IsIncrement
&& (CurrNodeCount
== MAX_UINT8
)) ||
824 (!IsIncrement
&& (CurrNodeCount
== 0)))
827 return EFI_INVALID_PARAMETER
;
830 // Update the node count in the DataNode.
831 CurrNodeCount
= IsIncrement
? (CurrNodeCount
+ 1) : (CurrNodeCount
- 1);
832 *(((AML_DATA_NODE
*)NodeCountArg
)->Buffer
) = CurrNodeCount
;
833 } else if (AmlNodeCompareOpCode (ObjectNode
, AML_VAR_PACKAGE_OP
, 0)) {
834 // First fixed argument of PackageOp stores the number of elements
835 // in the package. It is an integer (can be a BYTE, WORD, DWORD, QWORD).
836 Status
= AmlNodeUpdateIntegerValue (
837 (AML_OBJECT_NODE
*)NodeCountArg
,
842 if (EFI_ERROR (Status
)) {
851 /** Propagate information up the tree.
853 The information can be a new size, a new number of arguments.
855 @param [in] Node Pointer to a node.
856 Must be a root node or an object node.
857 @param [in] IsIncrement Choose the operation to do:
858 - TRUE: Increment the Node's size and
860 - FALSE: Decrement the Node's size and
862 @param [in] Diff Value to add/subtract to the Node's size.
863 @param [in] NodeCount Number of nodes added/removed.
865 @retval EFI_SUCCESS The function completed successfully.
866 @retval EFI_INVALID_PARAMETER Invalid parameter.
870 AmlPropagateInformation (
871 IN AML_NODE_HEADER
*Node
,
872 IN BOOLEAN IsIncrement
,
878 INT8 FieldWidthChange
;
880 // Currently there is no use case where (NodeCount > 1).
881 if ((!IS_AML_ROOT_NODE (Node
) &&
882 !IS_AML_OBJECT_NODE (Node
)) ||
886 return EFI_INVALID_PARAMETER
;
889 // Propagate the node count first as it may change the number of bytes
890 // needed to store the node count, and then impact FieldWidthChange.
891 if ((NodeCount
!= 0) &&
892 IS_AML_OBJECT_NODE (Node
))
894 Status
= AmlPropagateNodeCount (
895 (AML_OBJECT_NODE
*)Node
,
900 if (EFI_ERROR (Status
)) {
905 // Propagate the potential field width change.
906 // Maximum change is between UINT8/UINT64: 8 bytes.
907 if ((ABS (FieldWidthChange
) > 8) ||
909 ((FieldWidthChange
< 0) ||
910 ((Diff
+ (UINT8
)FieldWidthChange
) > MAX_UINT32
))) ||
912 ((FieldWidthChange
> 0) ||
913 (Diff
< (UINT32
)ABS (FieldWidthChange
)))))
916 return EFI_INVALID_PARAMETER
;
919 Diff
= (UINT32
)(Diff
+ (UINT8
)ABS (FieldWidthChange
));
922 // Diff can be zero if some data is updated without modifying the data size.
924 Status
= AmlPropagateSize (Node
, IsIncrement
, &Diff
);
925 if (EFI_ERROR (Status
)) {
934 /** Find and set the EndTag's Checksum of a list of Resource Data elements.
936 Lists of Resource Data elements end with an EndTag (most of the time). This
937 function finds the EndTag (if present) in a list of Resource Data elements
938 and sets the checksum.
940 ACPI 6.4, s6.4.2.9 "End Tag":
941 "This checksum is generated such that adding it to the sum of all the data
942 bytes will produce a zero sum."
943 "If the checksum field is zero, the resource data is treated as if the
944 checksum operation succeeded. Configuration proceeds normally."
946 To avoid re-computing checksums, if a new resource data elements is
947 added/removed/modified in a list of resource data elements, the AmlLib
948 resets the checksum to 0.
950 @param [in] BufferOpNode Node having a list of Resource Data elements.
951 @param [in] CheckSum CheckSum to store in the EndTag.
952 To ignore/avoid computing the checksum,
955 @retval EFI_SUCCESS The function completed successfully.
956 @retval EFI_INVALID_PARAMETER Invalid parameter.
957 @retval EFI_NOT_FOUND No EndTag found.
961 AmlSetRdListCheckSum (
962 IN AML_OBJECT_NODE
*BufferOpNode
,
967 AML_DATA_NODE
*LastRdNode
;
968 AML_RD_HEADER RdDataType
;
970 if (!AmlNodeCompareOpCode (BufferOpNode
, AML_BUFFER_OP
, 0)) {
972 return EFI_INVALID_PARAMETER
;
975 // Get the last Resource data node in the variable list of
976 // argument of the BufferOp node.
977 LastRdNode
= (AML_DATA_NODE
*)AmlGetPreviousVariableArgument (
978 (AML_NODE_HEADER
*)BufferOpNode
,
981 if ((LastRdNode
== NULL
) ||
982 !IS_AML_DATA_NODE (LastRdNode
) ||
983 (LastRdNode
->DataType
!= EAmlNodeDataTypeResourceData
))
986 return EFI_INVALID_PARAMETER
;
989 Status
= AmlGetResourceDataType (LastRdNode
, &RdDataType
);
990 if (EFI_ERROR (Status
)) {
995 // Check the LastRdNode is an EndTag.
996 // It is possible to have only one Resource Data in a BufferOp with
997 // no EndTag. Return EFI_NOT_FOUND is such case.
998 if (!AmlRdCompareDescId (
1000 AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME
)
1004 return EFI_NOT_FOUND
;
1007 Status
= AmlRdSetEndTagChecksum (LastRdNode
->Buffer
, CheckSum
);
1008 ASSERT_EFI_ERROR (Status
);