4 Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <Parser/AmlMethodParser.h>
11 #include <AmlCoreInterface.h>
12 #include <AmlDbgPrint/AmlDbgPrint.h>
13 #include <NameSpace/AmlNameSpace.h>
14 #include <Parser/AmlParser.h>
15 #include <Tree/AmlNode.h>
16 #include <Tree/AmlTree.h>
17 #include <String/AmlString.h>
19 /** Delete a namespace reference node and its pathname.
21 It is the caller's responsibility to check the NameSpaceRefNode has been
22 removed from any list the node is part of.
24 @param [in] NameSpaceRefNode Pointer to an AML_NAMESPACE_REF_NODE.
26 @retval EFI_SUCCESS The function completed successfully.
27 @retval EFI_INVALID_PARAMETER Invalid parameter.
32 AmlDeleteNameSpaceRefNode (
33 IN AML_NAMESPACE_REF_NODE
* NameSpaceRefNode
36 if (NameSpaceRefNode
== NULL
) {
38 return EFI_INVALID_PARAMETER
;
41 if (NameSpaceRefNode
->RawAbsolutePath
!= NULL
) {
42 FreePool ((CHAR8
*)NameSpaceRefNode
->RawAbsolutePath
);
45 return EFI_INVALID_PARAMETER
;
48 FreePool (NameSpaceRefNode
);
52 /** Delete a list of namespace reference nodes.
54 @param [in] NameSpaceRefList List of namespace reference nodes.
56 @retval EFI_SUCCESS The function completed successfully.
57 @retval EFI_INVALID_PARAMETER Invalid parameter.
61 AmlDeleteNameSpaceRefList (
62 IN LIST_ENTRY
* NameSpaceRefList
66 LIST_ENTRY
* CurrentLink
;
68 if (NameSpaceRefList
== NULL
) {
70 return EFI_INVALID_PARAMETER
;
73 while (!IsListEmpty (NameSpaceRefList
)) {
74 CurrentLink
= NameSpaceRefList
->ForwardLink
;
75 RemoveEntryList (CurrentLink
);
76 Status
= AmlDeleteNameSpaceRefNode (
77 (AML_NAMESPACE_REF_NODE
*)CurrentLink
79 if (EFI_ERROR (Status
)) {
88 /** Create an AML_NAMESPACE_REF_NODE.
90 A Buffer is allocated to store the raw AML absolute path.
92 @param [in] ObjectNode Node being part of the namespace.
93 Must be have the AML_IN_NAMESPACE
95 @param [in] RawAbsolutePath AML raw absolute path of the ObjectNode.
96 A raw NameString is a concatenated list
97 of 4 chars long names.
98 @param [in] RawAbsolutePathSize Size of the RawAbsolutePath buffer.
99 @param [out] NameSpaceRefNodePtr The created AML_METHOD_REF_NODE.
101 @retval EFI_SUCCESS The function completed successfully.
102 @retval EFI_INVALID_PARAMETER Invalid parameter.
103 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
108 AmlCreateMethodRefNode (
109 IN CONST AML_OBJECT_NODE
* ObjectNode
,
110 IN CONST CHAR8
* RawAbsolutePath
,
111 IN UINT32 RawAbsolutePathSize
,
112 OUT AML_NAMESPACE_REF_NODE
** NameSpaceRefNodePtr
115 AML_NAMESPACE_REF_NODE
* NameSpaceRefNode
;
117 if (!AmlNodeHasAttribute (ObjectNode
, AML_IN_NAMESPACE
) ||
118 (RawAbsolutePath
== NULL
) ||
119 (RawAbsolutePathSize
== 0) ||
120 (NameSpaceRefNodePtr
== NULL
)) {
122 return EFI_INVALID_PARAMETER
;
125 NameSpaceRefNode
= AllocateZeroPool (sizeof (AML_NAMESPACE_REF_NODE
));
126 if (NameSpaceRefNode
== NULL
) {
128 return EFI_OUT_OF_RESOURCES
;
131 NameSpaceRefNode
->RawAbsolutePathSize
= RawAbsolutePathSize
;
132 NameSpaceRefNode
->RawAbsolutePath
= AllocateCopyPool (
136 if (NameSpaceRefNode
->RawAbsolutePath
== NULL
) {
137 FreePool (NameSpaceRefNode
);
139 return EFI_OUT_OF_RESOURCES
;
142 InitializeListHead (&NameSpaceRefNode
->Link
);
144 NameSpaceRefNode
->NodeRef
= ObjectNode
;
145 *NameSpaceRefNodePtr
= NameSpaceRefNode
;
150 #if !defined (MDEPKG_NDEBUG)
152 /** Print the list of raw absolute paths of the NameSpace reference list.
154 @param [in] NameSpaceRefList List of NameSpace reference nodes.
158 AmlDbgPrintNameSpaceRefList (
159 IN CONST LIST_ENTRY
* NameSpaceRefList
162 LIST_ENTRY
* CurrLink
;
163 AML_NAMESPACE_REF_NODE
* CurrNameSpaceNode
;
165 if (NameSpaceRefList
== NULL
) {
170 DEBUG ((DEBUG_INFO
, "AmlMethodParser: List of available raw AML paths:\n"));
172 CurrLink
= NameSpaceRefList
->ForwardLink
;
173 while (CurrLink
!= NameSpaceRefList
) {
174 CurrNameSpaceNode
= (AML_NAMESPACE_REF_NODE
*)CurrLink
;
178 CurrNameSpaceNode
->RawAbsolutePath
,
179 CurrNameSpaceNode
->RawAbsolutePathSize
181 DEBUG ((DEBUG_INFO
, "\n"));
183 CurrLink
= CurrLink
->ForwardLink
;
186 DEBUG ((DEBUG_INFO
, "\n"));
189 #endif // MDEPKG_NDEBUG
191 /** From a forward stream pointing to a NameString,
192 initialize a raw backward stream.
195 Fstream: CurrPos EndOfStream
197 +-----------------------------------------+
198 |^^^[Multi-name prefix]AAAA.BBBB.CCCC |
199 +-----------------------------------------+
201 RawPathNameBStream: EndOfStream CurrPos
204 No memory is allocated when initializing the stream.
206 @param [in] FStream Forward stream pointing to a NameString.
207 The stream must not be at its end.
208 @param [out] RawPathNameBStream Backward stream containing the
211 @retval EFI_SUCCESS The function completed successfully.
212 @retval EFI_INVALID_PARAMETER Invalid parameter.
217 AmlInitRawPathBStream (
218 IN CONST AML_STREAM
* FStream
,
219 OUT AML_STREAM
* RawPathNameBStream
224 UINT8
* RawPathBuffer
;
225 CONST CHAR8
* Buffer
;
231 if (!IS_STREAM (FStream
) ||
232 IS_END_OF_STREAM (FStream
) ||
233 !IS_STREAM_FORWARD (FStream
) ||
234 (RawPathNameBStream
== NULL
)) {
236 return EFI_INVALID_PARAMETER
;
239 Buffer
= (CONST CHAR8
*)AmlStreamGetCurrPos (FStream
);
240 if (Buffer
== NULL
) {
242 return EFI_INVALID_PARAMETER
;
245 // Parse the NameString information.
246 Status
= AmlParseNameStringInfo (
252 if (EFI_ERROR (Status
)) {
257 // Get the beginning of the raw NameString.
258 RawPathBuffer
= (UINT8
*)AmlGetFirstNameSeg (
263 if (RawPathBuffer
== NULL
) {
265 return EFI_INVALID_PARAMETER
;
268 // Initialize a backward stream containing the raw path.
269 Status
= AmlStreamInit (
272 (SegCount
* AML_NAME_SEG_SIZE
),
273 EAmlStreamDirectionBackward
275 ASSERT_EFI_ERROR (Status
);
280 /** Get the first node in the ParentNode branch that is part of the
281 AML namespace and has its name defined.
283 This is different from getting the first namespace node. This function is
284 necessary because an absolute path is built while the tree is not complete
285 yet. The parsing is ongoing.
287 For instance, the ASL statement "CreateXXXField ()" adds a field in the
288 AML namespace, but the name it defines is the last fixed argument of the
289 corresponding object.
290 If an AML path is referenced in its first fixed argument, it is not
291 possible to resolve the name of the CreateXXXField object. However, the AML
292 path is not part of the scope created by the CreateXXXField object, so this
293 scope can be skipped.
295 In the following ASL code, the method invocation to MET0 is done in the
296 "CreateField" statement. The "CreateField" statement defines the "FIEL"
297 path in the AML namespace. However, MET0 must be not be resolved in the
298 "CreateField" object scope. It needs to be resolved in its parent.
300 Method (MET0, 0,,, BuffObj) {
301 Return (Buffer (0x1000) {})
303 CreateField (MET0(), 0x100, 0x4, FIEL)
305 @param [in] Node Node to get the first named node from, in
307 @param [out] OutNamedNode First named node in Node's hierarchy.
309 @retval EFI_SUCCESS The function completed successfully.
310 @retval EFI_INVALID_PARAMETER Invalid parameter.
315 AmlGetFirstNamedAncestorNode (
316 IN CONST AML_NODE_HEADER
* Node
,
317 OUT AML_NODE_HEADER
** OutNamedNode
321 CONST AML_NODE_HEADER
* NameSpaceNode
;
323 if ((!IS_AML_OBJECT_NODE (Node
) &&
324 !IS_AML_ROOT_NODE (Node
)) ||
325 (OutNamedNode
== NULL
)) {
327 return EFI_INVALID_PARAMETER
;
330 // If Node is not the root node and doesn't have a name defined yet,
331 // get the ancestor NameSpace node.
332 while (!IS_AML_ROOT_NODE (Node
) &&
333 !(AmlNodeHasAttribute (
334 (CONST AML_OBJECT_NODE
*)Node
,
336 AmlNodeGetName ((CONST AML_OBJECT_NODE
*)Node
) != NULL
)) {
337 Status
= AmlGetFirstAncestorNameSpaceNode (
339 (AML_NODE_HEADER
**)&NameSpaceNode
341 if (EFI_ERROR (Status
)) {
345 // The NameSpaceNode may not have its name defined as yet. In this
346 // case get the next ancestor node.
347 Node
= NameSpaceNode
;
350 *OutNamedNode
= (AML_NODE_HEADER
*)Node
;
355 /** From a ParentNode and a forward stream pointing to a relative path,
356 build a raw AML absolute path and return it in a backward stream.
358 No memory is allocated in this function, the out stream must be initialized
359 with a buffer long enough to hold any raw absolute AML path.
361 @param [in] ParentNode Parent node of the namespace
362 node from which the absolute
363 path is built. ParentNode isn't
364 necessarily a namespace node.
365 Must be a root or an object node.
366 @param [in] PathnameFStream Forward stream pointing to the
367 beginning of a pathname (any
369 The stream must not be at its end.
370 @param [in, out] AbsolutePathBStream Backward stream where the raw
371 absolute path is written. The
372 stream must be already initialized.
373 The stream must not be at its end.
375 @retval EFI_SUCCESS The function completed successfully.
376 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
377 @retval EFI_INVALID_PARAMETER Invalid parameter.
382 AmlBuildRawMethodAbsolutePath (
383 IN CONST AML_NODE_HEADER
* ParentNode
,
384 IN CONST AML_STREAM
* PathnameFStream
,
385 IN OUT AML_STREAM
* AbsolutePathBStream
390 AML_NODE_HEADER
* NamedParentNode
;
391 UINT8
* RawPathBuffer
;
392 CONST CHAR8
* CurrPos
;
398 if ((!IS_AML_OBJECT_NODE (ParentNode
) &&
399 !IS_AML_ROOT_NODE (ParentNode
)) ||
400 !IS_STREAM (PathnameFStream
) ||
401 IS_END_OF_STREAM (PathnameFStream
) ||
402 !IS_STREAM_FORWARD (PathnameFStream
) ||
403 !IS_STREAM (AbsolutePathBStream
) ||
404 IS_END_OF_STREAM (AbsolutePathBStream
) ||
405 !IS_STREAM_BACKWARD (AbsolutePathBStream
)) {
407 return EFI_INVALID_PARAMETER
;
410 CurrPos
= (CONST CHAR8
*)AmlStreamGetCurrPos (PathnameFStream
);
411 if (CurrPos
== NULL
) {
413 return EFI_INVALID_PARAMETER
;
416 // Parse the NameString information.
417 Status
= AmlParseNameStringInfo (
423 if (EFI_ERROR (Status
)) {
428 // Copy the method invocation raw relative path at the end of the Stream.
430 // Get the beginning of the raw NameString.
431 RawPathBuffer
= (UINT8
*)AmlGetFirstNameSeg (
437 Status
= AmlStreamWrite (
440 SegCount
* AML_NAME_SEG_SIZE
442 if (EFI_ERROR (Status
)) {
448 // If the pathname contained an absolute path, this is finished, return.
453 // Get the first named node of the parent node in its hierarchy.
454 Status
= AmlGetFirstNamedAncestorNode (ParentNode
, &NamedParentNode
);
455 if (EFI_ERROR (Status
)) {
460 // Build the raw absolute path of the namespace node.
461 Status
= AmlGetRawNameSpacePath (
466 ASSERT_EFI_ERROR (Status
);
471 /** Compare two raw NameStrings stored in forward streams.
472 Compare them NameSeg by NameSeg (a NameSeg is 4 bytes long).
474 The two raw NameStrings can be of different size.
476 @param [in] RawFStream1 First forward stream to compare.
477 Points to the beginning of the raw NameString.
478 @param [in] RawFStream2 Second forward stream to compare.
479 Points to the beginning of the raw NameString.
480 @param [out] CompareCount Count of identic bytes.
481 Must be a multiple of 4 (size of a NameSeg).
483 @retval EFI_SUCCESS The function completed successfully.
484 @retval EFI_INVALID_PARAMETER Invalid parameter.
489 AmlCompareRawNameString (
490 IN CONST AML_STREAM
* RawFStream1
,
491 IN CONST AML_STREAM
* RawFStream2
,
492 OUT UINT32
* CompareCount
498 AML_STREAM RawFStream1Clone
;
499 AML_STREAM RawFStream2Clone
;
504 // Raw NameStrings have a size that is a multiple of the size of NameSegs.
505 if (!IS_STREAM (RawFStream1
) ||
506 IS_END_OF_STREAM (RawFStream1
) ||
507 !IS_STREAM_FORWARD (RawFStream1
) ||
508 !IS_STREAM (RawFStream2
) ||
509 IS_END_OF_STREAM (RawFStream2
) ||
510 (CompareCount
== NULL
)) {
512 return EFI_INVALID_PARAMETER
;
515 Stream1Size
= AmlStreamGetFreeSpace (RawFStream1
);
516 if ((Stream1Size
& (AML_NAME_SEG_SIZE
- 1)) != 0) {
518 return EFI_INVALID_PARAMETER
;
521 Stream2Size
= AmlStreamGetFreeSpace (RawFStream2
);
522 if ((Stream2Size
& (AML_NAME_SEG_SIZE
- 1)) != 0) {
524 return EFI_INVALID_PARAMETER
;
527 Status
= AmlStreamClone (RawFStream1
, &RawFStream1Clone
);
528 if (EFI_ERROR (Status
)) {
533 Status
= AmlStreamClone (RawFStream2
, &RawFStream2Clone
);
534 if (EFI_ERROR (Status
)) {
539 CompareLen
= MIN (Stream1Size
, Stream2Size
);
541 // Check there is enough space for a NameSeg in both Stream1 and Stream2.
542 while (Index
< CompareLen
) {
548 // NameSegs are different. Break.
552 Status
= AmlStreamProgress (&RawFStream1Clone
, AML_NAME_SEG_SIZE
);
553 if (EFI_ERROR (Status
)) {
557 Status
= AmlStreamProgress (&RawFStream2Clone
, AML_NAME_SEG_SIZE
);
558 if (EFI_ERROR (Status
)) {
563 Index
+= AML_NAME_SEG_SIZE
;
566 *CompareCount
= Index
;
571 /** Check whether an alias can be resolved to a method definition.
573 Indeed, the following ASL code must be handled:
580 When searching for \ALI1 in the AML NameSpace, it resolves to \ALI0.
581 When searching for \ALI0 in the AML NameSpace, it resolves to \MET0.
582 When searching for \MET0 in the AML NameSpace, it resolves to a method
585 This method is a wrapper to recursively call AmlFindMethodDefinition.
587 @param [in] AliasNode Pointer to an Alias object node.
588 @param [in] NameSpaceRefList List of NameSpaceRef nodes.
589 @param [out] OutNameSpaceRefNode If success, and if the alias is resolved
590 to a method definition (this can go
591 through other alias indirections),
592 containing the corresponding
595 @retval EFI_SUCCESS The function completed successfully.
596 @retval EFI_INVALID_PARAMETER Invalid parameter.
601 AmlResolveAliasMethod (
602 IN CONST AML_OBJECT_NODE
* AliasNode
,
603 IN CONST LIST_ENTRY
* NameSpaceRefList
,
604 OUT AML_NAMESPACE_REF_NODE
** OutNameSpaceRefNode
608 AML_STREAM SourceAliasFStream
;
609 CONST AML_DATA_NODE
* DataNode
;
611 if (!AmlNodeCompareOpCode (AliasNode
, AML_ALIAS_OP
, 0) ||
612 (NameSpaceRefList
== NULL
) ||
613 (OutNameSpaceRefNode
== NULL
)) {
615 return EFI_INVALID_PARAMETER
;
618 // The aliased NameString (the source name) is the first fixed argument,
619 // cf. ACPI6.3 spec, s19.6.4: Alias (SourceObject, AliasObject)
620 DataNode
= (CONST AML_DATA_NODE
*)AmlGetFixedArgument (
621 (AML_OBJECT_NODE
*)AliasNode
,
624 if (DataNode
== NULL
) {
626 return EFI_INVALID_PARAMETER
;
629 // Initialize a stream on the source alias NameString.
630 Status
= AmlStreamInit (
634 EAmlStreamDirectionForward
636 if (EFI_ERROR (Status
)) {
641 // Recursively check whether the source alias NameString
642 // is a method invocation.
643 Status
= AmlIsMethodInvocation (
644 AmlGetParent ((AML_NODE_HEADER
*)AliasNode
),
649 if (EFI_ERROR (Status
)) {
656 /** Iterate through the MethodList to find the best namespace resolution.
657 If the pathname resolves to a method definition, returns it.
659 For instance, if the AML namespace is:
661 \-MET0 <- Device definition, absolute path: \MET0
663 \-MET0 <- Method definition, absolute path: \AAAA.MET0
664 \-MET1 <- Method definition, absolute path: \AAAA.MET1
668 \-MET0 <- Method definition, absolute path: \AAAA.BBBB.CCCC.DDDD.MET0
670 The list of the available pathnames is:
672 - \MET0 <- Device definition
674 - \AAAA.MET0 <- Method definition
675 - \AAAA.MET1 <- Method definition
678 - \AAAA.BBBB.CCCC.DDDD
679 - \AAAA.BBBB.CCCC.DDDD.MET0 <- Method definition
681 Depending on where the method invocation is done, the method definition
682 referenced changes. If the method call "MET0" is done from
684 1. Identify which pathnames end with "MET0":
685 - \MET0 <- Device definition
686 - \AAAA.MET0 <- Method definition
687 - \AAAA.BBBB.CCCC.DDDD.MET0 <- Method definition
688 2. Resolve the method invocation:
689 - \AAAA.MET0 <- Method definition
690 3. \AAAA.MET0 is a method definition, so return the corresponding
693 @param [in] RawAbsolutePathFStream Forward stream pointing to a raw
695 The stream must not be at its end.
696 @param [in] RawPathNameBStream Backward stream pointing to a raw
697 pathname. This raw pathname is the
698 raw NameString of namespace node.
699 The stream must not be at its end.
700 @param [in] NameSpaceRefList List of NameSpaceRef nodes.
701 @param [out] OutNameSpaceRefNode If the two input paths are
702 referencing a method definition,
703 returns the corresponding
706 @retval EFI_SUCCESS The function completed successfully.
707 @retval EFI_INVALID_PARAMETER Invalid parameter.
712 AmlFindMethodDefinition (
713 IN CONST AML_STREAM
* RawAbsolutePathFStream
,
714 IN CONST AML_STREAM
* RawPathNameBStream
,
715 IN CONST LIST_ENTRY
* NameSpaceRefList
,
716 OUT AML_NAMESPACE_REF_NODE
** OutNameSpaceRefNode
721 LIST_ENTRY
* NextLink
;
723 // To resolve a pathname, scope levels need to be compared.
724 UINT32 NameSegScopeCount
;
725 UINT32 PathNameSegScopeCount
;
726 UINT32 ProbedScopeCount
;
727 UINT32 BestScopeCount
;
729 AML_STREAM ProbedRawAbsoluteFStream
;
730 AML_STREAM ProbedRawAbsoluteBStream
;
732 AML_NAMESPACE_REF_NODE
* ProbedNameSpaceRefNode
;
733 AML_NAMESPACE_REF_NODE
* BestNameSpaceRefNode
;
735 if (!IS_STREAM (RawAbsolutePathFStream
) ||
736 IS_END_OF_STREAM (RawAbsolutePathFStream
) ||
737 !IS_STREAM_FORWARD (RawAbsolutePathFStream
) ||
738 ((AmlStreamGetIndex (RawAbsolutePathFStream
) &
739 (AML_NAME_SEG_SIZE
- 1)) != 0) ||
740 !IS_STREAM (RawPathNameBStream
) ||
741 IS_END_OF_STREAM (RawPathNameBStream
) ||
742 !IS_STREAM_BACKWARD (RawPathNameBStream
) ||
743 ((AmlStreamGetIndex (RawPathNameBStream
) &
744 (AML_NAME_SEG_SIZE
- 1)) != 0) ||
745 (NameSpaceRefList
== NULL
) ||
746 (OutNameSpaceRefNode
== NULL
)) {
748 return EFI_INVALID_PARAMETER
;
751 DEBUG ((DEBUG_VERBOSE
, "AmlMethodParser: Checking absolute name: "));
754 (CONST CHAR8
*)AmlStreamGetCurrPos (RawAbsolutePathFStream
),
755 AmlStreamGetMaxBufferSize (RawAbsolutePathFStream
)
757 DEBUG ((DEBUG_VERBOSE
, ".\n"));
759 BestNameSpaceRefNode
= NULL
;
761 NameSegScopeCount
= AmlStreamGetMaxBufferSize (RawAbsolutePathFStream
);
762 PathNameSegScopeCount
= AmlStreamGetMaxBufferSize (RawPathNameBStream
);
764 // Iterate through the raw AML absolute path to find the best match.
765 DEBUG ((DEBUG_VERBOSE
, "AmlMethodParser: Comparing with: "));
766 NextLink
= NameSpaceRefList
->ForwardLink
;
767 while (NextLink
!= NameSpaceRefList
) {
768 ProbedNameSpaceRefNode
= (AML_NAMESPACE_REF_NODE
*)NextLink
;
770 // Print the raw absolute path of the probed node.
773 ProbedNameSpaceRefNode
->RawAbsolutePath
,
774 ProbedNameSpaceRefNode
->RawAbsolutePathSize
776 DEBUG ((DEBUG_VERBOSE
, "; "));
778 // If the raw AML absolute path of the probed node is longer than the
779 // searched pathname, continue.
780 // E.g.: The method call \MET0 cannot resolve to a method defined at
781 // \AAAA.MET0. The method definition is out of scope.
782 if (PathNameSegScopeCount
> ProbedNameSpaceRefNode
->RawAbsolutePathSize
) {
783 NextLink
= NextLink
->ForwardLink
;
787 // Initialize a backward stream for the probed node.
788 // This stream is used to compare the ending of the pathnames.
789 // E.g. if the method searched ends with "MET0", pathnames not ending with
790 // "MET0" should be skipped.
791 Status
= AmlStreamInit (
792 &ProbedRawAbsoluteBStream
,
793 (UINT8
*)ProbedNameSpaceRefNode
->RawAbsolutePath
,
794 ProbedNameSpaceRefNode
->RawAbsolutePathSize
,
795 EAmlStreamDirectionBackward
797 if (EFI_ERROR (Status
)) {
802 // Compare the pathname endings. If they don't match, continue.
805 &ProbedRawAbsoluteBStream
,
806 AmlStreamGetMaxBufferSize (RawPathNameBStream
))) {
807 NextLink
= NextLink
->ForwardLink
;
811 // Initialize a forward stream for the probed node.
812 // This stream is used to count how many scope levels from the root
813 // are common with the probed node. The more there are, the better it is.
814 // E.g.: For the method invocation \AAAA.BBBB.MET0, if there are 2
815 // pathnames ending with MET0:
816 // - \AAAA.MET0 has 1 NameSeg in common with \AAAA.BBBB.MET0
817 // from the root (this is "AAAA");
818 // - \MET0 has 0 NameSeg in common with \AAAA.BBBB.MET0
820 // Thus, the best match is \AAAA.MET0.
821 Status
= AmlStreamInit (
822 &ProbedRawAbsoluteFStream
,
823 (UINT8
*)ProbedNameSpaceRefNode
->RawAbsolutePath
,
824 ProbedNameSpaceRefNode
->RawAbsolutePathSize
,
825 EAmlStreamDirectionForward
827 if (EFI_ERROR (Status
)) {
832 // Count how many namespace levels are in common from the root.
833 Status
= AmlCompareRawNameString (
834 RawAbsolutePathFStream
,
835 &ProbedRawAbsoluteFStream
,
838 if (EFI_ERROR (Status
)) {
840 return EFI_INVALID_PARAMETER
;
843 if (ProbedScopeCount
== NameSegScopeCount
) {
844 // This is a perfect match. Exit the loop.
845 BestNameSpaceRefNode
= ProbedNameSpaceRefNode
;
847 } else if (ProbedScopeCount
> BestScopeCount
) {
848 // The probed node has more scope levels in common than the
849 // last best match. Update the best match.
850 BestScopeCount
= ProbedScopeCount
;
851 BestNameSpaceRefNode
= ProbedNameSpaceRefNode
;
852 } else if (ProbedScopeCount
== BestScopeCount
) {
853 // The probed node has the same number of scope levels in
854 // common as the last best match.
855 if (ProbedScopeCount
== 0) {
856 // There was not best match previously. Set it.
857 BestNameSpaceRefNode
= ProbedNameSpaceRefNode
;
859 // (ProbedScopeCount != 0)
860 // If there is an equivalent candidate, the best has the shortest
861 // absolute path. Indeed, a similar ProbedScopeCount and a longer
862 // path means the definition is out of the scope.
863 // E.g.: For the method invocation \AAAA.BBBB.MET0, if there are 2
864 // pathnames ending with MET0:
865 // - \AAAA.MET0 has 1 NameSegs in common with \AAAA.BBBB.MET0
866 // from the root (this is "AAAA");
867 // - \AAAA.CCCC.MET0 has 1 NameSegs in common with
868 // \AAAA.BBBB.MET0 from the root (this is "AAAA");
869 // As \AAAA.CCCC.MET0 is longer than \AAAA.MET0, it means that
870 // the pathname could have matched on more NameSegs, but it
871 // didn't because it is out of scope.
872 // Thus, the best match is \AAAA.MET0.
873 if (AmlStreamGetIndex (&ProbedRawAbsoluteFStream
) <
874 BestNameSpaceRefNode
->RawAbsolutePathSize
) {
875 BestScopeCount
= ProbedScopeCount
;
876 BestNameSpaceRefNode
= ProbedNameSpaceRefNode
;
877 } else if (AmlStreamGetIndex (&ProbedRawAbsoluteFStream
) ==
878 BestNameSpaceRefNode
->RawAbsolutePathSize
) {
880 return EFI_INVALID_PARAMETER
;
885 NextLink
= NextLink
->ForwardLink
;
888 DEBUG ((DEBUG_VERBOSE
, "\n"));
890 // Check whether the BestNameSpaceRefNode is a method definition.
891 if (BestNameSpaceRefNode
!= NULL
) {
892 if (AmlIsMethodDefinitionNode (BestNameSpaceRefNode
->NodeRef
)) {
893 *OutNameSpaceRefNode
= BestNameSpaceRefNode
;
894 } else if (AmlNodeCompareOpCode (
895 BestNameSpaceRefNode
->NodeRef
,
897 // The path matches an alias. Resolve the alias and check whether
898 // this is a method defintion.
899 Status
= AmlResolveAliasMethod (
900 BestNameSpaceRefNode
->NodeRef
,
904 if (EFI_ERROR (Status
)) {
910 // If no, return NULL, even if a matching pathname has been found.
911 *OutNameSpaceRefNode
= NULL
;
917 /** Check whether a pathname is a method invocation.
919 If there is a matching method definition, returns the corresponding
922 To do so, the NameSpaceRefList is keeping track of every namespace node
923 and its raw AML absolute path.
924 To check whether a pathname is a method invocation, a corresponding raw
925 absolute pathname is built. This raw absolute pathname is then compared
926 to the list of available pathnames. If a pathname defining a method
927 matches the scope of the input pathname, return.
929 @param [in] ParentNode Parent node. Node to which the node to be
930 created will be attached.
931 @param [in] FStream Forward stream pointing to the NameString
933 @param [in] NameSpaceRefList List of NameSpaceRef nodes.
934 @param [out] OutNameSpaceRefNode If the NameString pointed by FStream is
935 a method invocation, OutNameSpaceRefNode
936 contains the NameSpaceRef corresponding
937 to the method definition.
940 @retval EFI_SUCCESS The function completed successfully.
941 @retval EFI_INVALID_PARAMETER Invalid parameter.
945 AmlIsMethodInvocation (
946 IN CONST AML_NODE_HEADER
* ParentNode
,
947 IN CONST AML_STREAM
* FStream
,
948 IN CONST LIST_ENTRY
* NameSpaceRefList
,
949 OUT AML_NAMESPACE_REF_NODE
** OutNameSpaceRefNode
954 AML_STREAM RawPathNameBStream
;
955 AML_STREAM RawAbsolutePathFStream
;
957 AML_STREAM RawAbsolutePathBStream
;
958 UINT8
* RawAbsolutePathBuffer
;
959 UINT32 RawAbsolutePathBufferSize
;
961 AML_NAMESPACE_REF_NODE
* NameSpaceRefNode
;
963 if ((!IS_AML_OBJECT_NODE (ParentNode
) &&
964 !IS_AML_ROOT_NODE (ParentNode
)) ||
965 !IS_STREAM (FStream
) ||
966 IS_END_OF_STREAM (FStream
) ||
967 !IS_STREAM_FORWARD (FStream
) ||
968 (NameSpaceRefList
== NULL
) ||
969 (OutNameSpaceRefNode
== NULL
)) {
971 return EFI_INVALID_PARAMETER
;
974 // There cannot be a method invocation in a field list. Return.
975 if (AmlNodeHasAttribute (
976 (CONST AML_OBJECT_NODE
*)ParentNode
,
977 AML_HAS_FIELD_LIST
)) {
978 *OutNameSpaceRefNode
= NULL
;
982 // Allocate memory for the raw absolute path.
983 RawAbsolutePathBufferSize
= MAX_AML_NAMESTRING_SIZE
;
984 RawAbsolutePathBuffer
= AllocateZeroPool (RawAbsolutePathBufferSize
);
985 if (RawAbsolutePathBuffer
== NULL
) {
987 return EFI_OUT_OF_RESOURCES
;
990 // Initialize a backward stream to get the raw absolute path.
991 Status
= AmlStreamInit (
992 &RawAbsolutePathBStream
,
993 RawAbsolutePathBuffer
,
994 RawAbsolutePathBufferSize
,
995 EAmlStreamDirectionBackward
997 if (EFI_ERROR (Status
)) {
1002 // Build the raw AML absolute path of the namespace node.
1003 Status
= AmlBuildRawMethodAbsolutePath (
1006 &RawAbsolutePathBStream
1008 if (EFI_ERROR (Status
)) {
1013 // If this is the root path: it cannot be a method invocation. Just return.
1014 if (AmlStreamGetIndex (&RawAbsolutePathBStream
) == 0) {
1018 "Root node cannot be a method invocation\n"
1020 *OutNameSpaceRefNode
= NULL
;
1021 Status
= EFI_SUCCESS
;
1025 // Create a forward stream for the raw absolute path.
1026 // This forward stream only contains the raw absolute path with
1027 // no extra free space.
1028 Status
= AmlStreamInit (
1029 &RawAbsolutePathFStream
,
1030 AmlStreamGetCurrPos (&RawAbsolutePathBStream
),
1031 AmlStreamGetIndex (&RawAbsolutePathBStream
),
1032 EAmlStreamDirectionForward
1034 if (EFI_ERROR (Status
)) {
1039 // Create a backward stream for the node name.
1040 Status
= AmlInitRawPathBStream (
1044 if (EFI_ERROR (Status
)) {
1049 // Go through the NameSpaceRefList elements to check for
1050 // a corresponding method definition.
1051 NameSpaceRefNode
= NULL
;
1052 Status
= AmlFindMethodDefinition (
1053 &RawAbsolutePathFStream
,
1054 &RawPathNameBStream
,
1058 if (EFI_ERROR (Status
)) {
1063 #if !defined(MDEPKG_NDEBUG)
1064 // Print whether a method definition has been found.
1065 if (NameSpaceRefNode
!= NULL
) {
1068 "AmlMethodParser: Corresponding method definition: "
1070 AMLDBG_PRINT_CHARS (
1072 NameSpaceRefNode
->RawAbsolutePath
,
1073 NameSpaceRefNode
->RawAbsolutePathSize
1075 DEBUG ((DEBUG_VERBOSE
, ".\n"));
1078 DEBUG ((DEBUG_VERBOSE
, "AmlMethodParser: No method definition found.\n"));
1080 #endif // MDEPKG_NDEBUG
1082 *OutNameSpaceRefNode
= NameSpaceRefNode
;
1085 // Free allocated memory.
1086 FreePool (RawAbsolutePathBuffer
);
1090 /** Create a namespace reference node and add it to the NameSpaceRefList.
1092 When a namespace node is encountered, the namespace it defines must be
1093 associated to the node. This allow to keep track of the nature of each
1094 name present in the AML namespace.
1096 In the end, this allows to recognize method invocations and parse the right
1097 number of arguments after the method name.
1099 @param [in] Node Namespace node.
1100 @param [in, out] NameSpaceRefList List of namespace reference nodes.
1102 @retval EFI_SUCCESS The function completed successfully.
1103 @retval EFI_INVALID_PARAMETER Invalid parameter.
1107 AmlAddNameSpaceReference (
1108 IN CONST AML_OBJECT_NODE
* Node
,
1109 IN OUT LIST_ENTRY
* NameSpaceRefList
1113 AML_NAMESPACE_REF_NODE
* NameSpaceRefNode
;
1115 AML_STREAM NodeNameFStream
;
1116 EAML_PARSE_INDEX NameIndex
;
1117 CONST AML_DATA_NODE
* NameNode
;
1119 AML_STREAM RawAbsolutePathBStream
;
1120 UINT32 RawAbsolutePathBStreamSize
;
1122 CHAR8
* AbsolutePathBuffer
;
1123 UINT32 AbsolutePathBufferSize
;
1125 CONST AML_NODE_HEADER
* ParentNode
;
1127 if (!AmlNodeHasAttribute (Node
, AML_IN_NAMESPACE
) ||
1128 (NameSpaceRefList
== NULL
)) {
1130 return EFI_INVALID_PARAMETER
;
1133 // Allocate a buffer to get the raw AML absolute pathname of the
1135 AbsolutePathBufferSize
= MAX_AML_NAMESTRING_SIZE
;
1136 AbsolutePathBuffer
= AllocateZeroPool (AbsolutePathBufferSize
);
1137 if (AbsolutePathBuffer
== NULL
) {
1139 return EFI_OUT_OF_RESOURCES
;
1142 Status
= AmlStreamInit (
1143 &RawAbsolutePathBStream
,
1144 (UINT8
*)AbsolutePathBuffer
,
1145 AbsolutePathBufferSize
,
1146 EAmlStreamDirectionBackward
1148 if (EFI_ERROR (Status
)) {
1150 Status
= EFI_INVALID_PARAMETER
;
1154 // Get the index where the name of the Node is stored in its
1155 // fixed list of arguments.
1156 Status
= AmlNodeGetNameIndex (Node
, &NameIndex
);
1157 if (EFI_ERROR (Status
)) {
1159 Status
= EFI_INVALID_PARAMETER
;
1163 // Get the Node name.
1164 NameNode
= (CONST AML_DATA_NODE
*)AmlGetFixedArgument (
1165 (AML_OBJECT_NODE
*)Node
,
1168 if (!IS_AML_DATA_NODE (NameNode
) ||
1169 (NameNode
->DataType
!= EAmlNodeDataTypeNameString
)) {
1171 Status
= EFI_INVALID_PARAMETER
;
1175 // Initialize a stream on the node name of the namespace node.
1176 // This is an AML NameString.
1177 Status
= AmlStreamInit (
1181 EAmlStreamDirectionForward
1183 if (EFI_ERROR (Status
)) {
1185 Status
= EFI_INVALID_PARAMETER
;
1189 ParentNode
= AmlGetParent ((AML_NODE_HEADER
*)Node
);
1190 if (ParentNode
== NULL
) {
1192 Status
= EFI_INVALID_PARAMETER
;
1196 // Build the raw AML absolute path of the namespace node.
1197 Status
= AmlBuildRawMethodAbsolutePath (
1200 &RawAbsolutePathBStream
1202 if (EFI_ERROR (Status
)) {
1207 RawAbsolutePathBStreamSize
= AmlStreamGetIndex (&RawAbsolutePathBStream
);
1208 // This is the root path: this cannot be a method invocation.
1209 if (RawAbsolutePathBStreamSize
== 0) {
1210 Status
= EFI_SUCCESS
;
1214 // Create a NameSpace reference node.
1215 Status
= AmlCreateMethodRefNode (
1217 (CONST CHAR8
*)AmlStreamGetCurrPos (&RawAbsolutePathBStream
),
1218 RawAbsolutePathBStreamSize
,
1221 if (EFI_ERROR (Status
)) {
1226 // Add the created NameSpaceRefNode to the list.
1227 InsertTailList (NameSpaceRefList
, &NameSpaceRefNode
->Link
);
1231 "AmlMethodParser: Adding namespace reference with name:\n"
1233 AMLDBG_PRINT_CHARS (
1235 (CONST CHAR8
*)AmlStreamGetCurrPos (&RawAbsolutePathBStream
),
1236 AmlStreamGetIndex (&RawAbsolutePathBStream
)
1238 DEBUG ((DEBUG_VERBOSE
, "\n"));
1241 // Free allocated memory.
1242 FreePool (AbsolutePathBuffer
);
1247 /** Create a method invocation node.
1249 The AML grammar does not attribute an OpCode/SubOpCode couple for
1250 method invocations. This library is representing method invocations
1253 The AML encoding for method invocations in the ACPI specification 6.3 is:
1254 MethodInvocation := NameString TermArgList
1255 In this library, it is:
1256 MethodInvocation := MethodInvocationOp NameString ArgumentCount TermArgList
1257 ArgumentCount := ByteData
1259 When computing the size of a tree or serializing it, the additional data is
1260 not taken into account (i.e. the MethodInvocationOp and the ArgumentCount).
1262 Method invocation nodes have the AML_METHOD_INVOVATION attribute.
1264 @param [in] NameSpaceRefNode NameSpaceRef node pointing to the
1265 the definition of the invoked
1267 @param [in] MethodInvocationName Data node containing the method
1269 @param [out] MethodInvocationNodePtr Created method invocation node.
1271 @retval EFI_SUCCESS The function completed successfully.
1272 @retval EFI_INVALID_PARAMETER Invalid parameter.
1273 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
1277 AmlCreateMethodInvocationNode (
1278 IN CONST AML_NAMESPACE_REF_NODE
* NameSpaceRefNode
,
1279 IN AML_DATA_NODE
* MethodInvocationName
,
1280 OUT AML_OBJECT_NODE
** MethodInvocationNodePtr
1286 AML_DATA_NODE
* ArgCountNode
;
1287 AML_NODE_HEADER
** FixedArgs
;
1288 AML_OBJECT_NODE
* MethodDefinitionNode
;
1289 AML_OBJECT_NODE
* MethodInvocationNode
;
1291 if ((NameSpaceRefNode
== NULL
) ||
1292 !AmlIsMethodDefinitionNode (NameSpaceRefNode
->NodeRef
) ||
1293 !IS_AML_DATA_NODE (MethodInvocationName
) ||
1294 (MethodInvocationName
->DataType
!= EAmlNodeDataTypeNameString
) ||
1295 (MethodInvocationNodePtr
== NULL
)) {
1297 return EFI_INVALID_PARAMETER
;
1300 // Get the number of arguments of the method.
1301 MethodDefinitionNode
= (AML_OBJECT_NODE
*)NameSpaceRefNode
->NodeRef
;
1302 FixedArgs
= MethodDefinitionNode
->FixedArgs
;
1303 // The method definition is an actual method definition.
1304 if (AmlNodeCompareOpCode (MethodDefinitionNode
, AML_METHOD_OP
, 0)) {
1305 // Cf ACPI 6.3 specification:
1306 // DefMethod := MethodOp PkgLength NameString MethodFlags TermList
1308 // MethodFlags := ByteData bit 0-2: ArgCount (0-7)
1309 // bit 3: SerializeFlag
1312 // bit 4-7: SyncLevel (0x00-0x0f)
1314 // Read the MethodFlags to decode the ArgCount.
1315 ArgCountNode
= (AML_DATA_NODE
*)FixedArgs
[EAmlParseIndexTerm1
];
1316 ArgCount
= *((UINT8
*)ArgCountNode
->Buffer
) & 0x7;
1317 } else if (AmlNodeCompareOpCode (MethodDefinitionNode
, AML_EXTERNAL_OP
, 0)) {
1318 // The method definition is an external statement.
1319 // Cf ACPI 6.3 specification:
1320 // DefExternal := ExternalOp NameString ObjectType ArgumentCount
1321 // ExternalOp := 0x15
1322 // ObjectType := ByteData
1323 // ArgumentCount := ByteData (0 - 7)
1325 // Read the ArgumentCount.
1326 ArgCountNode
= (AML_DATA_NODE
*)FixedArgs
[EAmlParseIndexTerm2
];
1327 ArgCount
= *((UINT8
*)ArgCountNode
->Buffer
);
1330 return EFI_INVALID_PARAMETER
;
1333 // Create the object node for the method invocation.
1334 // MethodInvocation := MethodInvocationOp NameString ArgumentCount
1335 // MethodInvocationOp := Pseudo Opcode for Method Invocation
1336 // NameString := Method Name
1337 // ArgumentCount := ByteData (0 - 7)
1338 Status
= AmlCreateObjectNode (
1339 AmlGetByteEncodingByOpCode (AML_METHOD_INVOC_OP
, 0),
1341 &MethodInvocationNode
1343 if (EFI_ERROR (Status
)) {
1348 // The first fixed argument is the method name.
1349 Status
= AmlSetFixedArgument (
1350 MethodInvocationNode
,
1351 EAmlParseIndexTerm0
,
1352 (AML_NODE_HEADER
*)MethodInvocationName
1354 if (EFI_ERROR (Status
)) {
1359 // Create a data node holding the number of arguments
1360 // of the method invocation.
1361 ArgCountNode
= NULL
;
1362 Status
= AmlCreateDataNode (
1363 EAmlNodeDataTypeUInt
,
1368 if (EFI_ERROR (Status
)) {
1373 // The second fixed argument is the number of arguments.
1374 Status
= AmlSetFixedArgument (
1375 MethodInvocationNode
,
1376 EAmlParseIndexTerm1
,
1377 (AML_NODE_HEADER
*)ArgCountNode
1379 if (EFI_ERROR (Status
)) {
1384 *MethodInvocationNodePtr
= MethodInvocationNode
;
1388 // Delete the sub-tree: the method invocation name is already attached.
1389 AmlDeleteTree ((AML_NODE_HEADER
*)MethodInvocationNode
);
1390 if (ArgCountNode
!= NULL
) {
1391 AmlDeleteNode ((AML_NODE_HEADER
*)ArgCountNode
);
1397 /** Get the number of arguments of a method invocation node.
1399 This function also allow to identify whether a node is a method invocation
1400 node. If the input node is not a method invocation node, just return.
1402 @param [in] MethodInvocationNode Method invocation node.
1403 @param [out] IsMethodInvocation Boolean stating whether the input
1404 node is a method invocation.
1405 @param [out] ArgCount Number of arguments of the method
1407 Set to 0 if MethodInvocationNode
1408 is not a method invocation.
1410 @retval EFI_SUCCESS The function completed successfully.
1411 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
1412 @retval EFI_INVALID_PARAMETER Invalid parameter.
1413 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
1417 AmlGetMethodInvocationArgCount (
1418 IN CONST AML_OBJECT_NODE
* MethodInvocationNode
,
1419 OUT BOOLEAN
* IsMethodInvocation
,
1420 OUT UINT8
* ArgCount
1423 AML_DATA_NODE
* NumArgsNode
;
1425 if (!IS_AML_NODE_VALID (MethodInvocationNode
) ||
1426 (IsMethodInvocation
== NULL
) ||
1427 (ArgCount
== NULL
)) {
1429 return EFI_INVALID_PARAMETER
;
1432 // Check whether MethodInvocationNode is a method invocation.
1433 if (!AmlNodeCompareOpCode (MethodInvocationNode
, AML_METHOD_INVOC_OP
, 0)) {
1434 *IsMethodInvocation
= FALSE
;
1439 // MethodInvocation := MethodInvocationOp NameString ArgumentCount
1440 // MethodInvocationOp := Pseudo Opcode for Method Invocation
1441 // NameString := Method Name
1442 // ArgumentCount := ByteData (0 - 7)
1443 NumArgsNode
= (AML_DATA_NODE
*)AmlGetFixedArgument (
1444 (AML_OBJECT_NODE
*)MethodInvocationNode
,
1447 if (!IS_AML_NODE_VALID (NumArgsNode
) ||
1448 (NumArgsNode
->Buffer
== NULL
) ||
1449 (NumArgsNode
->DataType
!= EAmlNodeDataTypeUInt
) ||
1450 (NumArgsNode
->Size
!= 1)) {
1452 return EFI_INVALID_PARAMETER
;
1454 *ArgCount
= *NumArgsNode
->Buffer
;
1456 *IsMethodInvocation
= TRUE
;