]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlMethodParser.c
53e91dd6278bcfb5d0be9ff2c9a04db6d39ab57c
[mirror_edk2.git] / DynamicTablesPkg / Library / Common / AmlLib / Parser / AmlMethodParser.c
1 /** @file
2 AML Method Parser.
3
4 Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8
9 #include <Parser/AmlMethodParser.h>
10
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>
18
19 /** Delete a namespace reference node and its pathname.
20
21 It is the caller's responsibility to check the NameSpaceRefNode has been
22 removed from any list the node is part of.
23
24 @param [in] NameSpaceRefNode Pointer to an AML_NAMESPACE_REF_NODE.
25
26 @retval EFI_SUCCESS The function completed successfully.
27 @retval EFI_INVALID_PARAMETER Invalid parameter.
28 **/
29 STATIC
30 EFI_STATUS
31 EFIAPI
32 AmlDeleteNameSpaceRefNode (
33 IN AML_NAMESPACE_REF_NODE * NameSpaceRefNode
34 )
35 {
36 if (NameSpaceRefNode == NULL) {
37 ASSERT (0);
38 return EFI_INVALID_PARAMETER;
39 }
40
41 if (NameSpaceRefNode->RawAbsolutePath != NULL) {
42 FreePool ((CHAR8*)NameSpaceRefNode->RawAbsolutePath);
43 } else {
44 ASSERT (0);
45 return EFI_INVALID_PARAMETER;
46 }
47
48 FreePool (NameSpaceRefNode);
49 return EFI_SUCCESS;
50 }
51
52 /** Delete a list of namespace reference nodes.
53
54 @param [in] NameSpaceRefList List of namespace reference nodes.
55
56 @retval EFI_SUCCESS The function completed successfully.
57 @retval EFI_INVALID_PARAMETER Invalid parameter.
58 **/
59 EFI_STATUS
60 EFIAPI
61 AmlDeleteNameSpaceRefList (
62 IN LIST_ENTRY * NameSpaceRefList
63 )
64 {
65 EFI_STATUS Status;
66 LIST_ENTRY * CurrentLink;
67
68 if (NameSpaceRefList == NULL) {
69 ASSERT (0);
70 return EFI_INVALID_PARAMETER;
71 }
72
73 while (!IsListEmpty (NameSpaceRefList)) {
74 CurrentLink = NameSpaceRefList->ForwardLink;
75 RemoveEntryList (CurrentLink);
76 Status = AmlDeleteNameSpaceRefNode (
77 (AML_NAMESPACE_REF_NODE*)CurrentLink
78 );
79 if (EFI_ERROR (Status)) {
80 ASSERT (0);
81 return Status;
82 }
83 } // while
84
85 return EFI_SUCCESS;
86 }
87
88 /** Create an AML_NAMESPACE_REF_NODE.
89
90 A Buffer is allocated to store the raw AML absolute path.
91
92 @param [in] ObjectNode Node being part of the namespace.
93 Must be have the AML_IN_NAMESPACE
94 attribute.
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.
100
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.
104 **/
105 STATIC
106 EFI_STATUS
107 EFIAPI
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
113 )
114 {
115 AML_NAMESPACE_REF_NODE * NameSpaceRefNode;
116
117 if (!AmlNodeHasAttribute (ObjectNode, AML_IN_NAMESPACE) ||
118 (RawAbsolutePath == NULL) ||
119 (RawAbsolutePathSize == 0) ||
120 (NameSpaceRefNodePtr == NULL)) {
121 ASSERT (0);
122 return EFI_INVALID_PARAMETER;
123 }
124
125 NameSpaceRefNode = AllocateZeroPool (sizeof (AML_NAMESPACE_REF_NODE));
126 if (NameSpaceRefNode == NULL) {
127 ASSERT (0);
128 return EFI_OUT_OF_RESOURCES;
129 }
130
131 NameSpaceRefNode->RawAbsolutePathSize = RawAbsolutePathSize;
132 NameSpaceRefNode->RawAbsolutePath = AllocateCopyPool (
133 RawAbsolutePathSize,
134 RawAbsolutePath
135 );
136 if (NameSpaceRefNode->RawAbsolutePath == NULL) {
137 FreePool (NameSpaceRefNode);
138 ASSERT (0);
139 return EFI_OUT_OF_RESOURCES;
140 }
141
142 InitializeListHead (&NameSpaceRefNode->Link);
143
144 NameSpaceRefNode->NodeRef = ObjectNode;
145 *NameSpaceRefNodePtr = NameSpaceRefNode;
146
147 return EFI_SUCCESS;
148 }
149
150 #if !defined (MDEPKG_NDEBUG)
151
152 /** Print the list of raw absolute paths of the NameSpace reference list.
153
154 @param [in] NameSpaceRefList List of NameSpace reference nodes.
155 **/
156 VOID
157 EFIAPI
158 AmlDbgPrintNameSpaceRefList (
159 IN CONST LIST_ENTRY * NameSpaceRefList
160 )
161 {
162 LIST_ENTRY * CurrLink;
163 AML_NAMESPACE_REF_NODE * CurrNameSpaceNode;
164
165 if (NameSpaceRefList == NULL) {
166 ASSERT (0);
167 return;
168 }
169
170 DEBUG ((DEBUG_INFO, "AmlMethodParser: List of available raw AML paths:\n"));
171
172 CurrLink = NameSpaceRefList->ForwardLink;
173 while (CurrLink != NameSpaceRefList) {
174 CurrNameSpaceNode = (AML_NAMESPACE_REF_NODE*)CurrLink;
175
176 AMLDBG_PRINT_CHARS (
177 DEBUG_INFO,
178 CurrNameSpaceNode->RawAbsolutePath,
179 CurrNameSpaceNode->RawAbsolutePathSize
180 );
181 DEBUG ((DEBUG_INFO, "\n"));
182
183 CurrLink = CurrLink->ForwardLink;
184 }
185
186 DEBUG ((DEBUG_INFO, "\n"));
187 }
188
189 #endif // MDEPKG_NDEBUG
190
191 /** From a forward stream pointing to a NameString,
192 initialize a raw backward stream.
193
194 StartOfStream
195 Fstream: CurrPos EndOfStream
196 v v
197 +-----------------------------------------+
198 |^^^[Multi-name prefix]AAAA.BBBB.CCCC |
199 +-----------------------------------------+
200 ^ ^
201 RawPathNameBStream: EndOfStream CurrPos
202 StartOfStream
203
204 No memory is allocated when initializing the stream.
205
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
209 raw AML path.
210
211 @retval EFI_SUCCESS The function completed successfully.
212 @retval EFI_INVALID_PARAMETER Invalid parameter.
213 **/
214 STATIC
215 EFI_STATUS
216 EFIAPI
217 AmlInitRawPathBStream (
218 IN CONST AML_STREAM * FStream,
219 OUT AML_STREAM * RawPathNameBStream
220 )
221 {
222 EFI_STATUS Status;
223
224 UINT8 * RawPathBuffer;
225 CONST CHAR8 * Buffer;
226
227 UINT32 Root;
228 UINT32 ParentPrefix;
229 UINT32 SegCount;
230
231 if (!IS_STREAM (FStream) ||
232 IS_END_OF_STREAM (FStream) ||
233 !IS_STREAM_FORWARD (FStream) ||
234 (RawPathNameBStream == NULL)) {
235 ASSERT (0);
236 return EFI_INVALID_PARAMETER;
237 }
238
239 Buffer = (CONST CHAR8*)AmlStreamGetCurrPos (FStream);
240 if (Buffer == NULL) {
241 ASSERT (0);
242 return EFI_INVALID_PARAMETER;
243 }
244
245 // Parse the NameString information.
246 Status = AmlParseNameStringInfo (
247 Buffer,
248 &Root,
249 &ParentPrefix,
250 &SegCount
251 );
252 if (EFI_ERROR (Status)) {
253 ASSERT (0);
254 return Status;
255 }
256
257 // Get the beginning of the raw NameString.
258 RawPathBuffer = (UINT8*)AmlGetFirstNameSeg (
259 Buffer,
260 Root,
261 ParentPrefix
262 );
263 if (RawPathBuffer == NULL) {
264 ASSERT (0);
265 return EFI_INVALID_PARAMETER;
266 }
267
268 // Initialize a backward stream containing the raw path.
269 Status = AmlStreamInit (
270 RawPathNameBStream,
271 RawPathBuffer,
272 (SegCount * AML_NAME_SEG_SIZE),
273 EAmlStreamDirectionBackward
274 );
275 ASSERT_EFI_ERROR (Status);
276
277 return Status;
278 }
279
280 /** Get the first node in the ParentNode branch that is part of the
281 AML namespace and has its name defined.
282
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.
286
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.
294
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.
299 ASL code:
300 Method (MET0, 0,,, BuffObj) {
301 Return (Buffer (0x1000) {})
302 }
303 CreateField (MET0(), 0x100, 0x4, FIEL)
304
305 @param [in] Node Node to get the first named node from, in
306 its hierarchy.
307 @param [out] OutNamedNode First named node in Node's hierarchy.
308
309 @retval EFI_SUCCESS The function completed successfully.
310 @retval EFI_INVALID_PARAMETER Invalid parameter.
311 **/
312 STATIC
313 EFI_STATUS
314 EFIAPI
315 AmlGetFirstNamedAncestorNode (
316 IN CONST AML_NODE_HEADER * Node,
317 OUT AML_NODE_HEADER ** OutNamedNode
318 )
319 {
320 EFI_STATUS Status;
321 CONST AML_NODE_HEADER * NameSpaceNode;
322
323 if ((!IS_AML_OBJECT_NODE (Node) &&
324 !IS_AML_ROOT_NODE (Node)) ||
325 (OutNamedNode == NULL)) {
326 ASSERT (0);
327 return EFI_INVALID_PARAMETER;
328 }
329
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,
335 AML_IN_NAMESPACE) &&
336 AmlNodeGetName ((CONST AML_OBJECT_NODE*)Node) != NULL)) {
337 Status = AmlGetFirstAncestorNameSpaceNode (
338 Node,
339 (AML_NODE_HEADER**)&NameSpaceNode
340 );
341 if (EFI_ERROR (Status)) {
342 ASSERT (0);
343 return Status;
344 }
345 // The NameSpaceNode may not have its name defined as yet. In this
346 // case get the next ancestor node.
347 Node = NameSpaceNode;
348 }
349
350 *OutNamedNode = (AML_NODE_HEADER*)Node;
351
352 return EFI_SUCCESS;
353 }
354
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.
357
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.
360
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
368 NameString).
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.
374
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.
378 **/
379 STATIC
380 EFI_STATUS
381 EFIAPI
382 AmlBuildRawMethodAbsolutePath (
383 IN CONST AML_NODE_HEADER * ParentNode,
384 IN CONST AML_STREAM * PathnameFStream,
385 IN OUT AML_STREAM * AbsolutePathBStream
386 )
387 {
388 EFI_STATUS Status;
389
390 AML_NODE_HEADER * NamedParentNode;
391 UINT8 * RawPathBuffer;
392 CONST CHAR8 * CurrPos;
393
394 UINT32 Root;
395 UINT32 ParentPrefix;
396 UINT32 SegCount;
397
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)) {
406 ASSERT (0);
407 return EFI_INVALID_PARAMETER;
408 }
409
410 CurrPos = (CONST CHAR8*)AmlStreamGetCurrPos (PathnameFStream);
411 if (CurrPos == NULL) {
412 ASSERT (0);
413 return EFI_INVALID_PARAMETER;
414 }
415
416 // Parse the NameString information.
417 Status = AmlParseNameStringInfo (
418 CurrPos,
419 &Root,
420 &ParentPrefix,
421 &SegCount
422 );
423 if (EFI_ERROR (Status)) {
424 ASSERT (0);
425 return Status;
426 }
427
428 // Copy the method invocation raw relative path at the end of the Stream.
429 if (SegCount != 0) {
430 // Get the beginning of the raw NameString.
431 RawPathBuffer = (UINT8*)AmlGetFirstNameSeg (
432 CurrPos,
433 Root,
434 ParentPrefix
435 );
436
437 Status = AmlStreamWrite (
438 AbsolutePathBStream,
439 RawPathBuffer,
440 SegCount * AML_NAME_SEG_SIZE
441 );
442 if (EFI_ERROR (Status)) {
443 ASSERT (0);
444 return Status;
445 }
446 }
447
448 // If the pathname contained an absolute path, this is finished, return.
449 if (Root) {
450 return Status;
451 }
452
453 // Get the first named node of the parent node in its hierarchy.
454 Status = AmlGetFirstNamedAncestorNode (ParentNode, &NamedParentNode);
455 if (EFI_ERROR (Status)) {
456 ASSERT (0);
457 return Status;
458 }
459
460 // Build the raw absolute path of the namespace node.
461 Status = AmlGetRawNameSpacePath (
462 NamedParentNode,
463 ParentPrefix,
464 AbsolutePathBStream
465 );
466 ASSERT_EFI_ERROR (Status);
467
468 return Status;
469 }
470
471 /** Compare two raw NameStrings stored in forward streams.
472 Compare them NameSeg by NameSeg (a NameSeg is 4 bytes long).
473
474 The two raw NameStrings can be of different size.
475
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).
482
483 @retval EFI_SUCCESS The function completed successfully.
484 @retval EFI_INVALID_PARAMETER Invalid parameter.
485 **/
486 STATIC
487 EFI_STATUS
488 EFIAPI
489 AmlCompareRawNameString (
490 IN CONST AML_STREAM * RawFStream1,
491 IN CONST AML_STREAM * RawFStream2,
492 OUT UINT32 * CompareCount
493 )
494 {
495 EFI_STATUS Status;
496 UINT32 Index;
497
498 AML_STREAM RawFStream1Clone;
499 AML_STREAM RawFStream2Clone;
500 UINT32 Stream1Size;
501 UINT32 Stream2Size;
502 UINT32 CompareLen;
503
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)) {
511 ASSERT (0);
512 return EFI_INVALID_PARAMETER;
513 }
514
515 Stream1Size = AmlStreamGetFreeSpace (RawFStream1);
516 if ((Stream1Size & (AML_NAME_SEG_SIZE - 1)) != 0) {
517 ASSERT (0);
518 return EFI_INVALID_PARAMETER;
519 }
520
521 Stream2Size = AmlStreamGetFreeSpace (RawFStream2);
522 if ((Stream2Size & (AML_NAME_SEG_SIZE - 1)) != 0) {
523 ASSERT (0);
524 return EFI_INVALID_PARAMETER;
525 }
526
527 Status = AmlStreamClone (RawFStream1, &RawFStream1Clone);
528 if (EFI_ERROR (Status)) {
529 ASSERT (0);
530 return Status;
531 }
532
533 Status = AmlStreamClone (RawFStream2, &RawFStream2Clone);
534 if (EFI_ERROR (Status)) {
535 ASSERT (0);
536 return Status;
537 }
538
539 CompareLen = MIN (Stream1Size, Stream2Size);
540 Index = 0;
541 // Check there is enough space for a NameSeg in both Stream1 and Stream2.
542 while (Index < CompareLen) {
543 if (!AmlStreamCmp (
544 &RawFStream1Clone,
545 &RawFStream2Clone,
546 AML_NAME_SEG_SIZE)
547 ) {
548 // NameSegs are different. Break.
549 break;
550 }
551
552 Status = AmlStreamProgress (&RawFStream1Clone, AML_NAME_SEG_SIZE);
553 if (EFI_ERROR (Status)) {
554 ASSERT (0);
555 return Status;
556 }
557 Status = AmlStreamProgress (&RawFStream2Clone, AML_NAME_SEG_SIZE);
558 if (EFI_ERROR (Status)) {
559 ASSERT (0);
560 return Status;
561 }
562
563 Index += AML_NAME_SEG_SIZE;
564 }
565
566 *CompareCount = Index;
567
568 return EFI_SUCCESS;
569 }
570
571 /** Check whether an alias can be resolved to a method definition.
572
573 Indeed, the following ASL code must be handled:
574 Method (MET0, 1) {
575 Return (0x9)
576 }
577 Alias (\MET0, \ALI0)
578 Alias (\ALI0, \ALI1)
579 \ALI1(0x5)
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
583 definition.
584
585 This method is a wrapper to recursively call AmlFindMethodDefinition.
586
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
593 NameSpaceRef node.
594
595 @retval EFI_SUCCESS The function completed successfully.
596 @retval EFI_INVALID_PARAMETER Invalid parameter.
597 **/
598 STATIC
599 EFI_STATUS
600 EFIAPI
601 AmlResolveAliasMethod (
602 IN CONST AML_OBJECT_NODE * AliasNode,
603 IN CONST LIST_ENTRY * NameSpaceRefList,
604 OUT AML_NAMESPACE_REF_NODE ** OutNameSpaceRefNode
605 )
606 {
607 EFI_STATUS Status;
608 AML_STREAM SourceAliasFStream;
609 CONST AML_DATA_NODE * DataNode;
610
611 if (!AmlNodeCompareOpCode (AliasNode, AML_ALIAS_OP, 0) ||
612 (NameSpaceRefList == NULL) ||
613 (OutNameSpaceRefNode == NULL)) {
614 ASSERT (0);
615 return EFI_INVALID_PARAMETER;
616 }
617
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,
622 EAmlParseIndexTerm0
623 );
624 if (DataNode == NULL) {
625 ASSERT (0);
626 return EFI_INVALID_PARAMETER;
627 }
628
629 // Initialize a stream on the source alias NameString.
630 Status = AmlStreamInit (
631 &SourceAliasFStream,
632 DataNode->Buffer,
633 DataNode->Size,
634 EAmlStreamDirectionForward
635 );
636 if (EFI_ERROR (Status)) {
637 ASSERT (0);
638 return Status;
639 }
640
641 // Recursively check whether the source alias NameString
642 // is a method invocation.
643 Status = AmlIsMethodInvocation (
644 AmlGetParent ((AML_NODE_HEADER*)AliasNode),
645 &SourceAliasFStream,
646 NameSpaceRefList,
647 OutNameSpaceRefNode
648 );
649 if (EFI_ERROR (Status)) {
650 ASSERT (0);
651 }
652
653 return Status;
654 }
655
656 /** Iterate through the MethodList to find the best namespace resolution.
657 If the pathname resolves to a method definition, returns it.
658
659 For instance, if the AML namespace is:
660 \
661 \-MET0 <- Device definition, absolute path: \MET0
662 \-AAAA
663 \-MET0 <- Method definition, absolute path: \AAAA.MET0
664 \-MET1 <- Method definition, absolute path: \AAAA.MET1
665 \-BBBB
666 \-CCCC
667 \-DDDD
668 \-MET0 <- Method definition, absolute path: \AAAA.BBBB.CCCC.DDDD.MET0
669
670 The list of the available pathnames is:
671 [NameSpaceRefList]
672 - \MET0 <- Device definition
673 - \AAAA
674 - \AAAA.MET0 <- Method definition
675 - \AAAA.MET1 <- Method definition
676 - \AAAA.BBBB
677 - \AAAA.BBBB.CCCC
678 - \AAAA.BBBB.CCCC.DDDD
679 - \AAAA.BBBB.CCCC.DDDD.MET0 <- Method definition
680
681 Depending on where the method invocation is done, the method definition
682 referenced changes. If the method call "MET0" is done from
683 \AAAA.BBBB.CCCC:
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
691 reference node.
692
693 @param [in] RawAbsolutePathFStream Forward stream pointing to a raw
694 absolute path.
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
704 NameSpaceRef node.
705
706 @retval EFI_SUCCESS The function completed successfully.
707 @retval EFI_INVALID_PARAMETER Invalid parameter.
708 **/
709 STATIC
710 EFI_STATUS
711 EFIAPI
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
717 )
718 {
719 EFI_STATUS Status;
720
721 LIST_ENTRY * NextLink;
722
723 // To resolve a pathname, scope levels need to be compared.
724 UINT32 NameSegScopeCount;
725 UINT32 PathNameSegScopeCount;
726 UINT32 ProbedScopeCount;
727 UINT32 BestScopeCount;
728
729 AML_STREAM ProbedRawAbsoluteFStream;
730 AML_STREAM ProbedRawAbsoluteBStream;
731
732 AML_NAMESPACE_REF_NODE * ProbedNameSpaceRefNode;
733 AML_NAMESPACE_REF_NODE * BestNameSpaceRefNode;
734
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)) {
747 ASSERT (0);
748 return EFI_INVALID_PARAMETER;
749 }
750
751 DEBUG ((DEBUG_VERBOSE, "AmlMethodParser: Checking absolute name: "));
752 AMLDBG_PRINT_CHARS (
753 DEBUG_VERBOSE,
754 (CONST CHAR8*)AmlStreamGetCurrPos (RawAbsolutePathFStream),
755 AmlStreamGetMaxBufferSize (RawAbsolutePathFStream)
756 );
757 DEBUG ((DEBUG_VERBOSE, ".\n"));
758
759 BestNameSpaceRefNode = NULL;
760 BestScopeCount = 0;
761 NameSegScopeCount = AmlStreamGetMaxBufferSize (RawAbsolutePathFStream);
762 PathNameSegScopeCount = AmlStreamGetMaxBufferSize (RawPathNameBStream);
763
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;
769
770 // Print the raw absolute path of the probed node.
771 AMLDBG_PRINT_CHARS (
772 DEBUG_VERBOSE,
773 ProbedNameSpaceRefNode->RawAbsolutePath,
774 ProbedNameSpaceRefNode->RawAbsolutePathSize
775 );
776 DEBUG ((DEBUG_VERBOSE, "; "));
777
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;
784 continue;
785 }
786
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
796 );
797 if (EFI_ERROR (Status)) {
798 ASSERT (0);
799 return Status;
800 }
801
802 // Compare the pathname endings. If they don't match, continue.
803 if (!AmlStreamCmp (
804 RawPathNameBStream,
805 &ProbedRawAbsoluteBStream,
806 AmlStreamGetMaxBufferSize (RawPathNameBStream))) {
807 NextLink = NextLink->ForwardLink;
808 continue;
809 }
810
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
819 // from the root;
820 // Thus, the best match is \AAAA.MET0.
821 Status = AmlStreamInit (
822 &ProbedRawAbsoluteFStream,
823 (UINT8*)ProbedNameSpaceRefNode->RawAbsolutePath,
824 ProbedNameSpaceRefNode->RawAbsolutePathSize,
825 EAmlStreamDirectionForward
826 );
827 if (EFI_ERROR (Status)) {
828 ASSERT (0);
829 return Status;
830 }
831
832 // Count how many namespace levels are in common from the root.
833 Status = AmlCompareRawNameString (
834 RawAbsolutePathFStream,
835 &ProbedRawAbsoluteFStream,
836 &ProbedScopeCount
837 );
838 if (EFI_ERROR (Status)) {
839 ASSERT (0);
840 return EFI_INVALID_PARAMETER;
841 }
842
843 if (ProbedScopeCount == NameSegScopeCount) {
844 // This is a perfect match. Exit the loop.
845 BestNameSpaceRefNode = ProbedNameSpaceRefNode;
846 break;
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;
858 } else {
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) {
879 ASSERT (0);
880 return EFI_INVALID_PARAMETER;
881 }
882 }
883 }
884
885 NextLink = NextLink->ForwardLink;
886 }
887
888 DEBUG ((DEBUG_VERBOSE, "\n"));
889
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,
896 AML_ALIAS_OP, 0)) {
897 // The path matches an alias. Resolve the alias and check whether
898 // this is a method defintion.
899 Status = AmlResolveAliasMethod (
900 BestNameSpaceRefNode->NodeRef,
901 NameSpaceRefList,
902 OutNameSpaceRefNode
903 );
904 if (EFI_ERROR (Status)) {
905 ASSERT (0);
906 return Status;
907 }
908 }
909 } else {
910 // If no, return NULL, even if a matching pathname has been found.
911 *OutNameSpaceRefNode = NULL;
912 }
913
914 return EFI_SUCCESS;
915 }
916
917 /** Check whether a pathname is a method invocation.
918
919 If there is a matching method definition, returns the corresponding
920 NameSpaceRef node.
921
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.
928
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
932 to find.
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.
938 NULL otherwise.
939
940 @retval EFI_SUCCESS The function completed successfully.
941 @retval EFI_INVALID_PARAMETER Invalid parameter.
942 **/
943 EFI_STATUS
944 EFIAPI
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
950 )
951 {
952 EFI_STATUS Status;
953
954 AML_STREAM RawPathNameBStream;
955 AML_STREAM RawAbsolutePathFStream;
956
957 AML_STREAM RawAbsolutePathBStream;
958 UINT8 * RawAbsolutePathBuffer;
959 UINT32 RawAbsolutePathBufferSize;
960
961 AML_NAMESPACE_REF_NODE * NameSpaceRefNode;
962
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)) {
970 ASSERT (0);
971 return EFI_INVALID_PARAMETER;
972 }
973
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;
979 return EFI_SUCCESS;
980 }
981
982 // Allocate memory for the raw absolute path.
983 RawAbsolutePathBufferSize = MAX_AML_NAMESTRING_SIZE;
984 RawAbsolutePathBuffer = AllocateZeroPool (RawAbsolutePathBufferSize);
985 if (RawAbsolutePathBuffer == NULL) {
986 ASSERT (0);
987 return EFI_OUT_OF_RESOURCES;
988 }
989
990 // Initialize a backward stream to get the raw absolute path.
991 Status = AmlStreamInit (
992 &RawAbsolutePathBStream,
993 RawAbsolutePathBuffer,
994 RawAbsolutePathBufferSize,
995 EAmlStreamDirectionBackward
996 );
997 if (EFI_ERROR (Status)) {
998 ASSERT (0);
999 goto exit_handler;
1000 }
1001
1002 // Build the raw AML absolute path of the namespace node.
1003 Status = AmlBuildRawMethodAbsolutePath (
1004 ParentNode,
1005 FStream,
1006 &RawAbsolutePathBStream
1007 );
1008 if (EFI_ERROR (Status)) {
1009 ASSERT (0);
1010 goto exit_handler;
1011 }
1012
1013 // If this is the root path: it cannot be a method invocation. Just return.
1014 if (AmlStreamGetIndex (&RawAbsolutePathBStream) == 0) {
1015 DEBUG ((
1016 DEBUG_VERBOSE,
1017 "AmlMethodParser: "
1018 "Root node cannot be a method invocation\n"
1019 ));
1020 *OutNameSpaceRefNode = NULL;
1021 Status = EFI_SUCCESS;
1022 goto exit_handler;
1023 }
1024
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
1033 );
1034 if (EFI_ERROR (Status)) {
1035 ASSERT (0);
1036 goto exit_handler;
1037 }
1038
1039 // Create a backward stream for the node name.
1040 Status = AmlInitRawPathBStream (
1041 FStream,
1042 &RawPathNameBStream
1043 );
1044 if (EFI_ERROR (Status)) {
1045 ASSERT (0);
1046 return Status;
1047 }
1048
1049 // Go through the NameSpaceRefList elements to check for
1050 // a corresponding method definition.
1051 NameSpaceRefNode = NULL;
1052 Status = AmlFindMethodDefinition (
1053 &RawAbsolutePathFStream,
1054 &RawPathNameBStream,
1055 NameSpaceRefList,
1056 &NameSpaceRefNode
1057 );
1058 if (EFI_ERROR (Status)) {
1059 ASSERT (0);
1060 goto exit_handler;
1061 }
1062
1063 #if !defined(MDEPKG_NDEBUG)
1064 // Print whether a method definition has been found.
1065 if (NameSpaceRefNode != NULL) {
1066 DEBUG ((
1067 DEBUG_VERBOSE,
1068 "AmlMethodParser: Corresponding method definition: "
1069 ));
1070 AMLDBG_PRINT_CHARS (
1071 DEBUG_VERBOSE,
1072 NameSpaceRefNode->RawAbsolutePath,
1073 NameSpaceRefNode->RawAbsolutePathSize
1074 );
1075 DEBUG ((DEBUG_VERBOSE, ".\n"));
1076
1077 } else {
1078 DEBUG ((DEBUG_VERBOSE, "AmlMethodParser: No method definition found.\n"));
1079 }
1080 #endif // MDEPKG_NDEBUG
1081
1082 *OutNameSpaceRefNode = NameSpaceRefNode;
1083
1084 exit_handler:
1085 // Free allocated memory.
1086 FreePool (RawAbsolutePathBuffer);
1087 return Status;
1088 }
1089
1090 /** Create a namespace reference node and add it to the NameSpaceRefList.
1091
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.
1095
1096 In the end, this allows to recognize method invocations and parse the right
1097 number of arguments after the method name.
1098
1099 @param [in] Node Namespace node.
1100 @param [in, out] NameSpaceRefList List of namespace reference nodes.
1101
1102 @retval EFI_SUCCESS The function completed successfully.
1103 @retval EFI_INVALID_PARAMETER Invalid parameter.
1104 **/
1105 EFI_STATUS
1106 EFIAPI
1107 AmlAddNameSpaceReference (
1108 IN CONST AML_OBJECT_NODE * Node,
1109 IN OUT LIST_ENTRY * NameSpaceRefList
1110 )
1111 {
1112 EFI_STATUS Status;
1113 AML_NAMESPACE_REF_NODE * NameSpaceRefNode;
1114
1115 AML_STREAM NodeNameFStream;
1116 EAML_PARSE_INDEX NameIndex;
1117 CONST AML_DATA_NODE * NameNode;
1118
1119 AML_STREAM RawAbsolutePathBStream;
1120 UINT32 RawAbsolutePathBStreamSize;
1121
1122 CHAR8 * AbsolutePathBuffer;
1123 UINT32 AbsolutePathBufferSize;
1124
1125 CONST AML_NODE_HEADER * ParentNode;
1126
1127 if (!AmlNodeHasAttribute (Node, AML_IN_NAMESPACE) ||
1128 (NameSpaceRefList == NULL)) {
1129 ASSERT (0);
1130 return EFI_INVALID_PARAMETER;
1131 }
1132
1133 // Allocate a buffer to get the raw AML absolute pathname of the
1134 // namespace node.
1135 AbsolutePathBufferSize = MAX_AML_NAMESTRING_SIZE;
1136 AbsolutePathBuffer = AllocateZeroPool (AbsolutePathBufferSize);
1137 if (AbsolutePathBuffer == NULL) {
1138 ASSERT (0);
1139 return EFI_OUT_OF_RESOURCES;
1140 }
1141
1142 Status = AmlStreamInit (
1143 &RawAbsolutePathBStream,
1144 (UINT8*)AbsolutePathBuffer,
1145 AbsolutePathBufferSize,
1146 EAmlStreamDirectionBackward
1147 );
1148 if (EFI_ERROR (Status)) {
1149 ASSERT (0);
1150 Status = EFI_INVALID_PARAMETER;
1151 goto exit_handler;
1152 }
1153
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)) {
1158 ASSERT (0);
1159 Status = EFI_INVALID_PARAMETER;
1160 goto exit_handler;
1161 }
1162
1163 // Get the Node name.
1164 NameNode = (CONST AML_DATA_NODE*)AmlGetFixedArgument (
1165 (AML_OBJECT_NODE*)Node,
1166 NameIndex
1167 );
1168 if (!IS_AML_DATA_NODE (NameNode) ||
1169 (NameNode->DataType != EAmlNodeDataTypeNameString)) {
1170 ASSERT (0);
1171 Status = EFI_INVALID_PARAMETER;
1172 goto exit_handler;
1173 }
1174
1175 // Initialize a stream on the node name of the namespace node.
1176 // This is an AML NameString.
1177 Status = AmlStreamInit (
1178 &NodeNameFStream,
1179 NameNode->Buffer,
1180 NameNode->Size,
1181 EAmlStreamDirectionForward
1182 );
1183 if (EFI_ERROR (Status)) {
1184 ASSERT (0);
1185 Status = EFI_INVALID_PARAMETER;
1186 goto exit_handler;
1187 }
1188
1189 ParentNode = AmlGetParent ((AML_NODE_HEADER*)Node);
1190 if (ParentNode == NULL) {
1191 ASSERT (0);
1192 Status = EFI_INVALID_PARAMETER;
1193 goto exit_handler;
1194 }
1195
1196 // Build the raw AML absolute path of the namespace node.
1197 Status = AmlBuildRawMethodAbsolutePath (
1198 ParentNode,
1199 &NodeNameFStream,
1200 &RawAbsolutePathBStream
1201 );
1202 if (EFI_ERROR (Status)) {
1203 ASSERT (0);
1204 goto exit_handler;
1205 }
1206
1207 RawAbsolutePathBStreamSize = AmlStreamGetIndex (&RawAbsolutePathBStream);
1208 // This is the root path: this cannot be a method invocation.
1209 if (RawAbsolutePathBStreamSize == 0) {
1210 Status = EFI_SUCCESS;
1211 goto exit_handler;
1212 }
1213
1214 // Create a NameSpace reference node.
1215 Status = AmlCreateMethodRefNode (
1216 Node,
1217 (CONST CHAR8*)AmlStreamGetCurrPos (&RawAbsolutePathBStream),
1218 RawAbsolutePathBStreamSize,
1219 &NameSpaceRefNode
1220 );
1221 if (EFI_ERROR (Status)) {
1222 ASSERT (0);
1223 goto exit_handler;
1224 }
1225
1226 // Add the created NameSpaceRefNode to the list.
1227 InsertTailList (NameSpaceRefList, &NameSpaceRefNode->Link);
1228
1229 DEBUG ((
1230 DEBUG_VERBOSE,
1231 "AmlMethodParser: Adding namespace reference with name:\n"
1232 ));
1233 AMLDBG_PRINT_CHARS (
1234 DEBUG_VERBOSE,
1235 (CONST CHAR8*)AmlStreamGetCurrPos (&RawAbsolutePathBStream),
1236 AmlStreamGetIndex (&RawAbsolutePathBStream)
1237 );
1238 DEBUG ((DEBUG_VERBOSE, "\n"));
1239
1240 exit_handler:
1241 // Free allocated memory.
1242 FreePool (AbsolutePathBuffer);
1243
1244 return Status;
1245 }
1246
1247 /** Create a method invocation node.
1248
1249 The AML grammar does not attribute an OpCode/SubOpCode couple for
1250 method invocations. This library is representing method invocations
1251 as if they had one.
1252
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
1258
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).
1261
1262 Method invocation nodes have the AML_METHOD_INVOVATION attribute.
1263
1264 @param [in] NameSpaceRefNode NameSpaceRef node pointing to the
1265 the definition of the invoked
1266 method.
1267 @param [in] MethodInvocationName Data node containing the method
1268 invocation name.
1269 @param [out] MethodInvocationNodePtr Created method invocation node.
1270
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.
1274 **/
1275 EFI_STATUS
1276 EFIAPI
1277 AmlCreateMethodInvocationNode (
1278 IN CONST AML_NAMESPACE_REF_NODE * NameSpaceRefNode,
1279 IN AML_DATA_NODE * MethodInvocationName,
1280 OUT AML_OBJECT_NODE ** MethodInvocationNodePtr
1281 )
1282 {
1283 EFI_STATUS Status;
1284
1285 UINT8 ArgCount;
1286 AML_DATA_NODE * ArgCountNode;
1287 AML_NODE_HEADER ** FixedArgs;
1288 AML_OBJECT_NODE * MethodDefinitionNode;
1289 AML_OBJECT_NODE * MethodInvocationNode;
1290
1291 if ((NameSpaceRefNode == NULL) ||
1292 !AmlIsMethodDefinitionNode (NameSpaceRefNode->NodeRef) ||
1293 !IS_AML_DATA_NODE (MethodInvocationName) ||
1294 (MethodInvocationName->DataType != EAmlNodeDataTypeNameString) ||
1295 (MethodInvocationNodePtr == NULL)) {
1296 ASSERT (0);
1297 return EFI_INVALID_PARAMETER;
1298 }
1299
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
1307 // MethodOp := 0x14
1308 // MethodFlags := ByteData bit 0-2: ArgCount (0-7)
1309 // bit 3: SerializeFlag
1310 // 0 NotSerialized
1311 // 1 Serialized
1312 // bit 4-7: SyncLevel (0x00-0x0f)
1313
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)
1324
1325 // Read the ArgumentCount.
1326 ArgCountNode = (AML_DATA_NODE*)FixedArgs[EAmlParseIndexTerm2];
1327 ArgCount = *((UINT8*)ArgCountNode->Buffer);
1328 } else {
1329 ASSERT (0);
1330 return EFI_INVALID_PARAMETER;
1331 }
1332
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),
1340 0,
1341 &MethodInvocationNode
1342 );
1343 if (EFI_ERROR (Status)) {
1344 ASSERT (0);
1345 return Status;
1346 }
1347
1348 // The first fixed argument is the method name.
1349 Status = AmlSetFixedArgument (
1350 MethodInvocationNode,
1351 EAmlParseIndexTerm0,
1352 (AML_NODE_HEADER*)MethodInvocationName
1353 );
1354 if (EFI_ERROR (Status)) {
1355 ASSERT (0);
1356 goto error_handler;
1357 }
1358
1359 // Create a data node holding the number of arguments
1360 // of the method invocation.
1361 ArgCountNode = NULL;
1362 Status = AmlCreateDataNode (
1363 EAmlNodeDataTypeUInt,
1364 &ArgCount,
1365 sizeof (UINT8),
1366 &ArgCountNode
1367 );
1368 if (EFI_ERROR (Status)) {
1369 ASSERT (0);
1370 goto error_handler;
1371 }
1372
1373 // The second fixed argument is the number of arguments.
1374 Status = AmlSetFixedArgument (
1375 MethodInvocationNode,
1376 EAmlParseIndexTerm1,
1377 (AML_NODE_HEADER*)ArgCountNode
1378 );
1379 if (EFI_ERROR (Status)) {
1380 ASSERT (0);
1381 goto error_handler;
1382 }
1383
1384 *MethodInvocationNodePtr = MethodInvocationNode;
1385 return Status;
1386
1387 error_handler:
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);
1392 }
1393
1394 return Status;
1395 }
1396
1397 /** Get the number of arguments of a method invocation node.
1398
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.
1401
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
1406 invocation.
1407 Set to 0 if MethodInvocationNode
1408 is not a method invocation.
1409
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.
1414 **/
1415 EFI_STATUS
1416 EFIAPI
1417 AmlGetMethodInvocationArgCount (
1418 IN CONST AML_OBJECT_NODE * MethodInvocationNode,
1419 OUT BOOLEAN * IsMethodInvocation,
1420 OUT UINT8 * ArgCount
1421 )
1422 {
1423 AML_DATA_NODE * NumArgsNode;
1424
1425 if (!IS_AML_NODE_VALID (MethodInvocationNode) ||
1426 (IsMethodInvocation == NULL) ||
1427 (ArgCount == NULL)) {
1428 ASSERT (0);
1429 return EFI_INVALID_PARAMETER;
1430 }
1431
1432 // Check whether MethodInvocationNode is a method invocation.
1433 if (!AmlNodeCompareOpCode (MethodInvocationNode, AML_METHOD_INVOC_OP, 0)) {
1434 *IsMethodInvocation = FALSE;
1435 *ArgCount = 0;
1436 return EFI_SUCCESS;
1437 }
1438
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,
1445 EAmlParseIndexTerm1
1446 );
1447 if (!IS_AML_NODE_VALID (NumArgsNode) ||
1448 (NumArgsNode->Buffer == NULL) ||
1449 (NumArgsNode->DataType != EAmlNodeDataTypeUInt) ||
1450 (NumArgsNode->Size != 1)) {
1451 ASSERT (0);
1452 return EFI_INVALID_PARAMETER;
1453 }
1454 *ArgCount = *NumArgsNode->Buffer;
1455
1456 *IsMethodInvocation = TRUE;
1457 return EFI_SUCCESS;
1458 }