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
)) {
58 return EFI_INVALID_PARAMETER
;
64 sizeof (EFI_ACPI_DESCRIPTION_HEADER
)
70 /** Get the ObjectNode information.
71 The Node must be an object node.
73 @ingroup NodeInterfaceApi
75 @param [in] ObjectNode Pointer to an object node.
76 @param [out] OpCode Pointer holding the OpCode.
77 Optional, can be NULL.
78 @param [out] SubOpCode Pointer holding the SubOpCode.
79 Optional, can be NULL.
80 @param [out] PkgLen Pointer holding the PkgLen.
81 The PkgLen is 0 for nodes
82 not having the Pkglen attribute.
83 Optional, can be NULL.
84 @param [out] IsNameSpaceNode Pointer holding TRUE if the node is defining
85 or changing the NameSpace scope.
86 E.g.: The "Name ()" and "Scope ()" ASL
87 statements add/modify the NameSpace scope.
88 Their corresponding node are NameSpace nodes.
89 Optional, can be NULL.
91 @retval EFI_SUCCESS The function completed successfully.
92 @retval EFI_INVALID_PARAMETER Invalid parameter.
96 AmlGetObjectNodeInfo (
97 IN AML_OBJECT_NODE
* ObjectNode
,
98 OUT UINT8
* OpCode OPTIONAL
,
99 OUT UINT8
* SubOpCode OPTIONAL
,
100 OUT UINT32
* PkgLen OPTIONAL
,
101 OUT BOOLEAN
* IsNameSpaceNode OPTIONAL
104 if (!IS_AML_OBJECT_NODE (ObjectNode
)) {
106 return EFI_INVALID_PARAMETER
;
109 if (OpCode
!= NULL
) {
110 *OpCode
= ObjectNode
->AmlByteEncoding
->OpCode
;
112 if (SubOpCode
!= NULL
) {
113 *SubOpCode
= ObjectNode
->AmlByteEncoding
->SubOpCode
;
115 if (PkgLen
!= NULL
) {
116 *PkgLen
= ObjectNode
->PkgLen
;
118 if (IsNameSpaceNode
!= NULL
) {
119 *IsNameSpaceNode
= AmlNodeHasAttribute (ObjectNode
, AML_IN_NAMESPACE
);
125 /** Returns the count of the fixed arguments for the input Node.
127 @param [in] Node Pointer to an object node.
129 @return Number of fixed arguments of the object node.
130 Return 0 if the node is not an object node.
133 AmlGetFixedArgumentCount (
134 IN AML_OBJECT_NODE
* Node
137 if (IS_AML_OBJECT_NODE (Node
) &&
138 (Node
->AmlByteEncoding
!= NULL
)) {
139 return (UINT8
)Node
->AmlByteEncoding
->MaxIndex
;
145 /** Get the data type of the DataNode.
146 The Node must be a data node.
148 @param [in] DataNode Pointer to a data node.
149 @param [out] DataType Pointer holding the data type of the data buffer.
151 @retval EFI_SUCCESS The function completed successfully.
152 @retval EFI_INVALID_PARAMETER Invalid parameter.
157 IN AML_DATA_NODE
* DataNode
,
158 OUT EAML_NODE_DATA_TYPE
* DataType
161 if (!IS_AML_DATA_NODE (DataNode
) ||
162 (DataType
== NULL
)) {
164 return EFI_INVALID_PARAMETER
;
167 *DataType
= DataNode
->DataType
;
172 /** Get the descriptor Id of the resource data element
173 contained in the DataNode.
175 The Node must be a data node.
176 The Node must have the resource data type, i.e. have the
177 EAmlNodeDataTypeResourceData data type.
179 @param [in] DataNode Pointer to a data node containing a
180 resource data element.
181 @param [out] ResourceDataType Pointer holding the descriptor Id of
184 @retval EFI_SUCCESS The function completed successfully.
185 @retval EFI_INVALID_PARAMETER Invalid parameter.
189 AmlGetResourceDataType (
190 IN AML_DATA_NODE
* DataNode
,
191 OUT AML_RD_HEADER
* ResourceDataType
194 if (!IS_AML_DATA_NODE (DataNode
) ||
195 (ResourceDataType
== NULL
) ||
196 (DataNode
->DataType
!= EAmlNodeDataTypeResourceData
)) {
198 return EFI_INVALID_PARAMETER
;
201 *ResourceDataType
= AmlRdGetDescId (DataNode
->Buffer
);
206 /** Get the data buffer and size of the DataNode.
207 The Node must be a data node.
209 BufferSize is always updated to the size of buffer of the DataNode.
212 - the content of BufferSize is >= to the DataNode's buffer size;
213 - Buffer is not NULL;
214 then copy the content of the DataNode's buffer in Buffer.
216 @param [in] DataNode Pointer to a data node.
217 @param [out] Buffer Buffer to write the data to.
218 Optional, if NULL, only update BufferSize.
219 @param [in, out] BufferSize Pointer holding:
220 - At entry, the size of the Buffer;
221 - At exit, the size of the DataNode's
224 @retval EFI_SUCCESS The function completed successfully.
225 @retval EFI_INVALID_PARAMETER Invalid parameter.
229 AmlGetDataNodeBuffer (
230 IN AML_DATA_NODE
* DataNode
,
231 OUT UINT8
* Buffer OPTIONAL
,
232 IN OUT UINT32
* BufferSize
235 if (!IS_AML_DATA_NODE (DataNode
) ||
236 (BufferSize
== NULL
)) {
238 return EFI_INVALID_PARAMETER
;
241 if ((*BufferSize
>= DataNode
->Size
) &&
243 CopyMem (Buffer
, DataNode
->Buffer
, DataNode
->Size
);
246 *BufferSize
= DataNode
->Size
;
251 /** Update the ACPI DSDT/SSDT table header.
253 The input SdtHeader information is copied to the tree RootNode.
254 The table Length field is automatically updated.
255 The checksum field is only updated when serializing the tree.
257 @param [in] RootNode Pointer to a root node.
258 @param [in] SdtHeader Pointer to an ACPI DSDT/SSDT table header.
260 @retval EFI_SUCCESS The function completed successfully.
261 @retval EFI_INVALID_PARAMETER Invalid parameter.
266 IN AML_ROOT_NODE
* RootNode
,
267 IN CONST EFI_ACPI_DESCRIPTION_HEADER
* SdtHeader
273 if (!IS_AML_ROOT_NODE (RootNode
) ||
274 (SdtHeader
== NULL
) ||
275 ((SdtHeader
->Signature
!=
276 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
) &&
277 (SdtHeader
->Signature
!=
278 EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
))) {
280 return EFI_INVALID_PARAMETER
;
286 sizeof (EFI_ACPI_DESCRIPTION_HEADER
)
289 // Update the Length field.
290 Status
= AmlComputeSize ((AML_NODE_HEADER
*)RootNode
, &Length
);
291 if (EFI_ERROR (Status
)) {
296 RootNode
->SdtHeader
->Length
= Length
+
297 (UINT32
)sizeof (EFI_ACPI_DESCRIPTION_HEADER
);
302 /** Update an object node representing an integer with a new value.
304 The object node must have one of the following OpCodes:
312 The following OpCode is not supported:
315 @param [in] IntegerOpNode Pointer an object node containing an integer.
316 Must not be an object node with an AML_ONES_OP
318 @param [in] NewInteger New integer value to set.
320 @retval EFI_SUCCESS The function completed successfully.
321 @retval EFI_INVALID_PARAMETER Invalid parameter.
326 IN AML_OBJECT_NODE
* IntegerOpNode
,
334 if (!IS_AML_OBJECT_NODE (IntegerOpNode
) ||
335 (!IsIntegerNode (IntegerOpNode
) &&
336 !IsSpecialIntegerNode (IntegerOpNode
)) ||
337 AmlNodeCompareOpCode (IntegerOpNode
, AML_ONES_OP
, 0)) {
339 return EFI_INVALID_PARAMETER
;
342 Status
= AmlNodeSetIntegerValue (IntegerOpNode
, NewInteger
, &ValueWidthDiff
);
343 if (EFI_ERROR (Status
)) {
348 // If the new size is different from the old size, propagate the new size.
349 if (ValueWidthDiff
!= 0) {
350 // Propagate the information.
351 Status
= AmlPropagateInformation (
352 (AML_NODE_HEADER
*)IntegerOpNode
,
353 (ValueWidthDiff
> 0) ? TRUE
: FALSE
,
354 ABS (ValueWidthDiff
),
357 if (EFI_ERROR (Status
)) {
365 /** Update the buffer of a data node.
367 Note: The data type of the buffer's content must match the data type of the
368 DataNode. This is a hard restriction to prevent undesired behaviour.
370 @param [in] DataNode Pointer to a data node.
371 @param [in] DataType Data type of the Buffer's content.
372 @param [in] Buffer Buffer containing the new data. The content of
373 the Buffer is copied.
374 @param [in] Size Size of the Buffer.
376 @retval EFI_SUCCESS The function completed successfully.
377 @retval EFI_INVALID_PARAMETER Invalid parameter.
378 @retval EFI_UNSUPPORTED Operation not supporter.
383 IN AML_DATA_NODE
* DataNode
,
384 IN EAML_NODE_DATA_TYPE DataType
,
392 AML_OBJECT_NODE
* ParentNode
;
393 EAML_NODE_DATA_TYPE ExpectedArgType
;
394 EAML_PARSE_INDEX Index
;
396 if (!IS_AML_DATA_NODE (DataNode
) ||
397 (DataType
> EAmlNodeDataTypeMax
) ||
401 return EFI_INVALID_PARAMETER
;
404 ParentNode
= (AML_OBJECT_NODE
*)AmlGetParent ((AML_NODE_HEADER
*)DataNode
);
405 if (!IS_AML_OBJECT_NODE (ParentNode
)) {
407 return EFI_INVALID_PARAMETER
;
410 // The NewNode and OldNode must have the same type.
411 // We do not allow to change the argument type of a data node.
412 // If required, the initial ASL template should be modified
414 // It is however possible to interchange a raw buffer and a
415 // resource data element, since raw data can be misinterpreted
416 // as a resource data element.
417 ExpectedArgType
= DataNode
->DataType
;
418 if ((ExpectedArgType
!= DataType
) &&
419 (((ExpectedArgType
!= EAmlNodeDataTypeRaw
) &&
420 (ExpectedArgType
!= EAmlNodeDataTypeResourceData
)) ||
421 ((DataType
!= EAmlNodeDataTypeRaw
) &&
422 (DataType
!= EAmlNodeDataTypeResourceData
)))) {
424 return EFI_UNSUPPORTED
;
427 // Perform some compatibility checks.
429 case EAmlNodeDataTypeNameString
:
431 // Check the name contained in the Buffer is an AML name
432 // with the right size.
433 Status
= AmlGetNameStringSize ((CONST CHAR8
*)Buffer
, &ExpectedSize
);
434 if (EFI_ERROR (Status
) ||
435 (Size
!= ExpectedSize
)) {
441 case EAmlNodeDataTypeString
:
444 while (ExpectedSize
< Size
) {
445 // Cf ACPI 6.3 specification 20.2.3 Data Objects Encoding.
446 // AsciiCharList := Nothing | <AsciiChar AsciiCharList>
447 // AsciiChar := 0x01 - 0x7F
449 if (Buffer
[ExpectedSize
] > 0x7F) {
451 return EFI_INVALID_PARAMETER
;
456 if (ExpectedSize
!= Size
) {
458 return EFI_INVALID_PARAMETER
;
462 case EAmlNodeDataTypeUInt
:
464 if (AmlIsNodeFixedArgument ((CONST AML_NODE_HEADER
*)DataNode
, &Index
)) {
465 if ((ParentNode
->AmlByteEncoding
== NULL
) ||
466 (ParentNode
->AmlByteEncoding
->Format
== NULL
)) {
468 return EFI_INVALID_PARAMETER
;
471 // It is not possible to change the size of a fixed length UintX.
472 // E.g. for PackageOp the first fixed argument is of type EAmlUInt8
473 // and represents the count of elements. This type cannot be changed.
474 if ((ParentNode
->AmlByteEncoding
->Format
[Index
] != EAmlObject
) &&
475 (DataNode
->Size
!= Size
)) {
477 return EFI_UNSUPPORTED
;
482 case EAmlNodeDataTypeRaw
:
484 // Check if the parent node has the byte list flag set.
485 if (!AmlNodeHasAttribute (ParentNode
, AML_HAS_BYTE_LIST
)) {
487 return EFI_INVALID_PARAMETER
;
491 case EAmlNodeDataTypeResourceData
:
493 // The resource data can be either small or large resource data.
494 // Small resource data must be at least 1 byte.
495 // Large resource data must be at least as long as the header
496 // of a large resource data.
497 if (AML_RD_IS_LARGE (Buffer
) &&
498 (Size
< sizeof (ACPI_LARGE_RESOURCE_HEADER
))) {
500 return EFI_INVALID_PARAMETER
;
503 // Check if the parent node has the byte list flag set.
504 if (!AmlNodeHasAttribute (ParentNode
, AML_HAS_BYTE_LIST
)) {
506 return EFI_INVALID_PARAMETER
;
509 // Check the size of the buffer is equal to the resource data size
510 // encoded in the input buffer.
511 ExpectedSize
= AmlRdGetSize (Buffer
);
512 if (ExpectedSize
!= Size
) {
514 return EFI_INVALID_PARAMETER
;
517 Status
= AmlSetRdListCheckSum (ParentNode
, 0);
518 if (EFI_ERROR (Status
)) {
525 case EAmlNodeDataTypeFieldPkgLen
:
527 // Check the parent is a FieldNamed field element.
528 if (!AmlNodeCompareOpCode (ParentNode
, AML_FIELD_NAMED_OP
, 0)) {
530 return EFI_INVALID_PARAMETER
;
534 // None and reserved types.
538 return EFI_INVALID_PARAMETER
;
543 // If the new size is different from the old size, propagate the new size.
544 if (DataNode
->Size
!= Size
) {
545 // Propagate the information.
546 Status
= AmlPropagateInformation (
547 DataNode
->NodeHeader
.Parent
,
548 (Size
> DataNode
->Size
) ? TRUE
: FALSE
,
549 (Size
> DataNode
->Size
) ?
550 (Size
- DataNode
->Size
) :
551 (DataNode
->Size
- Size
),
554 if (EFI_ERROR (Status
)) {
559 // Free the old DataNode buffer and allocate a new buffer to store the
561 FreePool (DataNode
->Buffer
);
562 DataNode
->Buffer
= AllocateZeroPool (Size
);
563 if (DataNode
->Buffer
== NULL
) {
565 return EFI_OUT_OF_RESOURCES
;
567 DataNode
->Size
= Size
;
570 CopyMem (DataNode
->Buffer
, Buffer
, Size
);