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