4 Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <Tree/AmlNode.h>
11 #include <AmlCoreInterface.h>
12 #include <Tree/AmlTree.h>
14 /** Initialize an AML_NODE_HEADER structure.
16 @param [in] Node Pointer to a node header.
17 @param [in] NodeType NodeType to initialize the Node with.
18 Must be an EAML_NODE_TYPE.
20 @retval EFI_SUCCESS The function completed successfully.
21 @retval EFI_INVALID_PARAMETER Invalid parameter.
26 AmlInitializeNodeHeader (
27 IN AML_NODE_HEADER
* Node
,
28 IN EAML_NODE_TYPE NodeType
33 return EFI_INVALID_PARAMETER
;
36 InitializeListHead (&Node
->Link
);
39 Node
->NodeType
= NodeType
;
44 /** Delete a root node and its ACPI DSDT/SSDT header.
46 It is the caller's responsibility to check the RootNode has been removed
47 from the tree and is not referencing any other node in the tree.
49 @param [in] RootNode Pointer to a root node.
51 @retval EFI_SUCCESS The function completed successfully.
52 @retval EFI_INVALID_PARAMETER Invalid parameter.
58 IN AML_ROOT_NODE
* RootNode
61 if (!IS_AML_ROOT_NODE (RootNode
)) {
63 return EFI_INVALID_PARAMETER
;
66 if ((RootNode
->SdtHeader
!= NULL
)) {
67 FreePool (RootNode
->SdtHeader
);
70 return EFI_INVALID_PARAMETER
;
77 /** Create an AML_ROOT_NODE.
78 This node will be the root of the tree.
80 @param [in] SdtHeader Pointer to an ACPI DSDT/SSDT header to copy
82 @param [out] NewRootNodePtr The created AML_ROOT_NODE.
84 @retval EFI_SUCCESS The function completed successfully.
85 @retval EFI_INVALID_PARAMETER Invalid parameter.
86 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
91 IN CONST EFI_ACPI_DESCRIPTION_HEADER
* SdtHeader
,
92 OUT AML_ROOT_NODE
** NewRootNodePtr
96 AML_ROOT_NODE
* RootNode
;
98 if ((SdtHeader
== NULL
) ||
99 (NewRootNodePtr
== NULL
)) {
101 return EFI_INVALID_PARAMETER
;
104 RootNode
= AllocateZeroPool (sizeof (AML_ROOT_NODE
));
105 if (RootNode
== NULL
) {
107 return EFI_OUT_OF_RESOURCES
;
110 Status
= AmlInitializeNodeHeader (&RootNode
->NodeHeader
, EAmlNodeRoot
);
111 if (EFI_ERROR (Status
)) {
117 InitializeListHead (&RootNode
->VariableArgs
);
119 RootNode
->SdtHeader
= AllocateCopyPool (
120 sizeof (EFI_ACPI_DESCRIPTION_HEADER
),
123 if (RootNode
->SdtHeader
== NULL
) {
125 AmlDeleteRootNode (RootNode
);
126 return EFI_OUT_OF_RESOURCES
;
129 *NewRootNodePtr
= RootNode
;
134 /** Delete an object node.
136 It is the caller's responsibility to check the ObjectNode has been removed
137 from the tree and is not referencing any other node in the tree.
139 @param [in] ObjectNode Pointer to an object node.
141 @retval EFI_SUCCESS The function completed successfully.
142 @retval EFI_INVALID_PARAMETER Invalid parameter.
147 AmlDeleteObjectNode (
148 IN AML_OBJECT_NODE
* ObjectNode
151 if (!IS_AML_OBJECT_NODE (ObjectNode
)) {
153 return EFI_INVALID_PARAMETER
;
156 FreePool (ObjectNode
);
160 /** Create an AML_OBJECT_NODE.
162 @param [in] AmlByteEncoding Byte encoding entry.
163 @param [in] PkgLength PkgLength of the node if the AmlByteEncoding
164 has the PkgLen attribute.
166 @param [out] NewObjectNodePtr The created AML_OBJECT_NODE.
168 @retval EFI_SUCCESS The function completed successfully.
169 @retval EFI_INVALID_PARAMETER Invalid parameter.
170 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
174 AmlCreateObjectNode (
175 IN CONST AML_BYTE_ENCODING
* AmlByteEncoding
,
177 OUT AML_OBJECT_NODE
** NewObjectNodePtr
181 AML_OBJECT_NODE
* ObjectNode
;
183 if ((AmlByteEncoding
== NULL
) ||
184 (NewObjectNodePtr
== NULL
)) {
186 return EFI_INVALID_PARAMETER
;
189 ObjectNode
= AllocateZeroPool (sizeof (AML_OBJECT_NODE
));
190 if (ObjectNode
== NULL
) {
192 return EFI_OUT_OF_RESOURCES
;
195 Status
= AmlInitializeNodeHeader (&ObjectNode
->NodeHeader
, EAmlNodeObject
);
196 if (EFI_ERROR (Status
)) {
197 FreePool (ObjectNode
);
202 InitializeListHead (&ObjectNode
->VariableArgs
);
204 // ObjectNode->FixedArgs[...] is already initialised to NULL as the
205 // ObjectNode is Zero allocated.
206 ObjectNode
->AmlByteEncoding
= AmlByteEncoding
;
207 ObjectNode
->PkgLen
= PkgLength
;
209 *NewObjectNodePtr
= ObjectNode
;
214 /** Delete a data node and its buffer.
216 It is the caller's responsibility to check the DataNode has been removed
217 from the tree and is not referencing any other node in the tree.
219 @param [in] DataNode Pointer to a data node.
221 @retval EFI_SUCCESS The function completed successfully.
222 @retval EFI_INVALID_PARAMETER Invalid parameter.
223 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
229 IN AML_DATA_NODE
* DataNode
232 if (!IS_AML_DATA_NODE (DataNode
)) {
234 return EFI_INVALID_PARAMETER
;
237 if (DataNode
->Buffer
!= NULL
) {
238 FreePool (DataNode
->Buffer
);
241 return EFI_INVALID_PARAMETER
;
248 /** Create an AML_DATA_NODE.
250 @param [in] DataType DataType of the node.
251 @param [in] Data Pointer to the AML bytecode corresponding to
252 this node. Data is copied from there.
253 @param [in] DataSize Number of bytes to consider at the address
255 @param [out] NewDataNodePtr The created AML_DATA_NODE.
257 @retval EFI_SUCCESS The function completed successfully.
258 @retval EFI_INVALID_PARAMETER Invalid parameter.
259 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
264 IN EAML_NODE_DATA_TYPE DataType
,
265 IN CONST UINT8
* Data
,
267 OUT AML_DATA_NODE
** NewDataNodePtr
271 AML_DATA_NODE
* DataNode
;
273 // A data node must not be created for certain data types.
274 if ((DataType
== EAmlNodeDataTypeNone
) ||
275 (DataType
== EAmlNodeDataTypeReserved1
) ||
276 (DataType
== EAmlNodeDataTypeReserved2
) ||
277 (DataType
== EAmlNodeDataTypeReserved3
) ||
278 (DataType
== EAmlNodeDataTypeReserved4
) ||
279 (DataType
== EAmlNodeDataTypeReserved5
) ||
282 (NewDataNodePtr
== NULL
)) {
284 return EFI_INVALID_PARAMETER
;
287 DataNode
= AllocateZeroPool (sizeof (AML_DATA_NODE
));
288 if (DataNode
== NULL
) {
290 return EFI_OUT_OF_RESOURCES
;
293 Status
= AmlInitializeNodeHeader (&DataNode
->NodeHeader
, EAmlNodeData
);
294 if (EFI_ERROR (Status
)) {
300 DataNode
->Buffer
= AllocateCopyPool (DataSize
, Data
);
301 if (DataNode
->Buffer
== NULL
) {
302 AmlDeleteDataNode (DataNode
);
304 return EFI_OUT_OF_RESOURCES
;
307 DataNode
->DataType
= DataType
;
308 DataNode
->Size
= DataSize
;
310 *NewDataNodePtr
= DataNode
;
317 @param [in] Node Pointer to a Node.
319 @retval EFI_SUCCESS The function completed successfully.
320 @retval EFI_INVALID_PARAMETER Invalid parameter.
325 IN AML_NODE_HEADER
* Node
329 EAML_PARSE_INDEX Index
;
331 // Check that the node being deleted is unlinked.
332 // When removing the node, its parent and list are reset
333 // with InitializeListHead. Thus it must be empty.
334 if (!IS_AML_NODE_VALID (Node
) ||
335 !AML_NODE_IS_DETACHED (Node
)) {
337 return EFI_INVALID_PARAMETER
;
340 switch (Node
->NodeType
) {
343 // Check the variable list of arguments has been cleaned.
344 if (!IsListEmpty (AmlNodeGetVariableArgList (Node
))) {
346 return EFI_INVALID_PARAMETER
;
349 Status
= AmlDeleteRootNode ((AML_ROOT_NODE
*)Node
);
350 if (EFI_ERROR (Status
)) {
358 // Check the variable list of arguments has been cleaned.
359 if (!IsListEmpty (AmlNodeGetVariableArgList (Node
))) {
361 return EFI_INVALID_PARAMETER
;
364 // Check the fixed argument list has been cleaned.
365 for (Index
= EAmlParseIndexTerm0
; Index
< EAmlParseIndexMax
; Index
++) {
366 if (((AML_OBJECT_NODE
*)Node
)->FixedArgs
[Index
] != NULL
) {
368 return EFI_INVALID_PARAMETER
;
372 Status
= AmlDeleteObjectNode ((AML_OBJECT_NODE
*)Node
);
373 if (EFI_ERROR (Status
)) {
381 Status
= AmlDeleteDataNode ((AML_DATA_NODE
*)Node
);
382 if (EFI_ERROR (Status
)) {
391 Status
= EFI_INVALID_PARAMETER
;
399 /** Check whether ObjectNode has the input attribute.
400 This function can be used to check ObjectNode is an object node
403 @param [in] ObjectNode Pointer to an object node.
404 @param [in] Attribute Attribute to check for.
406 @retval TRUE The node is an AML object and the attribute is present.
407 @retval FALSE Otherwise.
411 AmlNodeHasAttribute (
412 IN CONST AML_OBJECT_NODE
* ObjectNode
,
413 IN AML_OP_ATTRIBUTE Attribute
416 if (!IS_AML_OBJECT_NODE (ObjectNode
) ||
417 (ObjectNode
->AmlByteEncoding
== NULL
)) {
421 return ((ObjectNode
->AmlByteEncoding
->Attribute
&
422 Attribute
) == 0 ? FALSE
: TRUE
);
425 /** Check whether ObjectNode has the input OpCode/SubOpcode couple.
427 @param [in] ObjectNode Pointer to an object node.
428 @param [in] OpCode OpCode to check
429 @param [in] SubOpCode SubOpCode to check
431 @retval TRUE The node is an AML object and
432 the Opcode and the SubOpCode match.
433 @retval FALSE Otherwise.
437 AmlNodeCompareOpCode (
438 IN CONST AML_OBJECT_NODE
* ObjectNode
,
443 if (!IS_AML_OBJECT_NODE (ObjectNode
) ||
444 (ObjectNode
->AmlByteEncoding
== NULL
)) {
448 ASSERT (AmlIsOpCodeValid (OpCode
, SubOpCode
));
450 return ((ObjectNode
->AmlByteEncoding
->OpCode
== OpCode
) &&
451 (ObjectNode
->AmlByteEncoding
->SubOpCode
== SubOpCode
)) ?
455 /** Check whether a Node is an integer node.
457 By integer node we mean an object node having one of the following opcode:
463 @param [in] Node The node to check.
465 @retval TRUE The Node is an integer node.
466 @retval FALSE Otherwise.
471 IN AML_OBJECT_NODE
* Node
476 if (!IS_AML_OBJECT_NODE (Node
) ||
477 (Node
->AmlByteEncoding
== NULL
)) {
481 // Check Node is an integer node.
482 OpCode
= Node
->AmlByteEncoding
->OpCode
;
483 if ((OpCode
!= AML_BYTE_PREFIX
) &&
484 (OpCode
!= AML_WORD_PREFIX
) &&
485 (OpCode
!= AML_DWORD_PREFIX
) &&
486 (OpCode
!= AML_QWORD_PREFIX
)) {
493 /** Check whether a Node is a ZeroOp, a OneOp or a OnesOp.
495 These two objects don't have a data node holding
496 a value. This require special handling.
498 @param [in] Node The node to check.
500 @retval TRUE The Node is a ZeroOp or OneOp.
501 @retval FALSE Otherwise.
505 IsSpecialIntegerNode (
506 IN AML_OBJECT_NODE
* Node
511 if (!IS_AML_OBJECT_NODE (Node
) ||
512 (Node
->AmlByteEncoding
== NULL
)) {
516 OpCode
= Node
->AmlByteEncoding
->OpCode
;
518 if ((OpCode
!= AML_ZERO_OP
) &&
519 (OpCode
!= AML_ONE_OP
) &&
520 (OpCode
!= AML_ONES_OP
)) {
527 /** Check whether Node corresponds to a method definition.
529 A method definition can be introduced:
530 - By a method object, having an AML_METHOD_OP OpCode;
531 - By an external definition of a method, having an AML_EXTERNAL_OP OpCode
532 and an ObjectType byte set to the MethodObj.
535 An alias node, having an AML_ALIAS_OP, can be resolved to a method
536 definition. This function doesn't handle this case.
538 @param [in] Node Node to check whether it is a method definition.
540 @retval TRUE The Node is a method definition.
541 @retval FALSE Otherwise.
545 AmlIsMethodDefinitionNode (
546 IN CONST AML_OBJECT_NODE
* Node
549 AML_DATA_NODE
* ObjectType
;
551 // Node is checked to be an object node aswell.
552 if (AmlNodeCompareOpCode (Node
, AML_METHOD_OP
, 0)) {
554 } else if (AmlNodeCompareOpCode (Node
, AML_EXTERNAL_OP
, 0)) {
555 // If the node is an external definition, check this is a method.
556 // DefExternal := ExternalOp NameString ObjectType ArgumentCount
557 // ExternalOp := 0x15
558 // ObjectType := ByteData
559 // ArgumentCount := ByteData (0 – 7)
560 ObjectType
= (AML_DATA_NODE
*)AmlGetFixedArgument (
561 (AML_OBJECT_NODE
*)Node
,
564 if (IS_AML_DATA_NODE (ObjectType
) &&
565 (ObjectType
->DataType
== EAmlNodeDataTypeUInt
) &&
566 ((ObjectType
->Size
== 1))) {
567 if (*((UINT8
*)ObjectType
->Buffer
) == (UINT8
)EAmlObjTypeMethodObj
) {
568 // The external definition is a method.
571 // The external definition is not a method.
575 // The tree is inconsistent.
581 // This is not a method definition.
585 /** Get the index at which the name of the node is stored.
587 @param [in] ObjectNode Pointer to an object node.
588 Must have the AML_IN_NAMESPACE attribute.
589 @param [out] Index Index of the name in the fixed list of arguments.
591 @retval EFI_SUCCESS The function completed successfully.
592 @retval EFI_INVALID_PARAMETER Invalid parameter.
595 AmlNodeGetNameIndex (
596 IN CONST AML_OBJECT_NODE
* ObjectNode
,
597 OUT EAML_PARSE_INDEX
* Index
600 EAML_PARSE_INDEX NameIndex
;
602 if (!AmlNodeHasAttribute (ObjectNode
, AML_IN_NAMESPACE
) ||
603 (ObjectNode
->AmlByteEncoding
== NULL
) ||
606 return EFI_INVALID_PARAMETER
;
609 NameIndex
= ObjectNode
->AmlByteEncoding
->NameIndex
;
611 if ((NameIndex
> ObjectNode
->AmlByteEncoding
->MaxIndex
) ||
612 (ObjectNode
->AmlByteEncoding
->Format
[NameIndex
] != EAmlName
)) {
614 return EFI_INVALID_PARAMETER
;
622 /** Get the name of the Node.
624 Node must be part of the namespace.
626 @param [in] ObjectNode Pointer to an object node,
627 which is part of the namespace.
629 @return A pointer to the name.
631 Return NULL for the root node.
636 IN CONST AML_OBJECT_NODE
* ObjectNode
640 EAML_PARSE_INDEX NameIndex
;
641 AML_DATA_NODE
* DataNode
;
643 if (!AmlNodeHasAttribute (ObjectNode
, AML_IN_NAMESPACE
)) {
648 // Get the index at which the name is stored in the fixed arguments list.
649 Status
= AmlNodeGetNameIndex (ObjectNode
, &NameIndex
);
650 if (EFI_ERROR (Status
)) {
655 // The name is stored in a Data node.
656 DataNode
= (AML_DATA_NODE
*)ObjectNode
->FixedArgs
[NameIndex
];
657 if (IS_AML_DATA_NODE (DataNode
) &&
658 (DataNode
->DataType
== EAmlNodeDataTypeNameString
)) {
659 return (CHAR8
*)DataNode
->Buffer
;
662 /* Return NULL if no name is found.
663 This can occur if the name of a node is defined as a further
665 E.g.: CreateField (BD03, 0x28, Add (ID03 + 0x08), BF33)
668 The parent of the Add statement is the CreateField statement. This
669 statement defines a name in the AML namespace. This name defined as
670 the fourth fixed argument. It hasn't been parsed yet.