4 Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <AmlNodeDefines.h>
11 #include <AmlCoreInterface.h>
12 #include <ResourceData/AmlResourceData.h>
13 #include <String/AmlString.h>
14 #include <Tree/AmlNode.h>
15 #include <Tree/AmlTree.h>
16 #include <Utils/AmlUtility.h>
18 /** Returns the tree node type (Root/Object/Data).
20 @param [in] Node Pointer to a Node.
22 @return The node type.
23 EAmlNodeUnknown if invalid parameter.
28 IN AML_NODE_HEADER
*Node
31 if (!IS_AML_NODE_VALID (Node
)) {
33 return EAmlNodeUnknown
;
36 return Node
->NodeType
;
39 /** Get the RootNode information.
40 The Node must be a root node.
42 @param [in] RootNode Pointer to a root node.
43 @param [out] SdtHeaderBuffer Buffer to copy the ACPI DSDT/SSDT header to.
45 @retval EFI_SUCCESS The function completed successfully.
46 @retval EFI_INVALID_PARAMETER Invalid parameter.
51 IN AML_ROOT_NODE
*RootNode
,
52 OUT EFI_ACPI_DESCRIPTION_HEADER
*SdtHeaderBuffer
55 if (!IS_AML_ROOT_NODE (RootNode
) ||
56 (SdtHeaderBuffer
== NULL
))
59 return EFI_INVALID_PARAMETER
;
65 sizeof (EFI_ACPI_DESCRIPTION_HEADER
)
71 /** Get the ObjectNode information.
72 The Node must be an object node.
74 @ingroup NodeInterfaceApi
76 @param [in] ObjectNode Pointer to an object node.
77 @param [out] OpCode Pointer holding the OpCode.
78 Optional, can be NULL.
79 @param [out] SubOpCode Pointer holding the SubOpCode.
80 Optional, can be NULL.
81 @param [out] PkgLen Pointer holding the PkgLen.
82 The PkgLen is 0 for nodes
83 not having the Pkglen attribute.
84 Optional, can be NULL.
85 @param [out] IsNameSpaceNode Pointer holding TRUE if the node is defining
86 or changing the NameSpace scope.
87 E.g.: The "Name ()" and "Scope ()" ASL
88 statements add/modify the NameSpace scope.
89 Their corresponding node are NameSpace nodes.
90 Optional, can be NULL.
92 @retval EFI_SUCCESS The function completed successfully.
93 @retval EFI_INVALID_PARAMETER Invalid parameter.
97 AmlGetObjectNodeInfo (
98 IN AML_OBJECT_NODE
*ObjectNode
,
99 OUT UINT8
*OpCode OPTIONAL
,
100 OUT UINT8
*SubOpCode OPTIONAL
,
101 OUT UINT32
*PkgLen OPTIONAL
,
102 OUT BOOLEAN
*IsNameSpaceNode OPTIONAL
105 if (!IS_AML_OBJECT_NODE (ObjectNode
)) {
107 return EFI_INVALID_PARAMETER
;
110 if (OpCode
!= NULL
) {
111 *OpCode
= ObjectNode
->AmlByteEncoding
->OpCode
;
114 if (SubOpCode
!= NULL
) {
115 *SubOpCode
= ObjectNode
->AmlByteEncoding
->SubOpCode
;
118 if (PkgLen
!= NULL
) {
119 *PkgLen
= ObjectNode
->PkgLen
;
122 if (IsNameSpaceNode
!= NULL
) {
123 *IsNameSpaceNode
= AmlNodeHasAttribute (ObjectNode
, AML_IN_NAMESPACE
);
129 /** Returns the count of the fixed arguments for the input Node.
131 @param [in] Node Pointer to an object node.
133 @return Number of fixed arguments of the object node.
134 Return 0 if the node is not an object node.
137 AmlGetFixedArgumentCount (
138 IN AML_OBJECT_NODE
*Node
141 if (IS_AML_OBJECT_NODE (Node
) &&
142 (Node
->AmlByteEncoding
!= NULL
))
144 return (UINT8
)Node
->AmlByteEncoding
->MaxIndex
;
150 /** Get the data type of the DataNode.
151 The Node must be a data node.
153 @param [in] DataNode Pointer to a data node.
154 @param [out] DataType Pointer holding the data type of the data buffer.
156 @retval EFI_SUCCESS The function completed successfully.
157 @retval EFI_INVALID_PARAMETER Invalid parameter.
162 IN AML_DATA_NODE
*DataNode
,
163 OUT EAML_NODE_DATA_TYPE
*DataType
166 if (!IS_AML_DATA_NODE (DataNode
) ||
170 return EFI_INVALID_PARAMETER
;
173 *DataType
= DataNode
->DataType
;
178 /** Get the descriptor Id of the resource data element
179 contained in the DataNode.
181 The Node must be a data node.
182 The Node must have the resource data type, i.e. have the
183 EAmlNodeDataTypeResourceData data type.
185 @param [in] DataNode Pointer to a data node containing a
186 resource data element.
187 @param [out] ResourceDataType Pointer holding the descriptor Id of
190 @retval EFI_SUCCESS The function completed successfully.
191 @retval EFI_INVALID_PARAMETER Invalid parameter.
195 AmlGetResourceDataType (
196 IN AML_DATA_NODE
*DataNode
,
197 OUT AML_RD_HEADER
*ResourceDataType
200 if (!IS_AML_DATA_NODE (DataNode
) ||
201 (ResourceDataType
== NULL
) ||
202 (DataNode
->DataType
!= EAmlNodeDataTypeResourceData
))
205 return EFI_INVALID_PARAMETER
;
208 *ResourceDataType
= AmlRdGetDescId (DataNode
->Buffer
);
213 /** Get the data buffer and size of the DataNode.
214 The Node must be a data node.
216 BufferSize is always updated to the size of buffer of the DataNode.
219 - the content of BufferSize is >= to the DataNode's buffer size;
220 - Buffer is not NULL;
221 then copy the content of the DataNode's buffer in Buffer.
223 @param [in] DataNode Pointer to a data node.
224 @param [out] Buffer Buffer to write the data to.
225 Optional, if NULL, only update BufferSize.
226 @param [in, out] BufferSize Pointer holding:
227 - At entry, the size of the Buffer;
228 - At exit, the size of the DataNode's
231 @retval EFI_SUCCESS The function completed successfully.
232 @retval EFI_INVALID_PARAMETER Invalid parameter.
236 AmlGetDataNodeBuffer (
237 IN AML_DATA_NODE
*DataNode
,
238 OUT UINT8
*Buffer OPTIONAL
,
239 IN OUT UINT32
*BufferSize
242 if (!IS_AML_DATA_NODE (DataNode
) ||
243 (BufferSize
== NULL
))
246 return EFI_INVALID_PARAMETER
;
249 if ((*BufferSize
>= DataNode
->Size
) &&
252 CopyMem (Buffer
, DataNode
->Buffer
, DataNode
->Size
);
255 *BufferSize
= DataNode
->Size
;
260 /** Update the ACPI DSDT/SSDT table header.
262 The input SdtHeader information is copied to the tree RootNode.
263 The table Length field is automatically updated.
264 The checksum field is only updated when serializing the tree.
266 @param [in] RootNode Pointer to a root node.
267 @param [in] SdtHeader Pointer to an ACPI DSDT/SSDT table header.
269 @retval EFI_SUCCESS The function completed successfully.
270 @retval EFI_INVALID_PARAMETER Invalid parameter.
275 IN AML_ROOT_NODE
*RootNode
,
276 IN CONST EFI_ACPI_DESCRIPTION_HEADER
*SdtHeader
282 if (!IS_AML_ROOT_NODE (RootNode
) ||
283 (SdtHeader
== NULL
) ||
284 ((SdtHeader
->Signature
!=
285 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
) &&
286 (SdtHeader
->Signature
!=
287 EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
)))
290 return EFI_INVALID_PARAMETER
;
296 sizeof (EFI_ACPI_DESCRIPTION_HEADER
)
299 // Update the Length field.
300 Status
= AmlComputeSize ((AML_NODE_HEADER
*)RootNode
, &Length
);
301 if (EFI_ERROR (Status
)) {
306 RootNode
->SdtHeader
->Length
= Length
+
307 (UINT32
)sizeof (EFI_ACPI_DESCRIPTION_HEADER
);
312 /** Update an object node representing an integer with a new value.
314 The object node must have one of the following OpCodes:
322 The following OpCode is not supported:
325 @param [in] IntegerOpNode Pointer an object node containing an integer.
326 Must not be an object node with an AML_ONES_OP
328 @param [in] NewInteger New integer value to set.
330 @retval EFI_SUCCESS The function completed successfully.
331 @retval EFI_INVALID_PARAMETER Invalid parameter.
336 IN AML_OBJECT_NODE
*IntegerOpNode
,
344 if (!IS_AML_OBJECT_NODE (IntegerOpNode
) ||
345 (!IsIntegerNode (IntegerOpNode
) &&
346 !IsSpecialIntegerNode (IntegerOpNode
)) ||
347 AmlNodeCompareOpCode (IntegerOpNode
, AML_ONES_OP
, 0))
350 return EFI_INVALID_PARAMETER
;
353 Status
= AmlNodeSetIntegerValue (IntegerOpNode
, NewInteger
, &ValueWidthDiff
);
354 if (EFI_ERROR (Status
)) {
359 // If the new size is different from the old size, propagate the new size.
360 if (ValueWidthDiff
!= 0) {
361 // Propagate the information.
362 Status
= AmlPropagateInformation (
363 (AML_NODE_HEADER
*)IntegerOpNode
,
364 (ValueWidthDiff
> 0) ? TRUE
: FALSE
,
365 ABS (ValueWidthDiff
),
368 if (EFI_ERROR (Status
)) {
376 /** Update the buffer of a data node.
378 Note: The data type of the buffer's content must match the data type of the
379 DataNode. This is a hard restriction to prevent undesired behaviour.
381 @param [in] DataNode Pointer to a data node.
382 @param [in] DataType Data type of the Buffer's content.
383 @param [in] Buffer Buffer containing the new data. The content of
384 the Buffer is copied.
385 @param [in] Size Size of the Buffer.
387 @retval EFI_SUCCESS The function completed successfully.
388 @retval EFI_INVALID_PARAMETER Invalid parameter.
389 @retval EFI_UNSUPPORTED Operation not supporter.
394 IN AML_DATA_NODE
*DataNode
,
395 IN EAML_NODE_DATA_TYPE DataType
,
403 AML_OBJECT_NODE
*ParentNode
;
404 EAML_NODE_DATA_TYPE ExpectedArgType
;
405 EAML_PARSE_INDEX Index
;
407 if (!IS_AML_DATA_NODE (DataNode
) ||
408 (DataType
> EAmlNodeDataTypeMax
) ||
413 return EFI_INVALID_PARAMETER
;
416 ParentNode
= (AML_OBJECT_NODE
*)AmlGetParent ((AML_NODE_HEADER
*)DataNode
);
417 if (!IS_AML_OBJECT_NODE (ParentNode
)) {
419 return EFI_INVALID_PARAMETER
;
422 // The NewNode and OldNode must have the same type.
423 // We do not allow to change the argument type of a data node.
424 // If required, the initial ASL template should be modified
426 // It is however possible to interchange a raw buffer and a
427 // resource data element, since raw data can be misinterpreted
428 // as a resource data element.
429 ExpectedArgType
= DataNode
->DataType
;
430 if ((ExpectedArgType
!= DataType
) &&
431 (((ExpectedArgType
!= EAmlNodeDataTypeRaw
) &&
432 (ExpectedArgType
!= EAmlNodeDataTypeResourceData
)) ||
433 ((DataType
!= EAmlNodeDataTypeRaw
) &&
434 (DataType
!= EAmlNodeDataTypeResourceData
))))
437 return EFI_UNSUPPORTED
;
440 // Perform some compatibility checks.
442 case EAmlNodeDataTypeNameString
:
444 // Check the name contained in the Buffer is an AML name
445 // with the right size.
446 Status
= AmlGetNameStringSize ((CONST CHAR8
*)Buffer
, &ExpectedSize
);
447 if (EFI_ERROR (Status
) ||
448 (Size
!= ExpectedSize
))
456 case EAmlNodeDataTypeString
:
459 while (ExpectedSize
< Size
) {
460 // Cf ACPI 6.3 specification 20.2.3 Data Objects Encoding.
461 // AsciiCharList := Nothing | <AsciiChar AsciiCharList>
462 // AsciiChar := 0x01 - 0x7F
464 if (Buffer
[ExpectedSize
] > 0x7F) {
466 return EFI_INVALID_PARAMETER
;
472 if (ExpectedSize
!= Size
) {
474 return EFI_INVALID_PARAMETER
;
479 case EAmlNodeDataTypeUInt
:
481 if (AmlIsNodeFixedArgument ((CONST AML_NODE_HEADER
*)DataNode
, &Index
)) {
482 if ((ParentNode
->AmlByteEncoding
== NULL
) ||
483 (ParentNode
->AmlByteEncoding
->Format
== NULL
))
486 return EFI_INVALID_PARAMETER
;
489 // It is not possible to change the size of a fixed length UintX.
490 // E.g. for PackageOp the first fixed argument is of type EAmlUInt8
491 // and represents the count of elements. This type cannot be changed.
492 if ((ParentNode
->AmlByteEncoding
->Format
[Index
] != EAmlObject
) &&
493 (DataNode
->Size
!= Size
))
496 return EFI_UNSUPPORTED
;
502 case EAmlNodeDataTypeRaw
:
504 // Check if the parent node has the byte list flag set.
505 if (!AmlNodeHasAttribute (ParentNode
, AML_HAS_BYTE_LIST
)) {
507 return EFI_INVALID_PARAMETER
;
512 case EAmlNodeDataTypeResourceData
:
514 // The resource data can be either small or large resource data.
515 // Small resource data must be at least 1 byte.
516 // Large resource data must be at least as long as the header
517 // of a large resource data.
518 if (AML_RD_IS_LARGE (Buffer
) &&
519 (Size
< sizeof (ACPI_LARGE_RESOURCE_HEADER
)))
522 return EFI_INVALID_PARAMETER
;
525 // Check if the parent node has the byte list flag set.
526 if (!AmlNodeHasAttribute (ParentNode
, AML_HAS_BYTE_LIST
)) {
528 return EFI_INVALID_PARAMETER
;
531 // Check the size of the buffer is equal to the resource data size
532 // encoded in the input buffer.
533 ExpectedSize
= AmlRdGetSize (Buffer
);
534 if (ExpectedSize
!= Size
) {
536 return EFI_INVALID_PARAMETER
;
539 Status
= AmlSetRdListCheckSum (ParentNode
, 0);
540 if (EFI_ERROR (Status
)) {
547 case EAmlNodeDataTypeFieldPkgLen
:
549 // Check the parent is a FieldNamed field element.
550 if (!AmlNodeCompareOpCode (ParentNode
, AML_FIELD_NAMED_OP
, 0)) {
552 return EFI_INVALID_PARAMETER
;
557 // None and reserved types.
561 return EFI_INVALID_PARAMETER
;
566 // If the new size is different from the old size, propagate the new size.
567 if (DataNode
->Size
!= Size
) {
568 // Propagate the information.
569 Status
= AmlPropagateInformation (
570 DataNode
->NodeHeader
.Parent
,
571 (Size
> DataNode
->Size
) ? TRUE
: FALSE
,
572 (Size
> DataNode
->Size
) ?
573 (Size
- DataNode
->Size
) :
574 (DataNode
->Size
- Size
),
577 if (EFI_ERROR (Status
)) {
582 // Free the old DataNode buffer and allocate a new buffer to store the
584 FreePool (DataNode
->Buffer
);
585 DataNode
->Buffer
= AllocateZeroPool (Size
);
586 if (DataNode
->Buffer
== NULL
) {
588 return EFI_OUT_OF_RESOURCES
;
591 DataNode
->Size
= Size
;
594 CopyMem (DataNode
->Buffer
, Buffer
, Size
);