xref: /netbsd-src/sys/external/bsd/acpica/dist/compiler/aslmethod.c (revision e7ac2a8b5bd66fa2e050809de09a075c36a7014d)
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             MethodInfo->NumArguments = ActualArgs;
202             ArgNode->Asl.Value.Integer |= ActualArgs;
203         }
204 
205         if ((MethodInfo->NumArguments) &&
206             (MethodInfo->NumArguments != ActualArgs))
207         {
208             sprintf (AslGbl_MsgBuffer,
209                 "Length = %u", ActualArgs);
210             AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_MISMATCH,
211                 Op->Asl.Child->Asl.Next, AslGbl_MsgBuffer);
212         }
213 
214         /* Allow numarguments == 0 for Function() */
215 
216         if ((!MethodInfo->NumArguments) && (ActualArgs))
217         {
218             MethodInfo->NumArguments = ActualArgs;
219             ArgNode->Asl.Value.Integer |= ActualArgs;
220         }
221 
222         /*
223          * Actual arguments are initialized at method entry.
224          * All other ArgX "registers" can be used as locals, so we
225          * track their initialization.
226          */
227         for (i = 0; i < MethodInfo->NumArguments; i++)
228         {
229             MethodInfo->ArgInitialized[i] = TRUE;
230         }
231         break;
232 
233     case PARSEOP_METHODCALL:
234 
235         /* Check for a recursive method call */
236 
237         if (MethodInfo &&
238            (Op->Asl.Node == MethodInfo->Op->Asl.Node))
239         {
240             if (MethodInfo->CreatesNamedObjects)
241             {
242                 /*
243                  * This is an error, as it will fail at runtime on all ACPI
244                  * implementations. Any named object declarations will be
245                  * executed twice, causing failure the second time. Note,
246                  * this is independent of whether the method is declared
247                  * Serialized, because the same thread is attempting to
248                  * reenter the method, and this will always succeed.
249                  */
250                 AslDualParseOpError (ASL_ERROR, ASL_MSG_ILLEGAL_RECURSION, Op,
251                     Op->Asl.Value.String, ASL_MSG_FOUND_HERE, MethodInfo->Op,
252                     MethodInfo->Op->Asl.ExternalName);
253             }
254             else
255             {
256                 /* Method does not create objects, issue a remark */
257 
258                 AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName);
259             }
260         }
261         break;
262 
263     case PARSEOP_LOCAL0:
264     case PARSEOP_LOCAL1:
265     case PARSEOP_LOCAL2:
266     case PARSEOP_LOCAL3:
267     case PARSEOP_LOCAL4:
268     case PARSEOP_LOCAL5:
269     case PARSEOP_LOCAL6:
270     case PARSEOP_LOCAL7:
271 
272         if (!MethodInfo)
273         {
274             /*
275              * Local was used outside a control method, or there was an error
276              * in the method declaration.
277              */
278             AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD,
279                 Op, Op->Asl.ExternalName);
280             return (AE_ERROR);
281         }
282 
283         RegisterNumber = (Op->Asl.AmlOpcode & 0x0007);
284 
285         /*
286          * If the local is being used as a target, mark the local
287          * initialized
288          */
289         if (Op->Asl.CompileFlags & OP_IS_TARGET)
290         {
291             MethodInfo->LocalInitialized[RegisterNumber] = TRUE;
292         }
293 
294         /*
295          * Otherwise, this is a reference, check if the local
296          * has been previously initialized.
297          *
298          * The only operator that accepts an uninitialized value is ObjectType()
299          */
300         else if ((!MethodInfo->LocalInitialized[RegisterNumber]) &&
301                  (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
302         {
303             LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30);
304             AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName);
305         }
306         break;
307 
308     case PARSEOP_ARG0:
309     case PARSEOP_ARG1:
310     case PARSEOP_ARG2:
311     case PARSEOP_ARG3:
312     case PARSEOP_ARG4:
313     case PARSEOP_ARG5:
314     case PARSEOP_ARG6:
315 
316         if (!MethodInfo)
317         {
318             /*
319              * Arg was used outside a control method, or there was an error
320              * in the method declaration.
321              */
322             AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD,
323                 Op, Op->Asl.ExternalName);
324             return (AE_ERROR);
325         }
326 
327         RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8;
328         ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30);
329 
330         /*
331          * If the Arg is being used as a target, mark the local
332          * initialized
333          */
334         if (Op->Asl.CompileFlags & OP_IS_TARGET)
335         {
336             MethodInfo->ArgInitialized[RegisterNumber] = TRUE;
337         }
338 
339         /*
340          * Otherwise, this is a reference, check if the Arg
341          * has been previously initialized.
342          *
343          * The only operator that accepts an uninitialized value is ObjectType()
344          */
345         else if ((!MethodInfo->ArgInitialized[RegisterNumber]) &&
346             (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
347         {
348             AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName);
349         }
350 
351         /* Flag this arg if it is not a "real" argument to the method */
352 
353         if (RegisterNumber >= MethodInfo->NumArguments)
354         {
355             AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName);
356         }
357         break;
358 
359     case PARSEOP_RETURN:
360 
361         if (!MethodInfo)
362         {
363             /*
364              * Probably was an error in the method declaration,
365              * no additional error here
366              */
367             ACPI_WARNING ((AE_INFO, "%p, No parent method", Op));
368             return (AE_ERROR);
369         }
370 
371         /*
372          * A child indicates a possible return value. A simple Return or
373          * Return() is marked with OP_IS_NULL_RETURN by the parser so
374          * that it is not counted as a "real" return-with-value, although
375          * the AML code that is actually emitted is Return(0). The AML
376          * definition of Return has a required parameter, so we are
377          * forced to convert a null return to Return(0).
378          */
379         if ((Op->Asl.Child) &&
380             (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) &&
381             (!(Op->Asl.Child->Asl.CompileFlags & OP_IS_NULL_RETURN)))
382         {
383             MethodInfo->NumReturnWithValue++;
384         }
385         else
386         {
387             MethodInfo->NumReturnNoValue++;
388         }
389         break;
390 
391     case PARSEOP_BREAK:
392     case PARSEOP_CONTINUE:
393 
394         Next = Op->Asl.Parent;
395         while (Next)
396         {
397             if (Next->Asl.ParseOpcode == PARSEOP_WHILE)
398             {
399                 break;
400             }
401             Next = Next->Asl.Parent;
402         }
403 
404         if (!Next)
405         {
406             AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL);
407         }
408         break;
409 
410     case PARSEOP_STALL:
411 
412         /* We can range check if the argument is an integer */
413 
414         if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) &&
415             (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX))
416         {
417             AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL);
418         }
419         break;
420 
421     case PARSEOP_DEVICE:
422 
423         /* Check usage of _HID and _ADR objects */
424 
425         HidExists = ApFindNameInDeviceTree (METHOD_NAME__HID, Op);
426         AdrExists = ApFindNameInDeviceTree (METHOD_NAME__ADR, Op);
427 
428         if (!HidExists && !AdrExists)
429         {
430             AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
431                 "Device object requires a _HID or _ADR in same scope");
432         }
433         else if (HidExists && AdrExists)
434         {
435             /*
436              * According to the ACPI spec, "A device object must contain
437              * either an _HID object or an _ADR object, but should not contain
438              * both".
439              */
440             AslError (ASL_WARNING, ASL_MSG_MULTIPLE_TYPES, Op,
441                 "Device object requires either a _HID or _ADR, but not both");
442         }
443         break;
444 
445     case PARSEOP_EVENT:
446     case PARSEOP_MUTEX:
447     case PARSEOP_OPERATIONREGION:
448     case PARSEOP_POWERRESOURCE:
449     case PARSEOP_PROCESSOR:
450     case PARSEOP_THERMALZONE:
451 
452         /*
453          * The first operand is a name to be created in the namespace.
454          * Check against the reserved list.
455          */
456         i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg);
457         if (i < ACPI_VALID_RESERVED_NAME_MAX)
458         {
459             AslError (ASL_ERROR, ASL_MSG_RESERVED_USE,
460                 Op, Op->Asl.ExternalName);
461         }
462 
463         MtCheckStaticOperationRegionInMethod (Op);
464         break;
465 
466     case PARSEOP_NAME:
467 
468         /* Typecheck any predefined names statically defined with Name() */
469 
470         ApCheckForPredefinedObject (Op, Op->Asl.NameSeg);
471 
472         /* Special typechecking for _HID */
473 
474         if (ACPI_COMPARE_NAMESEG (METHOD_NAME__HID, Op->Asl.NameSeg))
475         {
476             Next = Op->Asl.Child->Asl.Next;
477             AnCheckId (Next, ASL_TYPE_HID);
478         }
479 
480         /* Special typechecking for _CID */
481 
482         else if (ACPI_COMPARE_NAMESEG (METHOD_NAME__CID, Op->Asl.NameSeg))
483         {
484             Next = Op->Asl.Child->Asl.Next;
485 
486             if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
487                 (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE))
488             {
489                 Next = Next->Asl.Child;
490                 while (Next)
491                 {
492                     AnCheckId (Next, ASL_TYPE_CID);
493                     Next = Next->Asl.Next;
494                 }
495             }
496             else
497             {
498                 AnCheckId (Next, ASL_TYPE_CID);
499             }
500         }
501 
502         break;
503 
504     default:
505 
506         break;
507     }
508 
509     /* Check for named object creation within a non-serialized method */
510 
511     MtCheckNamedObjectInMethod (Op, MethodInfo);
512     return (AE_OK);
513 }
514 
515 
516 /*******************************************************************************
517  *
518  * FUNCTION:    MtProcessTypeOp
519  *
520  * PARAMETERS:  Op                  - Op representing a btype
521  *
522  * RETURN:      Btype represented by Op
523  *
524  * DESCRIPTION: Process a parse object that represents single parameter type or
525  *              a return type in method, function, and external declarations.
526  *
527  ******************************************************************************/
528 
529 UINT32
530 MtProcessTypeOp (
531     ACPI_PARSE_OBJECT       *TypeOp)
532 {
533     UINT32                  Btype = ACPI_BTYPE_ANY;
534 
535 
536     while (TypeOp)
537     {
538         Btype |= AnMapObjTypeToBtype (TypeOp);
539         TypeOp->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
540         TypeOp = TypeOp->Asl.Next;
541     }
542 
543     return (Btype);
544 }
545 
546 
547 /*******************************************************************************
548  *
549  * FUNCTION:    MtProcessParameterTypeList
550  *
551  * PARAMETERS:  Op                  - Op representing a btype
552  *
553  * RETURN:      Btype represented by Op
554  *
555  * DESCRIPTION: Process a parse object that represents a parameter type list in
556  *              method, function, and external declarations.
557  *
558  ******************************************************************************/
559 
560 UINT8
561 MtProcessParameterTypeList (
562     ACPI_PARSE_OBJECT       *ParamTypeOp,
563     UINT32                  *TypeList)
564 {
565     UINT8                   ParameterCount = 0;
566 
567 
568     if (ParamTypeOp && ParamTypeOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)
569     {
570         /* Special case for a single parameter without braces */
571 
572         TypeList[ParameterCount] =
573             MtProcessTypeOp (ParamTypeOp);
574 
575         return (1);
576     }
577 
578     while (ParamTypeOp)
579     {
580         TypeList[ParameterCount] =
581             MtProcessTypeOp (ParamTypeOp->Asl.Child);
582 
583         ParameterCount++;
584         ParamTypeOp = ParamTypeOp->Asl.Next;
585     }
586 
587     return (ParameterCount);
588 }
589 
590 
591 /*******************************************************************************
592  *
593  * FUNCTION:    MtCheckNamedObjectInMethod
594  *
595  * PARAMETERS:  Op                  - Current parser op
596  *              MethodInfo          - Info for method being parsed
597  *
598  * RETURN:      None
599  *
600  * DESCRIPTION: Detect if a non-serialized method is creating a named object,
601  *              which could possibly cause problems if two threads execute
602  *              the method concurrently. Emit a remark in this case.
603  *
604  ******************************************************************************/
605 
606 static void
607 MtCheckNamedObjectInMethod (
608     ACPI_PARSE_OBJECT       *Op,
609     ASL_METHOD_INFO         *MethodInfo)
610 {
611     const ACPI_OPCODE_INFO  *OpInfo;
612     char                    *ExternalPath;
613 
614 
615     /* We don't care about actual method declarations or scopes */
616 
617     if ((Op->Asl.AmlOpcode == AML_METHOD_OP) ||
618         (Op->Asl.AmlOpcode == AML_SCOPE_OP))
619     {
620         return;
621     }
622 
623     /* Determine if we are creating a named object within a method */
624 
625     if (!MethodInfo)
626     {
627         return;
628     }
629 
630     OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
631     if ((OpInfo->Class == AML_CLASS_NAMED_OBJECT) && (Op->Asl.AmlOpcode != AML_FIELD_OP))
632     {
633         /*
634          * 1) Mark the method as a method that creates named objects.
635          *
636          * 2) Issue a remark indicating the inefficiency of creating named
637          * objects within a method (Except for compiler-emitted temporary
638          * variables).
639          *
640          * 3) If the method is non-serialized, emit a remark that the method
641          * should be serialized.
642          *
643          * Reason: If a thread blocks within the method for any reason, and
644          * another thread enters the method, the method will fail because
645          * an attempt will be made to create the same object twice.
646          *
647          * Note: The Field opcode is disallowed here because Field() does not
648          * create a new named object.
649          */
650         ExternalPath = AcpiNsGetNormalizedPathname (MethodInfo->Op->Asl.Node, TRUE);
651 
652         /* No error for compiler temp variables (name starts with "_T_") */
653 
654         if ((Op->Asl.NameSeg[0] != '_') &&
655             (Op->Asl.NameSeg[1] != 'T') &&
656             (Op->Asl.NameSeg[2] != '_'))
657         {
658             AslError (ASL_REMARK, ASL_MSG_NAMED_OBJECT_CREATION, Op,
659                 ExternalPath);
660         }
661 
662         MethodInfo->CreatesNamedObjects = TRUE;
663         if (!MethodInfo->ShouldBeSerialized)
664         {
665             AslError (ASL_REMARK, ASL_MSG_SERIALIZED_REQUIRED, MethodInfo->Op,
666                 ExternalPath);
667 
668             /* Emit message only ONCE per method */
669 
670             MethodInfo->ShouldBeSerialized = TRUE;
671         }
672 
673         if (ExternalPath)
674         {
675             ACPI_FREE (ExternalPath);
676         }
677     }
678 }
679 
680 
681 /*******************************************************************************
682  *
683  * FUNCTION:    MtCheckStaticOperationRegionInMethod
684  *
685  * PARAMETERS:  Op                  - Current parser op
686  *
687  * RETURN:      None
688  *
689  * DESCRIPTION: Warns if an Operation Region with static address or length
690  *              is declared inside a control method
691  *
692  ******************************************************************************/
693 
694 static void
695 MtCheckStaticOperationRegionInMethod(
696     ACPI_PARSE_OBJECT*       Op)
697 {
698     ACPI_PARSE_OBJECT*       AddressOp;
699     ACPI_PARSE_OBJECT*       LengthOp;
700 
701 
702     if (Op->Asl.ParseOpcode != PARSEOP_OPERATIONREGION)
703     {
704         return;
705     }
706 
707     /*
708      * OperationRegion should have 4 arguments defined. At this point, we
709      * assume that the parse tree is well-formed.
710      */
711     AddressOp = Op->Asl.Child->Asl.Next->Asl.Next;
712     LengthOp = Op->Asl.Child->Asl.Next->Asl.Next->Asl.Next;
713 
714     if (UtGetParentMethodOp (Op) &&
715         AddressOp->Asl.ParseOpcode == PARSEOP_INTEGER &&
716         LengthOp->Asl.ParseOpcode == PARSEOP_INTEGER)
717     {
718         /*
719          * At this point, a static operation region declared inside of a
720          * control method has been found. Throw a warning because this is
721          * highly inefficient.
722          */
723         AslError(ASL_WARNING, ASL_MSG_STATIC_OPREGION_IN_METHOD, Op, NULL);
724     }
725 
726     return;
727 }
728 
729 
730 /*******************************************************************************
731  *
732  * FUNCTION:    MtMethodAnalysisWalkEnd
733  *
734  * PARAMETERS:  ASL_WALK_CALLBACK
735  *
736  * RETURN:      Status
737  *
738  * DESCRIPTION: Ascending callback for analysis walk. Complete method
739  *              return analysis.
740  *
741  ******************************************************************************/
742 
743 ACPI_STATUS
744 MtMethodAnalysisWalkEnd (
745     ACPI_PARSE_OBJECT       *Op,
746     UINT32                  Level,
747     void                    *Context)
748 {
749     ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
750     ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack;
751     char                    *ExternalPath;
752 
753 
754     switch (Op->Asl.ParseOpcode)
755     {
756     case PARSEOP_METHOD:
757     case PARSEOP_RETURN:
758 
759         if (!MethodInfo)
760         {
761             printf ("No method info for method! [%s]\n", Op->Asl.Namepath);
762             AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op,
763                 "No method info for this method");
764 
765             CmCleanupAndExit ();
766             return (AE_AML_INTERNAL);
767         }
768         break;
769 
770     default:
771 
772         break;
773     }
774 
775     switch (Op->Asl.ParseOpcode)
776     {
777     case PARSEOP_METHOD:
778 
779         WalkInfo->MethodStack = MethodInfo->Next;
780 
781         /*
782          * Check if there is no return statement at the end of the
783          * method AND we can actually get there -- i.e., the execution
784          * of the method can possibly terminate without a return statement.
785          */
786         if ((!AnLastStatementIsReturn (Op)) &&
787             (!(Op->Asl.CompileFlags & OP_HAS_NO_EXIT)))
788         {
789             /*
790              * No return statement, and execution can possibly exit
791              * via this path. This is equivalent to Return ()
792              */
793             MethodInfo->NumReturnNoValue++;
794         }
795 
796         /*
797          * Check for case where some return statements have a return value
798          * and some do not. Exit without a return statement is a return with
799          * no value
800          */
801         if (MethodInfo->NumReturnNoValue &&
802             MethodInfo->NumReturnWithValue)
803         {
804             ExternalPath = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE);
805 
806             AslError (ASL_WARNING, ASL_MSG_RETURN_TYPES, Op,
807                 ExternalPath);
808 
809             if (ExternalPath)
810             {
811                 ACPI_FREE (ExternalPath);
812             }
813         }
814 
815         /*
816          * If there are any RETURN() statements with no value, or there is a
817          * control path that allows the method to exit without a return value,
818          * we mark the method as a method that does not return a value. This
819          * knowledge can be used to check method invocations that expect a
820          * returned value.
821          */
822         if (MethodInfo->NumReturnNoValue)
823         {
824             if (MethodInfo->NumReturnWithValue)
825             {
826                 Op->Asl.CompileFlags |= OP_METHOD_SOME_NO_RETVAL;
827             }
828             else
829             {
830                 Op->Asl.CompileFlags |= OP_METHOD_NO_RETVAL;
831             }
832         }
833 
834         /*
835          * Check predefined method names for correct return behavior
836          * and correct number of arguments. Also, some special checks
837          * For GPE and _REG methods.
838          */
839         if (ApCheckForPredefinedMethod (Op, MethodInfo))
840         {
841             /* Special check for two names like _L01 and _E01 in same scope */
842 
843             ApCheckForGpeNameConflict (Op);
844 
845             /*
846              * Special check for _REG: Must have an operation region definition
847              * within the same scope!
848              */
849             ApCheckRegMethod (Op);
850         }
851 
852         ACPI_FREE (MethodInfo);
853         break;
854 
855     case PARSEOP_NAME:
856 
857          /* Special check for two names like _L01 and _E01 in same scope */
858 
859         ApCheckForGpeNameConflict (Op);
860         break;
861 
862     case PARSEOP_RETURN:
863 
864         /*
865          * If the parent is a predefined method name, attempt to typecheck
866          * the return value. Only static types can be validated.
867          */
868         ApCheckPredefinedReturnValue (Op, MethodInfo);
869 
870         /*
871          * The parent block does not "exit" and continue execution -- the
872          * method is terminated here with the Return() statement.
873          */
874         Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
875 
876         /* Used in the "typing" pass later */
877 
878         Op->Asl.ParentMethod = MethodInfo->Op;
879 
880         /*
881          * If there is a peer node after the return statement, then this
882          * node is unreachable code -- i.e., it won't be executed because of
883          * the preceding Return() statement.
884          */
885         if (Op->Asl.Next)
886         {
887             AslError (ASL_WARNING, ASL_MSG_UNREACHABLE_CODE,
888                 Op->Asl.Next, NULL);
889         }
890         break;
891 
892     case PARSEOP_IF:
893 
894         if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
895             (Op->Asl.Next) &&
896             (Op->Asl.Next->Asl.ParseOpcode == PARSEOP_ELSE))
897         {
898             /*
899              * This IF has a corresponding ELSE. The IF block has no exit,
900              * (it contains an unconditional Return)
901              * mark the ELSE block to remember this fact.
902              */
903             Op->Asl.Next->Asl.CompileFlags |= OP_IF_HAS_NO_EXIT;
904         }
905         break;
906 
907     case PARSEOP_ELSE:
908 
909         if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
910             (Op->Asl.CompileFlags & OP_IF_HAS_NO_EXIT))
911         {
912             /*
913              * This ELSE block has no exit and the corresponding IF block
914              * has no exit either. Therefore, the parent node has no exit.
915              */
916             Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
917         }
918         break;
919 
920 
921     default:
922 
923         if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
924             (Op->Asl.Parent))
925         {
926             /* If this node has no exit, then the parent has no exit either */
927 
928             Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
929         }
930         break;
931     }
932 
933     return (AE_OK);
934 }
935