4 Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <Parser/AmlParser.h>
11 #include <AmlCoreInterface.h>
12 #include <AmlDbgPrint/AmlDbgPrint.h>
13 #include <Parser/AmlFieldListParser.h>
14 #include <Parser/AmlMethodParser.h>
15 #include <Parser/AmlResourceDataParser.h>
16 #include <String/AmlString.h>
17 #include <Tree/AmlNode.h>
18 #include <Tree/AmlTree.h>
24 Each ASL Statement is represented in AML as and ObjectNode.
25 Each ObjectNode has an Opcode and has up to six FixedArguments
26 followed by a list of VariableArguments.
29 |- [0][1][2][3][4][5] # Fixed Arguments
30 |- {(VarArg1)->(VarArg2)->(VarArg3)->...N} # Variable Arguments
32 A RootNode is a special type of Object Node that does not have an
33 Opcode or Fixed Arguments. It only has a list of VariableArguments
36 |- {(VarArg1)->(VarArg2)->(VarArg3)->...N} # Variable Arguments
38 A DataNode consists of a data buffer.
40 A FixedArgument or VariableArgument can be either an ObjectNode or
49 Tree generated from the ASL code:
52 |- {(Device statement (ObjectNode))} # Variable Arg of the
55 |- [0] - Device Name (DataNode)(="DEV0") # Fixed Arg0 of the
56 | # Device() statement
58 |- {(Name statement (ObjectNode))} # Variable Arg of the
59 \ # Device() statement
61 |- [0] - Name statement(DataNode)(="VAR0") # Fixed Arg0 of the
63 |- [1] - Value(DataNode)(=0x6) # Fixed Arg1 of the
67 // Forward declaration.
72 IN AML_NODE_HEADER
* Node
,
73 IN OUT AML_STREAM
* FStream
,
74 IN OUT LIST_ENTRY
* NameSpaceRefList
77 /** Function pointer to parse an AML construct.
79 The expected format of the AML construct is passed in the
80 ExpectedFormat argument. The available formats are available in
81 the AML_PARSE_FORMAT enum definition.
83 An object node or a data node is created in the function,
84 and returned through the OutNode parameter. This node should
85 be attached after this function returns.
87 @param [in] ParentNode Parent node to which the parsed
88 AML construct will be attached.
89 @param [in] ExpectedFormat Format of the AML construct to parse.
90 @param [in, out] FStream Forward stream containing the AML bytecode
92 The stream must not be at its end.
93 @param [out] OutNode Pointer holding the node created from the
96 @retval EFI_SUCCESS The function completed successfully.
97 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
98 @retval EFI_INVALID_PARAMETER Invalid parameter.
99 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
104 (*AML_PARSE_FUNCTION
) (
105 IN CONST AML_NODE_HEADER
* Node
,
106 IN AML_PARSE_FORMAT ExpectedFormat
,
107 IN OUT AML_STREAM
* FStream
,
108 OUT AML_NODE_HEADER
** OutNode
111 /** Parse a UInt<X> (where X=8, 16, 32 or 64).
113 A data node is created and returned through the OutNode parameter.
115 @param [in] ParentNode Parent node to which the parsed
116 AML construct will be attached.
117 @param [in] ExpectedFormat Format of the AML construct to parse.
118 @param [in, out] FStream Forward stream containing the AML bytecode
120 The stream must not be at its end.
121 @param [out] OutNode Pointer holding the node created from the
124 @retval EFI_SUCCESS The function completed successfully.
125 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
126 @retval EFI_INVALID_PARAMETER Invalid parameter.
127 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
133 IN CONST AML_NODE_HEADER
* ParentNode
,
134 IN AML_PARSE_FORMAT ExpectedFormat
,
135 IN OUT AML_STREAM
* FStream
,
136 OUT AML_NODE_HEADER
** OutNode
142 if ((!IS_AML_ROOT_NODE (ParentNode
) &&
143 !IS_AML_OBJECT_NODE (ParentNode
)) ||
144 ((ExpectedFormat
!= EAmlUInt8
) &&
145 (ExpectedFormat
!= EAmlUInt16
) &&
146 (ExpectedFormat
!= EAmlUInt32
) &&
147 (ExpectedFormat
!= EAmlUInt64
)) ||
148 !IS_STREAM (FStream
) ||
149 IS_END_OF_STREAM (FStream
) ||
150 !IS_STREAM_FORWARD (FStream
) ||
153 return EFI_INVALID_PARAMETER
;
156 switch (ExpectedFormat
) {
171 return EFI_INVALID_PARAMETER
;
174 Status
= AmlCreateDataNode (
175 AmlTypeToNodeDataType (ExpectedFormat
),
176 AmlStreamGetCurrPos (FStream
),
178 (AML_DATA_NODE
**)OutNode
180 if (EFI_ERROR (Status
)) {
185 AMLDBG_DUMP_RAW (AmlStreamGetCurrPos (FStream
), UIntXSize
);
187 // Move stream forward by the size of UIntX.
188 Status
= AmlStreamProgress (FStream
, UIntXSize
);
189 if (EFI_ERROR (Status
)) {
190 AmlDeleteTree (*OutNode
);
197 /** Parse an AML NameString.
199 A data node is created and returned through the OutNode parameter.
201 @param [in] ParentNode Parent node to which the parsed
202 AML construct will be attached.
203 @param [in] ExpectedFormat Format of the AML construct to parse.
204 @param [in, out] FStream Forward stream containing the AML bytecode
206 The stream must not be at its end.
207 @param [out] OutNode Pointer holding the node created from the
210 @retval EFI_SUCCESS The function completed successfully.
211 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
212 @retval EFI_INVALID_PARAMETER Invalid parameter.
213 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
219 IN CONST AML_NODE_HEADER
* ParentNode
,
220 IN AML_PARSE_FORMAT ExpectedFormat
,
221 IN OUT AML_STREAM
* FStream
,
222 OUT AML_NODE_HEADER
** OutNode
227 CONST UINT8
* Buffer
;
228 CONST AML_BYTE_ENCODING
* ByteEncoding
;
231 if ((!IS_AML_ROOT_NODE (ParentNode
) &&
232 !IS_AML_OBJECT_NODE (ParentNode
)) ||
233 (ExpectedFormat
!= EAmlName
) ||
234 !IS_STREAM (FStream
) ||
235 IS_END_OF_STREAM (FStream
) ||
236 !IS_STREAM_FORWARD (FStream
) ||
239 return EFI_INVALID_PARAMETER
;
242 Buffer
= (CONST UINT8
*)AmlStreamGetCurrPos (FStream
);
243 ByteEncoding
= AmlGetByteEncoding (Buffer
);
244 if ((ByteEncoding
== NULL
) ||
245 ((ByteEncoding
->Attribute
& AML_IS_NAME_CHAR
) == 0)) {
247 return EFI_INVALID_PARAMETER
;
250 // Parse the NameString.
251 Status
= AmlGetNameStringSize ((CONST CHAR8
*)Buffer
, &StrSize
);
252 if ((EFI_ERROR (Status
)) ||
253 (StrSize
> AmlStreamGetFreeSpace (FStream
))) {
255 return EFI_INVALID_PARAMETER
;
258 Status
= AmlCreateDataNode (
259 EAmlNodeDataTypeNameString
,
262 (AML_DATA_NODE
**)OutNode
264 if (EFI_ERROR (Status
)) {
269 AMLDBG_DUMP_RAW (AmlStreamGetCurrPos (FStream
), StrSize
);
271 // Move the stream forward by StrSize.
272 Status
= AmlStreamProgress (FStream
, StrSize
);
273 if (EFI_ERROR (Status
)) {
274 AmlDeleteTree (*OutNode
);
281 /** Parse an AML String.
283 A data node is created and returned through the OutNode parameter.
285 @param [in] ParentNode Parent node to which the parsed
286 AML construct will be attached.
287 @param [in] ExpectedFormat Format of the AML construct to parse.
288 @param [in, out] FStream Forward stream containing the AML bytecode
290 The stream must not be at its end.
291 @param [out] OutNode Pointer holding the node created from the
294 @retval EFI_SUCCESS The function completed successfully.
295 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
296 @retval EFI_INVALID_PARAMETER Invalid parameter.
297 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
303 IN CONST AML_NODE_HEADER
* ParentNode
,
304 IN AML_PARSE_FORMAT ExpectedFormat
,
305 IN OUT AML_STREAM
* FStream
,
306 OUT AML_NODE_HEADER
** OutNode
312 CONST UINT8
* Buffer
;
314 if ((!IS_AML_ROOT_NODE (ParentNode
) &&
315 !IS_AML_OBJECT_NODE (ParentNode
)) ||
316 (ExpectedFormat
!= EAmlString
) ||
317 !IS_STREAM (FStream
) ||
318 IS_END_OF_STREAM (FStream
) ||
319 !IS_STREAM_FORWARD (FStream
) ||
322 return EFI_INVALID_PARAMETER
;
325 Buffer
= (CONST UINT8
*)AmlStreamGetCurrPos (FStream
);
327 // AML String is NULL terminated.
329 // Reading the stream moves the stream forward aswell.
330 Status
= AmlStreamReadByte (FStream
, &Byte
);
331 if (EFI_ERROR (Status
)) {
336 } while (Byte
!= '\0');
338 AMLDBG_DUMP_RAW (Buffer
, StrSize
);
340 Status
= AmlCreateDataNode (
341 AmlTypeToNodeDataType (ExpectedFormat
),
344 (AML_DATA_NODE
**)OutNode
346 ASSERT_EFI_ERROR (Status
);
351 /** Parse an AML object.
353 An object can be resolved as an AML object with an OpCode,
354 or a NameString. An object node or a data node is created
355 and returned through the OutNode parameter.
357 @param [in] ParentNode Parent node to which the parsed
358 AML construct will be attached.
359 @param [in] ExpectedFormat Format of the AML construct to parse.
360 @param [in, out] FStream Forward stream containing the AML bytecode
362 The stream must not be at its end.
363 @param [out] OutNode Pointer holding the node created from the
366 @retval EFI_SUCCESS The function completed successfully.
367 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
368 @retval EFI_INVALID_PARAMETER Invalid parameter.
369 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
375 IN CONST AML_NODE_HEADER
* ParentNode
,
376 IN AML_PARSE_FORMAT ExpectedFormat
,
377 IN OUT AML_STREAM
* FStream
,
378 OUT AML_NODE_HEADER
** OutNode
388 CONST AML_BYTE_ENCODING
* AmlByteEncoding
;
389 CONST UINT8
* Buffer
;
391 if ((!IS_AML_ROOT_NODE (ParentNode
) &&
392 !IS_AML_OBJECT_NODE (ParentNode
)) ||
393 (ExpectedFormat
!= EAmlObject
) ||
394 !IS_STREAM (FStream
) ||
395 IS_END_OF_STREAM (FStream
) ||
396 !IS_STREAM_FORWARD (FStream
) ||
399 return EFI_INVALID_PARAMETER
;
404 // 0. Get the AML Byte encoding.
405 AmlByteEncoding
= AmlGetByteEncoding (AmlStreamGetCurrPos (FStream
));
406 if (AmlByteEncoding
== NULL
) {
408 return EFI_INVALID_PARAMETER
;
411 // 1. Check for NameString.
412 // Indeed a NameString can be found when an AML object is expected.
413 // e.g. VAR0 = 3 // VAR0 is assigned an object which is a UINT.
414 // VAR1 = VAR2 // VAR2 is a NameString.
415 // If this is a NameString, return. A NameString can be a variable, a
416 // method invocation, etc.
417 if ((AmlByteEncoding
->Attribute
& AML_IS_NAME_CHAR
) != 0) {
418 Status
= AmlParseNameString (
424 if (EFI_ERROR (Status
)) {
430 // 2. Determine the OpCode size to move the stream forward.
431 Buffer
= (CONST UINT8
*)AmlStreamGetCurrPos (FStream
);
432 if (*Buffer
== AML_EXT_OP
) {
437 Status
= AmlStreamProgress (FStream
, OpCodeSize
);
438 if (EFI_ERROR (Status
)) {
444 AMLDBG_DUMP_RAW (Buffer
, OpCodeSize
);
446 if (!IS_END_OF_STREAM (FStream
)) {
447 // 3. Parse the PkgLength field, if present.
448 if ((AmlByteEncoding
->Attribute
& AML_HAS_PKG_LENGTH
) != 0) {
449 Buffer
= (CONST UINT8
*)AmlStreamGetCurrPos (FStream
);
450 PkgOffset
= AmlGetPkgLength (Buffer
, &PkgLength
);
451 if (PkgOffset
== 0) {
453 return EFI_INVALID_PARAMETER
;
456 // Print the package length.
457 AMLDBG_DUMP_RAW (Buffer
, PkgOffset
);
459 // Adjust the size of the stream if it is valid package length.
460 FreeSpace
= AmlStreamGetFreeSpace (FStream
);
461 if (FreeSpace
> PkgLength
) {
462 // Reduce the stream size by (FreeSpace - PkgLength) bytes.
463 AmlStreamReduceMaxBufferSize (FStream
, FreeSpace
- PkgLength
);
464 } else if (FreeSpace
!= PkgLength
) {
466 return EFI_INVALID_PARAMETER
;
469 Status
= AmlStreamProgress (FStream
, PkgOffset
);
470 if (EFI_ERROR (Status
)) {
475 } else if ((AmlByteEncoding
->Attribute
& AML_HAS_PKG_LENGTH
) != 0) {
476 // The stream terminated unexpectedly. A PkgLen had to be parsed.
478 return EFI_INVALID_PARAMETER
;
481 // 4. Create an Object Node.
482 Status
= AmlCreateObjectNode (
485 (AML_OBJECT_NODE
**)OutNode
487 ASSERT_EFI_ERROR (Status
);
492 /** Parse a FieldPkgLen.
494 A FieldPkgLen can only be found in a field list, i.e. in a NamedField field
495 element. The PkgLen is otherwise part of the object node structure.
496 A data node is created and returned through the OutNode parameter.
498 @param [in] ParentNode Parent node to which the parsed
499 AML construct will be attached.
500 @param [in] ExpectedFormat Format of the AML construct to parse.
501 @param [in, out] FStream Forward stream containing the AML bytecode
503 The stream must not be at its end.
504 @param [out] OutNode Pointer holding the node created from the
507 @retval EFI_SUCCESS The function completed successfully.
508 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
509 @retval EFI_INVALID_PARAMETER Invalid parameter.
510 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
515 AmlParseFieldPkgLen (
516 IN CONST AML_NODE_HEADER
* ParentNode
,
517 IN AML_PARSE_FORMAT ExpectedFormat
,
518 IN OUT AML_STREAM
* FStream
,
519 OUT AML_NODE_HEADER
** OutNode
524 CONST UINT8
* Buffer
;
528 if (!AmlNodeHasAttribute (
529 (CONST AML_OBJECT_NODE
*)ParentNode
,
532 (ExpectedFormat
!= EAmlFieldPkgLen
) ||
533 !IS_STREAM (FStream
) ||
534 IS_END_OF_STREAM (FStream
) ||
535 !IS_STREAM_FORWARD (FStream
) ||
538 return EFI_INVALID_PARAMETER
;
541 Buffer
= (CONST UINT8
*)AmlStreamGetCurrPos (FStream
);
543 PkgOffset
= AmlGetPkgLength (Buffer
, &PkgLength
);
544 if (PkgOffset
== 0) {
546 return EFI_INVALID_PARAMETER
;
549 // Warning: Since, updating of field elements is not supported, store the
550 // FieldPkgLength in a Data Node as a raw buffer.
551 Status
= AmlCreateDataNode (
552 AmlTypeToNodeDataType (ExpectedFormat
),
555 (AML_DATA_NODE
**)OutNode
557 if (EFI_ERROR (Status
)) {
562 AMLDBG_DUMP_RAW (Buffer
, PkgOffset
);
564 Status
= AmlStreamProgress (FStream
, PkgOffset
);
565 if (EFI_ERROR (Status
)) {
566 Status1
= AmlDeleteNode (*OutNode
);
567 ASSERT_EFI_ERROR (Status1
);
574 /** Array of functions pointers to parse the AML constructs.
576 The AML Byte encoding tables in Aml.c describe the format of the AML
577 statements. The AML_PARSE_FORMAT enum definition lists these constructs
578 and the corresponding parsing functions.
580 AML_PARSE_FUNCTION mParseType
[EAmlParseFormatMax
] = {
582 AmlParseUIntX
, // EAmlUInt8
583 AmlParseUIntX
, // EAmlUInt16
584 AmlParseUIntX
, // EAmlUInt32
585 AmlParseUIntX
, // EAmlUInt64
586 AmlParseObject
, // EAmlObject
587 AmlParseNameString
, // EAmlName
588 AmlParseString
, // EAmlString
589 AmlParseFieldPkgLen
// EAmlFieldPkgLen
592 /** Check whether the NameString stored in the data node is a method invocation.
593 If so, create a method invocation node and return it.
595 @param [in] ParentNode Node to which the parsed AML construct
597 @param [in] DataNode Data node containing a NameString,
598 potentially being a method invocation.
599 @param [in, out] NameSpaceRefList List of namespace reference nodes.
600 @param [out] OutNode Pointer holding the method invocation
601 node if the NameString contained in the
602 data node is a method invocation.
605 @retval EFI_SUCCESS The function completed successfully.
606 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
607 @retval EFI_INVALID_PARAMETER Invalid parameter.
608 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
613 AmlCheckAndParseMethodInvoc (
614 IN CONST AML_NODE_HEADER
* ParentNode
,
615 IN AML_DATA_NODE
* DataNode
,
616 IN OUT LIST_ENTRY
* NameSpaceRefList
,
617 OUT AML_OBJECT_NODE
** OutNode
621 AML_NAMESPACE_REF_NODE
* NameSpaceRefNode
;
622 AML_OBJECT_NODE
* MethodInvocationNode
;
625 if ((!IS_AML_ROOT_NODE (ParentNode
) &&
626 !IS_AML_OBJECT_NODE (ParentNode
)) ||
627 !IS_AML_DATA_NODE (DataNode
) ||
628 (DataNode
->DataType
!= EAmlNodeDataTypeNameString
) ||
629 (NameSpaceRefList
== NULL
) ||
632 return EFI_INVALID_PARAMETER
;
635 // Initialize a stream containing the NameString which is checked.
636 Status
= AmlStreamInit (
640 EAmlStreamDirectionForward
642 if (EFI_ERROR (Status
)) {
647 // Check whether the NameString is a method invocation.
648 NameSpaceRefNode
= NULL
;
649 Status
= AmlIsMethodInvocation (
655 if (EFI_ERROR (Status
)) {
660 MethodInvocationNode
= NULL
;
661 if (NameSpaceRefNode
!= NULL
) {
662 // A matching method definition has been found.
663 // Create a method invocation node.
664 Status
= AmlCreateMethodInvocationNode (
666 (AML_DATA_NODE
*)DataNode
,
667 &MethodInvocationNode
669 if (EFI_ERROR (Status
)) {
675 *OutNode
= MethodInvocationNode
;
680 /** Call the appropriate function to parse the AML construct in the stream.
682 The ExpectedFormat parameter allows to choose the right parsing function.
683 An object node or a data node is created according to format.
685 @param [in] ParentNode Node to which the parsed AML construct
687 @param [in] ExpectedFormat Format of the AML construct to parse.
688 @param [in, out] FStream Forward stream containing the AML
690 The stream must not be at its end.
691 @param [in, out] NameSpaceRefList List of namespace reference nodes.
692 @param [out] OutNode Pointer holding the node created from the
695 @retval EFI_SUCCESS The function completed successfully.
696 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
697 @retval EFI_INVALID_PARAMETER Invalid parameter.
698 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
704 IN CONST AML_NODE_HEADER
* ParentNode
,
705 IN AML_PARSE_FORMAT ExpectedFormat
,
706 IN OUT AML_STREAM
* FStream
,
707 IN OUT LIST_ENTRY
* NameSpaceRefList
,
708 OUT AML_NODE_HEADER
** OutNode
712 AML_PARSE_FUNCTION ParsingFunction
;
713 AML_DATA_NODE
* DataNode
;
714 AML_OBJECT_NODE
* MethodInvocationNode
;
716 if ((!IS_AML_ROOT_NODE (ParentNode
) &&
717 !IS_AML_OBJECT_NODE (ParentNode
)) ||
718 (ExpectedFormat
>= EAmlParseFormatMax
) ||
719 !IS_STREAM (FStream
) ||
720 IS_END_OF_STREAM (FStream
) ||
721 !IS_STREAM_FORWARD (FStream
) ||
722 (NameSpaceRefList
== NULL
) ||
725 return EFI_INVALID_PARAMETER
;
728 ParsingFunction
= mParseType
[ExpectedFormat
];
729 if (ParsingFunction
== NULL
) {
731 return EFI_INVALID_PARAMETER
;
734 // Note: The ParsingFunction moves the stream forward as it
735 // consumes the AML bytecode
736 Status
= ParsingFunction (
742 if (EFI_ERROR (Status
)) {
747 // Check whether the parsed argument is a NameString when an object
748 // is expected. In such case, it could be a method invocation.
749 DataNode
= (AML_DATA_NODE
*)*OutNode
;
750 if (IS_AML_DATA_NODE (DataNode
) &&
751 (DataNode
->DataType
== EAmlNodeDataTypeNameString
) &&
752 (ExpectedFormat
== EAmlObject
)) {
753 Status
= AmlCheckAndParseMethodInvoc (
755 (AML_DATA_NODE
*)*OutNode
,
757 &MethodInvocationNode
);
758 if (EFI_ERROR (Status
)) {
763 // A method invocation node has been created and the DataNode containing
764 // the NameString has been attached to the MethodInvocationNode.
765 // Replace the OutNode with the MethodInvocationNode.
766 if (MethodInvocationNode
!= NULL
) {
767 *OutNode
= (AML_NODE_HEADER
*)MethodInvocationNode
;
774 /** Parse the Bytelist in the stream.
775 According to the content of the stream, create data node(s)
776 and add them to the variable list of arguments.
777 The byte list may be a list of resource data element or a simple byte list.
779 @param [in] BufferNode Object node having a byte list.
780 @param [in, out] FStream Forward stream containing the AML bytecode
782 The stream must not be at its end.
784 @retval EFI_SUCCESS The function completed successfully.
785 @retval EFI_INVALID_PARAMETER Invalid parameter.
786 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
792 IN AML_OBJECT_NODE
* BufferNode
,
793 IN OUT AML_STREAM
* FStream
797 AML_NODE_HEADER
* NewNode
;
798 CONST UINT8
* Buffer
;
801 // Check whether the node is an Object Node and has byte list.
802 if (!AmlNodeHasAttribute (BufferNode
, AML_HAS_BYTE_LIST
) ||
803 !IS_STREAM (FStream
) ||
804 IS_END_OF_STREAM (FStream
) ||
805 !IS_STREAM_FORWARD (FStream
)) {
807 return EFI_INVALID_PARAMETER
;
810 // The buffer contains a list of resource data elements.
811 if (AmlRdIsResourceDataBuffer (FStream
)) {
812 // Parse the resource data elements and add them as data nodes.
813 // AmlParseResourceData() moves the stream forward.
814 Status
= AmlParseResourceData (BufferNode
, FStream
);
815 if (EFI_ERROR (Status
)) {
819 // The buffer doesn't contain a list of resource data elements.
820 // Create a single node holding the whole buffer data.
822 // CreateDataNode checks the Buffer and BufferSize values.
823 Buffer
= (CONST UINT8
*)AmlStreamGetCurrPos (FStream
);
824 BufferSize
= AmlStreamGetFreeSpace (FStream
);
826 Status
= AmlCreateDataNode (
830 (AML_DATA_NODE
**)&NewNode
832 if (EFI_ERROR (Status
)) {
837 Status
= AmlVarListAddTailInternal (
838 (AML_NODE_HEADER
*)BufferNode
,
841 if (EFI_ERROR (Status
)) {
843 AmlDeleteTree (NewNode
);
847 AMLDBG_DUMP_RAW (Buffer
, BufferSize
);
849 // Move the stream forward as we have consumed the Buffer.
850 Status
= AmlStreamProgress (FStream
, BufferSize
);
851 if (EFI_ERROR (Status
)) {
859 /** Parse the list of fixed arguments of the input ObjectNode.
861 For each argument, create a node and add it to the fixed argument list
863 If a fixed argument has children, parse them.
865 @param [in] ObjectNode Object node to parse the fixed arguments
867 @param [in] FStream Forward stream containing the AML
869 The stream must not be at its end.
870 @param [in] NameSpaceRefList List of namespace reference nodes.
872 @retval EFI_SUCCESS The function completed successfully.
873 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
874 @retval EFI_INVALID_PARAMETER Invalid parameter.
875 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
879 AmlParseFixedArguments (
880 IN AML_OBJECT_NODE
* ObjectNode
,
881 IN AML_STREAM
* FStream
,
882 IN LIST_ENTRY
* NameSpaceRefList
887 AML_NODE_HEADER
* FixedArgNode
;
888 AML_STREAM FixedArgFStream
;
890 EAML_PARSE_INDEX TermIndex
;
891 EAML_PARSE_INDEX MaxIndex
;
892 CONST AML_PARSE_FORMAT
* Format
;
894 // Fixed arguments of method invocations node are handled differently.
895 if (!IS_AML_OBJECT_NODE (ObjectNode
) ||
896 AmlNodeCompareOpCode (ObjectNode
, AML_METHOD_INVOC_OP
, 0) ||
897 !IS_STREAM (FStream
) ||
898 IS_END_OF_STREAM (FStream
) ||
899 !IS_STREAM_FORWARD (FStream
) ||
900 (NameSpaceRefList
== NULL
)) {
902 return EFI_INVALID_PARAMETER
;
905 TermIndex
= EAmlParseIndexTerm0
;
906 MaxIndex
= (EAML_PARSE_INDEX
)AmlGetFixedArgumentCount (
907 (AML_OBJECT_NODE
*)ObjectNode
909 if ((ObjectNode
->AmlByteEncoding
!= NULL
) &&
910 (ObjectNode
->AmlByteEncoding
->Format
!= NULL
)) {
911 Format
= ObjectNode
->AmlByteEncoding
->Format
;
914 return EFI_INVALID_PARAMETER
;
917 // Parse all the FixedArgs.
918 while ((TermIndex
< MaxIndex
) &&
919 !IS_END_OF_STREAM (FStream
) &&
920 (Format
[TermIndex
] != EAmlNone
)) {
921 // Initialize a FixedArgStream to parse the current fixed argument.
922 Status
= AmlStreamInitSubStream (FStream
, &FixedArgFStream
);
923 if (EFI_ERROR (Status
)) {
928 // Parse the current fixed argument.
929 Status
= AmlParseArgument (
930 (CONST AML_NODE_HEADER
*)ObjectNode
,
936 if (EFI_ERROR (Status
)) {
941 // Add the fixed argument to the parent node's fixed argument list.
942 // FixedArgNode can be an object or data node.
943 Status
= AmlSetFixedArgument (
944 (AML_OBJECT_NODE
*)ObjectNode
,
948 if (EFI_ERROR (Status
)) {
950 // Delete the sub-tree if the insertion failed.
951 // Otherwise its reference will be lost.
952 // Use DeleteTree because if the argument was a method invocation,
953 // multiple nodes have been created.
954 AmlDeleteTree (FixedArgNode
);
958 // Parse the AML bytecode of the FixedArgNode if this is an object node.
959 if (IS_AML_OBJECT_NODE (FixedArgNode
) &&
960 !IS_END_OF_STREAM (&FixedArgFStream
)) {
961 Status
= AmlParseStream (
966 if (EFI_ERROR (Status
)) {
972 // Move the stream forward as we have consumed the sub-stream.
973 Status
= AmlStreamProgress (
975 AmlStreamGetIndex (&FixedArgFStream
)
977 if (EFI_ERROR (Status
)) {
988 /** Parse the variable list of arguments of the input ObjectNode.
990 For each variable argument, create a node and add it to the variable list of
991 arguments of the Node.
992 If a variable argument has children, parse them recursively.
994 The arguments of method invocation nodes are added to the variable list of
995 arguments of the method invocation node. It is necessary to first get
996 the number of arguments to parse for this kind of node. A method invocation
997 can have at most 7 fixed arguments.
999 @param [in] Node Node to parse the variable arguments
1001 @param [in] FStream Forward stream containing the AML
1003 The stream must not be at its end.
1004 @param [in] NameSpaceRefList List of namespace reference nodes.
1006 @retval EFI_SUCCESS The function completed successfully.
1007 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
1008 @retval EFI_INVALID_PARAMETER Invalid parameter.
1009 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
1013 AmlParseVariableArguments (
1014 IN AML_NODE_HEADER
* Node
,
1015 IN AML_STREAM
* FStream
,
1016 IN LIST_ENTRY
* NameSpaceRefList
1021 BOOLEAN IsMethodInvocation
;
1022 UINT8 MethodInvocationArgCount
;
1024 AML_NODE_HEADER
* VarArgNode
;
1025 AML_STREAM VarArgFStream
;
1027 if ((!AmlNodeHasAttribute (
1028 (CONST AML_OBJECT_NODE
*)Node
,
1031 !IS_AML_ROOT_NODE (Node
)) ||
1032 !IS_STREAM (FStream
) ||
1033 IS_END_OF_STREAM (FStream
) ||
1034 !IS_STREAM_FORWARD (FStream
) ||
1035 (NameSpaceRefList
== NULL
)) {
1037 return EFI_INVALID_PARAMETER
;
1040 Status
= AmlGetMethodInvocationArgCount (
1041 (CONST AML_OBJECT_NODE
*)Node
,
1042 &IsMethodInvocation
,
1043 &MethodInvocationArgCount
1045 if (EFI_ERROR (Status
)) {
1050 // Parse variable arguments while the Stream is not empty.
1051 while (!IS_END_OF_STREAM (FStream
)) {
1052 // If the number of variable arguments are counted, decrement the counter.
1053 if ((IsMethodInvocation
) && (MethodInvocationArgCount
-- == 0)) {
1057 // Initialize a VarArgStream to parse the current variable argument.
1058 Status
= AmlStreamInitSubStream (FStream
, &VarArgFStream
);
1059 if (EFI_ERROR (Status
)) {
1064 // Parse the current variable argument.
1065 Status
= AmlParseArgument (
1072 if (EFI_ERROR (Status
)) {
1077 // Add the variable argument to its parent variable list of arguments.
1078 // VarArgNode can be an object or data node.
1079 Status
= AmlVarListAddTailInternal (
1080 (AML_NODE_HEADER
*)Node
,
1083 if (EFI_ERROR (Status
)) {
1085 // Delete the sub-tree if the insertion failed.
1086 // Otherwise its reference will be lost.
1087 // Use DeleteTree because if the argument was a method invocation,
1088 // multiple nodes have been created.
1089 AmlDeleteTree (VarArgNode
);
1093 // Parse the AML bytecode of the VarArgNode if this is an object node.
1094 if (IS_AML_OBJECT_NODE (VarArgNode
) &&
1095 (!IS_END_OF_STREAM (&VarArgFStream
))) {
1096 Status
= AmlParseStream (VarArgNode
, &VarArgFStream
, NameSpaceRefList
);
1097 if (EFI_ERROR (Status
)) {
1103 // Move the stream forward as we have consumed the sub-stream.
1104 Status
= AmlStreamProgress (
1106 AmlStreamGetIndex (&VarArgFStream
)
1108 if (EFI_ERROR (Status
)) {
1114 // If the number of variable arguments are counted, check all the
1115 // MethodInvocationArgCount have been parsed.
1116 if (IsMethodInvocation
&& (MethodInvocationArgCount
!= 0)) {
1118 return EFI_INVALID_PARAMETER
;
1124 /** Parse the AML stream and populate the root node.
1126 @param [in] RootNode RootNode to which the children are
1128 @param [in, out] FStream Forward stream containing the AML
1130 The stream must not be at its end.
1131 @param [in, out] NameSpaceRefList List of namespace reference nodes.
1133 @retval EFI_SUCCESS The function completed successfully.
1134 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
1135 @retval EFI_INVALID_PARAMETER Invalid parameter.
1136 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
1141 AmlPopulateRootNode (
1142 IN AML_ROOT_NODE
* RootNode
,
1143 IN OUT AML_STREAM
* FStream
,
1144 IN OUT LIST_ENTRY
* NameSpaceRefList
1149 if (!IS_AML_ROOT_NODE (RootNode
) ||
1150 !IS_STREAM (FStream
) ||
1151 IS_END_OF_STREAM (FStream
) ||
1152 !IS_STREAM_FORWARD (FStream
) ||
1153 (NameSpaceRefList
== NULL
)) {
1155 return EFI_INVALID_PARAMETER
;
1158 // A Root Node only has variable arguments.
1159 Status
= AmlParseVariableArguments (
1160 (AML_NODE_HEADER
*)RootNode
,
1164 ASSERT_EFI_ERROR (Status
);
1169 /** Parse the AML stream an populate the object node.
1171 @param [in] ObjectNode ObjectNode to which the children are
1173 @param [in, out] FStream Forward stream containing the AML
1175 The stream must not be at its end.
1176 @param [in, out] NameSpaceRefList List of namespace reference nodes.
1178 @retval EFI_SUCCESS The function completed successfully.
1179 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
1180 @retval EFI_INVALID_PARAMETER Invalid parameter.
1181 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
1186 AmlPopulateObjectNode (
1187 IN AML_OBJECT_NODE
* ObjectNode
,
1188 IN OUT AML_STREAM
* FStream
,
1189 IN OUT LIST_ENTRY
* NameSpaceRefList
1194 if (!IS_AML_OBJECT_NODE (ObjectNode
) ||
1195 !IS_STREAM (FStream
) ||
1196 IS_END_OF_STREAM (FStream
) ||
1197 !IS_STREAM_FORWARD (FStream
) ||
1198 (NameSpaceRefList
== NULL
)) {
1200 return EFI_INVALID_PARAMETER
;
1203 Status
= EFI_SUCCESS
;
1205 // Don't parse the fixed arguments of method invocation nodes.
1206 // The AML encoding for method invocations in the ACPI specification 6.3 is:
1207 // MethodInvocation := NameString TermArgList
1208 // Since the AML specification does not define an OpCode for method
1209 // invocation, this AML parser defines a pseudo opcode and redefines the
1210 // grammar for simplicity as:
1211 // MethodInvocation := MethodInvocationOp NameString ArgumentCount TermArgList
1212 // ArgumentCount := ByteData
1213 // Due to this difference, the MethodInvocationOp and the fixed argument
1214 // i.e. ArgumentCount is not available in the AML stream and need to be
1215 // handled differently.
1216 if (!AmlNodeCompareOpCode (ObjectNode
, AML_METHOD_INVOC_OP
, 0)) {
1217 // Parse the fixed list of arguments.
1218 Status
= AmlParseFixedArguments (
1223 if (EFI_ERROR (Status
)) {
1229 // Save the association [node reference/pathname] in the NameSpaceRefList.
1230 // This allows to identify method invocations from other namespace
1231 // paths. Method invocation need to be parsed differently.
1232 if (AmlNodeHasAttribute (
1233 (CONST AML_OBJECT_NODE
*)ObjectNode
,
1234 AML_IN_NAMESPACE
)) {
1235 Status
= AmlAddNameSpaceReference (
1236 (CONST AML_OBJECT_NODE
*)ObjectNode
,
1239 if (EFI_ERROR (Status
)) {
1245 if (!IS_END_OF_STREAM (FStream
)) {
1246 // Parse the variable list of arguments if present.
1247 if (AmlNodeHasAttribute (ObjectNode
, AML_HAS_CHILD_OBJ
)) {
1248 Status
= AmlParseVariableArguments (
1249 (AML_NODE_HEADER
*)ObjectNode
,
1253 } else if (AmlNodeHasAttribute (ObjectNode
, AML_HAS_BYTE_LIST
)) {
1254 // Parse the byte list if present.
1255 Status
= AmlParseByteList (
1259 } else if (AmlNodeHasAttribute (ObjectNode
, AML_HAS_FIELD_LIST
)) {
1260 // Parse the field list if present.
1261 Status
= AmlParseFieldList (
1268 // Check status and assert
1269 if (EFI_ERROR (Status
)) {
1277 /** Invoke the appropriate parsing functions based on the Node type.
1279 @param [in] Node Node from which the children are parsed.
1280 Must be a root node or an object node.
1281 @param [in] FStream Forward stream containing the AML
1283 The stream must not be at its end.
1284 @param [in] NameSpaceRefList List of namespace reference nodes.
1286 @retval EFI_SUCCESS The function completed successfully.
1287 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
1288 @retval EFI_INVALID_PARAMETER Invalid parameter.
1289 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
1295 IN AML_NODE_HEADER
* Node
,
1296 IN AML_STREAM
* FStream
,
1297 IN LIST_ENTRY
* NameSpaceRefList
1302 if (IS_AML_ROOT_NODE (Node
)) {
1303 Status
= AmlPopulateRootNode (
1304 (AML_ROOT_NODE
*)Node
,
1308 if (EFI_ERROR (Status
)) {
1312 } else if (IS_AML_OBJECT_NODE (Node
)) {
1313 Status
= AmlPopulateObjectNode (
1314 (AML_OBJECT_NODE
*)Node
,
1318 if (EFI_ERROR (Status
)) {
1323 // Data node or other.
1325 Status
= EFI_INVALID_PARAMETER
;
1331 /** Parse the definition block.
1333 This function parses the whole AML blob. It starts with the ACPI DSDT/SSDT
1334 header and then parses the AML bytestream.
1335 A tree structure is returned via the RootPtr.
1336 The tree must be deleted with the AmlDeleteTree function.
1338 @param [in] DefinitionBlock Pointer to the definition block.
1339 @param [out] RootPtr Pointer to the root node of the tree.
1341 @retval EFI_SUCCESS The function completed successfully.
1342 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
1343 @retval EFI_INVALID_PARAMETER Invalid parameter.
1344 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
1348 AmlParseDefinitionBlock (
1349 IN CONST EFI_ACPI_DESCRIPTION_HEADER
* DefinitionBlock
,
1350 OUT AML_ROOT_NODE
** RootPtr
1356 AML_ROOT_NODE
* Root
;
1358 LIST_ENTRY NameSpaceRefList
;
1361 UINT32 MaxBufferSize
;
1363 if ((DefinitionBlock
== NULL
) ||
1364 (RootPtr
== NULL
)) {
1366 return EFI_INVALID_PARAMETER
;
1369 Buffer
= (UINT8
*)DefinitionBlock
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER
);
1370 if (DefinitionBlock
->Length
< sizeof (EFI_ACPI_DESCRIPTION_HEADER
)) {
1372 return EFI_INVALID_PARAMETER
;
1374 MaxBufferSize
= DefinitionBlock
->Length
-
1375 (UINT32
)sizeof (EFI_ACPI_DESCRIPTION_HEADER
);
1377 // Create a root node.
1378 Status
= AmlCreateRootNode (
1379 (EFI_ACPI_DESCRIPTION_HEADER
*)DefinitionBlock
,
1382 if (EFI_ERROR (Status
)) {
1389 if (MaxBufferSize
== 0) {
1393 // Initialize a stream to parse the AML bytecode.
1394 Status
= AmlStreamInit (
1398 EAmlStreamDirectionForward
1400 if (EFI_ERROR (Status
)) {
1405 // Initialize the NameSpaceRefList, holding references to nodes declaring
1406 // a name in the AML namespace.
1407 InitializeListHead (&NameSpaceRefList
);
1409 // Parse the whole AML blob.
1410 Status
= AmlParseStream (
1411 (AML_NODE_HEADER
*)Root
,
1415 if (EFI_ERROR (Status
)) {
1420 // Check the whole AML blob has been parsed.
1421 if (!IS_END_OF_STREAM (&Stream
)) {
1423 Status
= EFI_INVALID_PARAMETER
;
1427 // Print the list of NameSpace reference nodes.
1428 // AmlDbgPrintNameSpaceRefList (&NameSpaceRefList);
1430 // Delete the NameSpaceRefList
1435 AmlDeleteTree ((AML_NODE_HEADER
*)Root
);
1439 Status1
= AmlDeleteNameSpaceRefList (&NameSpaceRefList
);
1440 if (EFI_ERROR (Status1
)) {
1442 if (!EFI_ERROR (Status
)) {