xref: /netbsd-src/sys/external/bsd/acpica/dist/compiler/aslmethod.c (revision e6c7e151de239c49d2e38720a061ed9d1fa99309)
1 /******************************************************************************
2  *
3  * Module Name: aslmethod.c - Control method analysis walk
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2020, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 #include "acnamesp.h"
47 #include "acparser.h"
48 #include "amlcode.h"
49 
50 
51 #define _COMPONENT          ACPI_COMPILER
52         ACPI_MODULE_NAME    ("aslmethod")
53 
54 
55 /* Local prototypes */
56 
57 static void
58 MtCheckNamedObjectInMethod (
59     ACPI_PARSE_OBJECT       *Op,
60     ASL_METHOD_INFO         *MethodInfo);
61 
62 static void
63 MtCheckStaticOperationRegionInMethod (
64     ACPI_PARSE_OBJECT       *Op);
65 
66 
67 /*******************************************************************************
68  *
69  * FUNCTION:    MtMethodAnalysisWalkBegin
70  *
71  * PARAMETERS:  ASL_WALK_CALLBACK
72  *
73  * RETURN:      Status
74  *
75  * DESCRIPTION: Descending callback for the analysis walk. Check methods for:
76  *              1) Initialized local variables
77  *              2) Valid arguments
78  *              3) Return types
79  *
80  ******************************************************************************/
81 
82 ACPI_STATUS
83 MtMethodAnalysisWalkBegin (
84     ACPI_PARSE_OBJECT       *Op,
85     UINT32                  Level,
86     void                    *Context)
87 {
88     ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
89     ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack;
90     ACPI_PARSE_OBJECT       *Next;
91     UINT32                  RegisterNumber;
92     UINT32                  i;
93     char                    LocalName[] = "Local0";
94     char                    ArgName[] = "Arg0";
95     ACPI_PARSE_OBJECT       *ArgNode;
96     ACPI_PARSE_OBJECT       *NextType;
97     UINT8                   ActualArgs = 0;
98     BOOLEAN                 HidExists;
99     BOOLEAN                 AdrExists;
100 
101 
102     /* Build cross-reference output file if requested */
103 
104     if (AslGbl_CrossReferenceOutput)
105     {
106         OtXrefWalkPart1 (Op, Level, MethodInfo);
107     }
108 
109     switch (Op->Asl.ParseOpcode)
110     {
111     case PARSEOP_METHOD:
112 
113         AslGbl_TotalMethods++;
114 
115         /* Create and init method info */
116 
117         MethodInfo = UtLocalCalloc (sizeof (ASL_METHOD_INFO));
118         MethodInfo->Next = WalkInfo->MethodStack;
119         MethodInfo->Op = Op;
120 
121         WalkInfo->MethodStack = MethodInfo;
122 
123         /*
124          * Special handling for _PSx methods. Dependency rules (same scope):
125          *
126          * 1) _PS0 - One of these must exist: _PS1, _PS2, _PS3
127          * 2) _PS1/_PS2/_PS3: A _PS0 must exist
128          */
129         if (ACPI_COMPARE_NAMESEG (METHOD_NAME__PS0, Op->Asl.NameSeg))
130         {
131             /* For _PS0, one of _PS1/_PS2/_PS3 must exist */
132 
133             if ((!ApFindNameInScope (METHOD_NAME__PS1, Op)) &&
134                 (!ApFindNameInScope (METHOD_NAME__PS2, Op)) &&
135                 (!ApFindNameInScope (METHOD_NAME__PS3, Op)))
136             {
137                 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
138                     "_PS0 requires one of _PS1/_PS2/_PS3 in same scope");
139             }
140         }
141         else if (
142             ACPI_COMPARE_NAMESEG (METHOD_NAME__PS1, Op->Asl.NameSeg) ||
143             ACPI_COMPARE_NAMESEG (METHOD_NAME__PS2, Op->Asl.NameSeg) ||
144             ACPI_COMPARE_NAMESEG (METHOD_NAME__PS3, Op->Asl.NameSeg))
145         {
146             /* For _PS1/_PS2/_PS3, a _PS0 must exist */
147 
148             if (!ApFindNameInScope (METHOD_NAME__PS0, Op))
149             {
150                 sprintf (AslGbl_MsgBuffer,
151                     "%4.4s requires _PS0 in same scope", Op->Asl.NameSeg);
152 
153                 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
154                     AslGbl_MsgBuffer);
155             }
156         }
157 
158         /* Get the name node */
159 
160         Next = Op->Asl.Child;
161 
162         /* Get the NumArguments node */
163 
164         Next = Next->Asl.Next;
165         MethodInfo->NumArguments = (UINT8)
166             (((UINT8) Next->Asl.Value.Integer) & 0x07);
167 
168         /* Get the SerializeRule and SyncLevel nodes, ignored here */
169 
170         Next = Next->Asl.Next;
171         MethodInfo->ShouldBeSerialized = (UINT8) Next->Asl.Value.Integer;
172 
173         Next = Next->Asl.Next;
174         ArgNode = Next;
175 
176         /* Get the ReturnType node */
177 
178         Next = Next->Asl.Next;
179 
180         NextType = Next->Asl.Child;
181 
182         MethodInfo->ValidReturnTypes = MtProcessTypeOp (NextType);
183 
184         /* Get the ParameterType node */
185 
186         Next = Next->Asl.Next;
187 
188         NextType = Next->Asl.Child;
189         if (!NextType)
190         {
191             /*
192              * The optional parameter types list was omitted  at the source
193              * level. Use the Argument count parameter instead.
194              */
195             ActualArgs = MethodInfo->NumArguments;
196         }
197         else
198         {
199             ActualArgs = MtProcessParameterTypeList (NextType,
200                 MethodInfo->ValidArgTypes);
201         }
202 
203         if ((MethodInfo->NumArguments) &&
204             (MethodInfo->NumArguments != ActualArgs))
205         {
206             sprintf (AslGbl_MsgBuffer,
207                 "Length = %u", ActualArgs);
208             AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_MISMATCH,
209                 Op->Asl.Child->Asl.Next, AslGbl_MsgBuffer);
210         }
211 
212         /* Allow numarguments == 0 for Function() */
213 
214         if ((!MethodInfo->NumArguments) && (ActualArgs))
215         {
216             MethodInfo->NumArguments = ActualArgs;
217             ArgNode->Asl.Value.Integer |= ActualArgs;
218         }
219 
220         /*
221          * Actual arguments are initialized at method entry.
222          * All other ArgX "registers" can be used as locals, so we
223          * track their initialization.
224          */
225         for (i = 0; i < MethodInfo->NumArguments; i++)
226         {
227             MethodInfo->ArgInitialized[i] = TRUE;
228         }
229         break;
230 
231     case PARSEOP_METHODCALL:
232 
233         /* Check for a recursive method call */
234 
235         if (MethodInfo &&
236            (Op->Asl.Node == MethodInfo->Op->Asl.Node))
237         {
238             if (MethodInfo->CreatesNamedObjects)
239             {
240                 /*
241                  * This is an error, as it will fail at runtime on all ACPI
242                  * implementations. Any named object declarations will be
243                  * executed twice, causing failure the second time. Note,
244                  * this is independent of whether the method is declared
245                  * Serialized, because the same thread is attempting to
246                  * reenter the method, and this will always succeed.
247                  */
248                 AslDualParseOpError (ASL_ERROR, ASL_MSG_ILLEGAL_RECURSION, Op,
249                     Op->Asl.Value.String, ASL_MSG_FOUND_HERE, MethodInfo->Op,
250                     MethodInfo->Op->Asl.ExternalName);
251             }
252             else
253             {
254                 /* Method does not create objects, issue a remark */
255 
256                 AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName);
257             }
258         }
259         break;
260 
261     case PARSEOP_LOCAL0:
262     case PARSEOP_LOCAL1:
263     case PARSEOP_LOCAL2:
264     case PARSEOP_LOCAL3:
265     case PARSEOP_LOCAL4:
266     case PARSEOP_LOCAL5:
267     case PARSEOP_LOCAL6:
268     case PARSEOP_LOCAL7:
269 
270         if (!MethodInfo)
271         {
272             /*
273              * Local was used outside a control method, or there was an error
274              * in the method declaration.
275              */
276             AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD,
277                 Op, Op->Asl.ExternalName);
278             return (AE_ERROR);
279         }
280 
281         RegisterNumber = (Op->Asl.AmlOpcode & 0x0007);
282 
283         /*
284          * If the local is being used as a target, mark the local
285          * initialized
286          */
287         if (Op->Asl.CompileFlags & OP_IS_TARGET)
288         {
289             MethodInfo->LocalInitialized[RegisterNumber] = TRUE;
290         }
291 
292         /*
293          * Otherwise, this is a reference, check if the local
294          * has been previously initialized.
295          *
296          * The only operator that accepts an uninitialized value is ObjectType()
297          */
298         else if ((!MethodInfo->LocalInitialized[RegisterNumber]) &&
299                  (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
300         {
301             LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30);
302             AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName);
303         }
304         break;
305 
306     case PARSEOP_ARG0:
307     case PARSEOP_ARG1:
308     case PARSEOP_ARG2:
309     case PARSEOP_ARG3:
310     case PARSEOP_ARG4:
311     case PARSEOP_ARG5:
312     case PARSEOP_ARG6:
313 
314         if (!MethodInfo)
315         {
316             /*
317              * Arg was used outside a control method, or there was an error
318              * in the method declaration.
319              */
320             AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD,
321                 Op, Op->Asl.ExternalName);
322             return (AE_ERROR);
323         }
324 
325         RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8;
326         ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30);
327 
328         /*
329          * If the Arg is being used as a target, mark the local
330          * initialized
331          */
332         if (Op->Asl.CompileFlags & OP_IS_TARGET)
333         {
334             MethodInfo->ArgInitialized[RegisterNumber] = TRUE;
335         }
336 
337         /*
338          * Otherwise, this is a reference, check if the Arg
339          * has been previously initialized.
340          *
341          * The only operator that accepts an uninitialized value is ObjectType()
342          */
343         else if ((!MethodInfo->ArgInitialized[RegisterNumber]) &&
344             (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
345         {
346             AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName);
347         }
348 
349         /* Flag this arg if it is not a "real" argument to the method */
350 
351         if (RegisterNumber >= MethodInfo->NumArguments)
352         {
353             AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName);
354         }
355         break;
356 
357     case PARSEOP_RETURN:
358 
359         if (!MethodInfo)
360         {
361             /*
362              * Probably was an error in the method declaration,
363              * no additional error here
364              */
365             ACPI_WARNING ((AE_INFO, "%p, No parent method", Op));
366             return (AE_ERROR);
367         }
368 
369         /*
370          * A child indicates a possible return value. A simple Return or
371          * Return() is marked with OP_IS_NULL_RETURN by the parser so
372          * that it is not counted as a "real" return-with-value, although
373          * the AML code that is actually emitted is Return(0). The AML
374          * definition of Return has a required parameter, so we are
375          * forced to convert a null return to Return(0).
376          */
377         if ((Op->Asl.Child) &&
378             (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) &&
379             (!(Op->Asl.Child->Asl.CompileFlags & OP_IS_NULL_RETURN)))
380         {
381             MethodInfo->NumReturnWithValue++;
382         }
383         else
384         {
385             MethodInfo->NumReturnNoValue++;
386         }
387         break;
388 
389     case PARSEOP_BREAK:
390     case PARSEOP_CONTINUE:
391 
392         Next = Op->Asl.Parent;
393         while (Next)
394         {
395             if (Next->Asl.ParseOpcode == PARSEOP_WHILE)
396             {
397                 break;
398             }
399             Next = Next->Asl.Parent;
400         }
401 
402         if (!Next)
403         {
404             AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL);
405         }
406         break;
407 
408     case PARSEOP_STALL:
409 
410         /* We can range check if the argument is an integer */
411 
412         if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) &&
413             (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX))
414         {
415             AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL);
416         }
417         break;
418 
419     case PARSEOP_DEVICE:
420 
421         /* Check usage of _HID and _ADR objects */
422 
423         HidExists = ApFindNameInDeviceTree (METHOD_NAME__HID, Op);
424         AdrExists = ApFindNameInDeviceTree (METHOD_NAME__ADR, Op);
425 
426         if (!HidExists && !AdrExists)
427         {
428             AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
429                 "Device object requires a _HID or _ADR in same scope");
430         }
431         else if (HidExists && AdrExists)
432         {
433             /*
434              * According to the ACPI spec, "A device object must contain
435              * either an _HID object or an _ADR object, but should not contain
436              * both".
437              */
438             AslError (ASL_WARNING, ASL_MSG_MULTIPLE_TYPES, Op,
439                 "Device object requires either a _HID or _ADR, but not both");
440         }
441         break;
442 
443     case PARSEOP_EVENT:
444     case PARSEOP_MUTEX:
445     case PARSEOP_OPERATIONREGION:
446     case PARSEOP_POWERRESOURCE:
447     case PARSEOP_PROCESSOR:
448     case PARSEOP_THERMALZONE:
449 
450         /*
451          * The first operand is a name to be created in the namespace.
452          * Check against the reserved list.
453          */
454         i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg);
455         if (i < ACPI_VALID_RESERVED_NAME_MAX)
456         {
457             AslError (ASL_ERROR, ASL_MSG_RESERVED_USE,
458                 Op, Op->Asl.ExternalName);
459         }
460 
461         MtCheckStaticOperationRegionInMethod (Op);
462         break;
463 
464     case PARSEOP_NAME:
465 
466         /* Typecheck any predefined names statically defined with Name() */
467 
468         ApCheckForPredefinedObject (Op, Op->Asl.NameSeg);
469 
470         /* Special typechecking for _HID */
471 
472         if (ACPI_COMPARE_NAMESEG (METHOD_NAME__HID, Op->Asl.NameSeg))
473         {
474             Next = Op->Asl.Child->Asl.Next;
475             AnCheckId (Next, ASL_TYPE_HID);
476         }
477 
478         /* Special typechecking for _CID */
479 
480         else if (ACPI_COMPARE_NAMESEG (METHOD_NAME__CID, Op->Asl.NameSeg))
481         {
482             Next = Op->Asl.Child->Asl.Next;
483 
484             if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
485                 (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE))
486             {
487                 Next = Next->Asl.Child;
488                 while (Next)
489                 {
490                     AnCheckId (Next, ASL_TYPE_CID);
491                     Next = Next->Asl.Next;
492                 }
493             }
494             else
495             {
496                 AnCheckId (Next, ASL_TYPE_CID);
497             }
498         }
499 
500         break;
501 
502     default:
503 
504         break;
505     }
506 
507     /* Check for named object creation within a non-serialized method */
508 
509     MtCheckNamedObjectInMethod (Op, MethodInfo);
510     return (AE_OK);
511 }
512 
513 
514 /*******************************************************************************
515  *
516  * FUNCTION:    MtProcessTypeOp
517  *
518  * PARAMETERS:  Op                  - Op representing a btype
519  *
520  * RETURN:      Btype represented by Op
521  *
522  * DESCRIPTION: Process a parse object that represents single parameter type or
523  *              a return type in method, function, and external declarations.
524  *
525  ******************************************************************************/
526 
527 UINT32
528 MtProcessTypeOp (
529     ACPI_PARSE_OBJECT       *TypeOp)
530 {
531     UINT32                  Btype = ACPI_BTYPE_ANY;
532 
533 
534     while (TypeOp)
535     {
536         Btype |= AnMapObjTypeToBtype (TypeOp);
537         TypeOp->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
538         TypeOp = TypeOp->Asl.Next;
539     }
540 
541     return (Btype);
542 }
543 
544 
545 /*******************************************************************************
546  *
547  * FUNCTION:    MtProcessParameterTypeList
548  *
549  * PARAMETERS:  Op                  - Op representing a btype
550  *
551  * RETURN:      Btype represented by Op
552  *
553  * DESCRIPTION: Process a parse object that represents a parameter type list in
554  *              method, function, and external declarations.
555  *
556  ******************************************************************************/
557 
558 UINT8
559 MtProcessParameterTypeList (
560     ACPI_PARSE_OBJECT       *ParamTypeOp,
561     UINT32                  *TypeList)
562 {
563     UINT8                   ParameterCount = 0;
564 
565 
566     while (ParamTypeOp)
567     {
568         TypeList[ParameterCount] =
569             MtProcessTypeOp (ParamTypeOp->Asl.Child);
570 
571         ParameterCount++;
572         ParamTypeOp = ParamTypeOp->Asl.Next;
573     }
574 
575     return (ParameterCount);
576 }
577 
578 
579 /*******************************************************************************
580  *
581  * FUNCTION:    MtCheckNamedObjectInMethod
582  *
583  * PARAMETERS:  Op                  - Current parser op
584  *              MethodInfo          - Info for method being parsed
585  *
586  * RETURN:      None
587  *
588  * DESCRIPTION: Detect if a non-serialized method is creating a named object,
589  *              which could possibly cause problems if two threads execute
590  *              the method concurrently. Emit a remark in this case.
591  *
592  ******************************************************************************/
593 
594 static void
595 MtCheckNamedObjectInMethod (
596     ACPI_PARSE_OBJECT       *Op,
597     ASL_METHOD_INFO         *MethodInfo)
598 {
599     const ACPI_OPCODE_INFO  *OpInfo;
600     char                    *ExternalPath;
601 
602 
603     /* We don't care about actual method declarations or scopes */
604 
605     if ((Op->Asl.AmlOpcode == AML_METHOD_OP) ||
606         (Op->Asl.AmlOpcode == AML_SCOPE_OP))
607     {
608         return;
609     }
610 
611     /* Determine if we are creating a named object within a method */
612 
613     if (!MethodInfo)
614     {
615         return;
616     }
617 
618     OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
619     if (OpInfo->Class == AML_CLASS_NAMED_OBJECT)
620     {
621         /*
622          * 1) Mark the method as a method that creates named objects.
623          *
624          * 2) Issue a remark indicating the inefficiency of creating named
625          * objects within a method (Except for compiler-emitted temporary
626          * variables).
627          *
628          * 3) If the method is non-serialized, emit a remark that the method
629          * should be serialized.
630          *
631          * Reason: If a thread blocks within the method for any reason, and
632          * another thread enters the method, the method will fail because
633          * an attempt will be made to create the same object twice.
634          */
635         ExternalPath = AcpiNsGetNormalizedPathname (MethodInfo->Op->Asl.Node, TRUE);
636 
637         /* No error for compiler temp variables (name starts with "_T_") */
638 
639         if ((Op->Asl.NameSeg[0] != '_') &&
640             (Op->Asl.NameSeg[1] != 'T') &&
641             (Op->Asl.NameSeg[2] != '_'))
642         {
643             AslError (ASL_REMARK, ASL_MSG_NAMED_OBJECT_CREATION, Op,
644                 ExternalPath);
645         }
646 
647         MethodInfo->CreatesNamedObjects = TRUE;
648         if (!MethodInfo->ShouldBeSerialized)
649         {
650             AslError (ASL_REMARK, ASL_MSG_SERIALIZED_REQUIRED, MethodInfo->Op,
651                 ExternalPath);
652 
653             /* Emit message only ONCE per method */
654 
655             MethodInfo->ShouldBeSerialized = TRUE;
656         }
657 
658         if (ExternalPath)
659         {
660             ACPI_FREE (ExternalPath);
661         }
662     }
663 }
664 
665 
666 /*******************************************************************************
667  *
668  * FUNCTION:    MtCheckStaticOperationRegionInMethod
669  *
670  * PARAMETERS:  Op                  - Current parser op
671  *
672  * RETURN:      None
673  *
674  * DESCRIPTION: Warns if an Operation Region with static address or length
675  *              is declared inside a control method
676  *
677  ******************************************************************************/
678 
679 static void
680 MtCheckStaticOperationRegionInMethod(
681     ACPI_PARSE_OBJECT*       Op)
682 {
683     ACPI_PARSE_OBJECT*       AddressOp;
684     ACPI_PARSE_OBJECT*       LengthOp;
685 
686 
687     if (Op->Asl.ParseOpcode != PARSEOP_OPERATIONREGION)
688     {
689         return;
690     }
691 
692     /*
693      * OperationRegion should have 4 arguments defined. At this point, we
694      * assume that the parse tree is well-formed.
695      */
696     AddressOp = Op->Asl.Child->Asl.Next->Asl.Next;
697     LengthOp = Op->Asl.Child->Asl.Next->Asl.Next->Asl.Next;
698 
699     if (UtGetParentMethodOp (Op) &&
700         AddressOp->Asl.ParseOpcode == PARSEOP_INTEGER &&
701         LengthOp->Asl.ParseOpcode == PARSEOP_INTEGER)
702     {
703         /*
704          * At this point, a static operation region declared inside of a
705          * control method has been found. Throw a warning because this is
706          * highly inefficient.
707          */
708         AslError(ASL_WARNING, ASL_MSG_STATIC_OPREGION_IN_METHOD, Op, NULL);
709     }
710 
711     return;
712 }
713 
714 
715 /*******************************************************************************
716  *
717  * FUNCTION:    MtMethodAnalysisWalkEnd
718  *
719  * PARAMETERS:  ASL_WALK_CALLBACK
720  *
721  * RETURN:      Status
722  *
723  * DESCRIPTION: Ascending callback for analysis walk. Complete method
724  *              return analysis.
725  *
726  ******************************************************************************/
727 
728 ACPI_STATUS
729 MtMethodAnalysisWalkEnd (
730     ACPI_PARSE_OBJECT       *Op,
731     UINT32                  Level,
732     void                    *Context)
733 {
734     ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
735     ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack;
736     char                    *ExternalPath;
737 
738 
739     switch (Op->Asl.ParseOpcode)
740     {
741     case PARSEOP_METHOD:
742     case PARSEOP_RETURN:
743 
744         if (!MethodInfo)
745         {
746             printf ("No method info for method! [%s]\n", Op->Asl.Namepath);
747             AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op,
748                 "No method info for this method");
749 
750             CmCleanupAndExit ();
751             return (AE_AML_INTERNAL);
752         }
753         break;
754 
755     default:
756 
757         break;
758     }
759 
760     switch (Op->Asl.ParseOpcode)
761     {
762     case PARSEOP_METHOD:
763 
764         WalkInfo->MethodStack = MethodInfo->Next;
765 
766         /*
767          * Check if there is no return statement at the end of the
768          * method AND we can actually get there -- i.e., the execution
769          * of the method can possibly terminate without a return statement.
770          */
771         if ((!AnLastStatementIsReturn (Op)) &&
772             (!(Op->Asl.CompileFlags & OP_HAS_NO_EXIT)))
773         {
774             /*
775              * No return statement, and execution can possibly exit
776              * via this path. This is equivalent to Return ()
777              */
778             MethodInfo->NumReturnNoValue++;
779         }
780 
781         /*
782          * Check for case where some return statements have a return value
783          * and some do not. Exit without a return statement is a return with
784          * no value
785          */
786         if (MethodInfo->NumReturnNoValue &&
787             MethodInfo->NumReturnWithValue)
788         {
789             ExternalPath = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE);
790 
791             AslError (ASL_WARNING, ASL_MSG_RETURN_TYPES, Op,
792                 ExternalPath);
793 
794             if (ExternalPath)
795             {
796                 ACPI_FREE (ExternalPath);
797             }
798         }
799 
800         /*
801          * If there are any RETURN() statements with no value, or there is a
802          * control path that allows the method to exit without a return value,
803          * we mark the method as a method that does not return a value. This
804          * knowledge can be used to check method invocations that expect a
805          * returned value.
806          */
807         if (MethodInfo->NumReturnNoValue)
808         {
809             if (MethodInfo->NumReturnWithValue)
810             {
811                 Op->Asl.CompileFlags |= OP_METHOD_SOME_NO_RETVAL;
812             }
813             else
814             {
815                 Op->Asl.CompileFlags |= OP_METHOD_NO_RETVAL;
816             }
817         }
818 
819         /*
820          * Check predefined method names for correct return behavior
821          * and correct number of arguments. Also, some special checks
822          * For GPE and _REG methods.
823          */
824         if (ApCheckForPredefinedMethod (Op, MethodInfo))
825         {
826             /* Special check for two names like _L01 and _E01 in same scope */
827 
828             ApCheckForGpeNameConflict (Op);
829 
830             /*
831              * Special check for _REG: Must have an operation region definition
832              * within the same scope!
833              */
834             ApCheckRegMethod (Op);
835         }
836 
837         ACPI_FREE (MethodInfo);
838         break;
839 
840     case PARSEOP_NAME:
841 
842          /* Special check for two names like _L01 and _E01 in same scope */
843 
844         ApCheckForGpeNameConflict (Op);
845         break;
846 
847     case PARSEOP_RETURN:
848 
849         /*
850          * If the parent is a predefined method name, attempt to typecheck
851          * the return value. Only static types can be validated.
852          */
853         ApCheckPredefinedReturnValue (Op, MethodInfo);
854 
855         /*
856          * The parent block does not "exit" and continue execution -- the
857          * method is terminated here with the Return() statement.
858          */
859         Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
860 
861         /* Used in the "typing" pass later */
862 
863         Op->Asl.ParentMethod = MethodInfo->Op;
864 
865         /*
866          * If there is a peer node after the return statement, then this
867          * node is unreachable code -- i.e., it won't be executed because of
868          * the preceding Return() statement.
869          */
870         if (Op->Asl.Next)
871         {
872             AslError (ASL_WARNING, ASL_MSG_UNREACHABLE_CODE,
873                 Op->Asl.Next, NULL);
874         }
875         break;
876 
877     case PARSEOP_IF:
878 
879         if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
880             (Op->Asl.Next) &&
881             (Op->Asl.Next->Asl.ParseOpcode == PARSEOP_ELSE))
882         {
883             /*
884              * This IF has a corresponding ELSE. The IF block has no exit,
885              * (it contains an unconditional Return)
886              * mark the ELSE block to remember this fact.
887              */
888             Op->Asl.Next->Asl.CompileFlags |= OP_IF_HAS_NO_EXIT;
889         }
890         break;
891 
892     case PARSEOP_ELSE:
893 
894         if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
895             (Op->Asl.CompileFlags & OP_IF_HAS_NO_EXIT))
896         {
897             /*
898              * This ELSE block has no exit and the corresponding IF block
899              * has no exit either. Therefore, the parent node has no exit.
900              */
901             Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
902         }
903         break;
904 
905 
906     default:
907 
908         if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
909             (Op->Asl.Parent))
910         {
911             /* If this node has no exit, then the parent has no exit either */
912 
913             Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
914         }
915         break;
916     }
917 
918     return (AE_OK);
919 }
920