Sync ACPICA with Intel's version 20140724.
[dragonfly.git] / sys / contrib / dev / acpica / source / compiler / aslmethod.c
1 /******************************************************************************
2  *
3  * Module Name: aslmethod.c - Control method analysis walk
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2014, 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
45 #include "aslcompiler.h"
46 #include "aslcompiler.y.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 void
58 MtCheckNamedObjectInMethod (
59     ACPI_PARSE_OBJECT       *Op,
60     ASL_METHOD_INFO         *MethodInfo);
61
62
63 /*******************************************************************************
64  *
65  * FUNCTION:    MtMethodAnalysisWalkBegin
66  *
67  * PARAMETERS:  ASL_WALK_CALLBACK
68  *
69  * RETURN:      Status
70  *
71  * DESCRIPTION: Descending callback for the analysis walk. Check methods for:
72  *              1) Initialized local variables
73  *              2) Valid arguments
74  *              3) Return types
75  *
76  ******************************************************************************/
77
78 ACPI_STATUS
79 MtMethodAnalysisWalkBegin (
80     ACPI_PARSE_OBJECT       *Op,
81     UINT32                  Level,
82     void                    *Context)
83 {
84     ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
85     ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack;
86     ACPI_PARSE_OBJECT       *Next;
87     UINT32                  RegisterNumber;
88     UINT32                  i;
89     char                    LocalName[] = "Local0";
90     char                    ArgName[] = "Arg0";
91     ACPI_PARSE_OBJECT       *ArgNode;
92     ACPI_PARSE_OBJECT       *NextType;
93     ACPI_PARSE_OBJECT       *NextParamType;
94     UINT8                   ActualArgs = 0;
95
96
97     switch (Op->Asl.ParseOpcode)
98     {
99     case PARSEOP_METHOD:
100
101         TotalMethods++;
102
103         /* Create and init method info */
104
105         MethodInfo       = UtLocalCalloc (sizeof (ASL_METHOD_INFO));
106         MethodInfo->Next = WalkInfo->MethodStack;
107         MethodInfo->Op = Op;
108
109         WalkInfo->MethodStack = MethodInfo;
110
111         /* Special handling for _DSD, must have a _HID also */
112
113         if (!ACPI_STRCMP (METHOD_NAME__DSD, Op->Asl.NameSeg))
114         {
115             if (!ApFindNameInScope (METHOD_NAME__HID, Op))
116             {
117                 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
118                     "_DSD requires _HID in same scope");
119             }
120         }
121
122         /* Get the name node */
123
124         Next = Op->Asl.Child;
125
126         /* Get the NumArguments node */
127
128         Next = Next->Asl.Next;
129         MethodInfo->NumArguments = (UINT8)
130             (((UINT8) Next->Asl.Value.Integer) & 0x07);
131
132         /* Get the SerializeRule and SyncLevel nodes, ignored here */
133
134         Next = Next->Asl.Next;
135         MethodInfo->ShouldBeSerialized = (UINT8) Next->Asl.Value.Integer;
136
137         Next = Next->Asl.Next;
138         ArgNode = Next;
139
140         /* Get the ReturnType node */
141
142         Next = Next->Asl.Next;
143
144         NextType = Next->Asl.Child;
145         while (NextType)
146         {
147             /* Get and map each of the ReturnTypes */
148
149             MethodInfo->ValidReturnTypes |= AnMapObjTypeToBtype (NextType);
150             NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
151             NextType = NextType->Asl.Next;
152         }
153
154         /* Get the ParameterType node */
155
156         Next = Next->Asl.Next;
157
158         NextType = Next->Asl.Child;
159         while (NextType)
160         {
161             if (NextType->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
162             {
163                 NextParamType = NextType->Asl.Child;
164                 while (NextParamType)
165                 {
166                     MethodInfo->ValidArgTypes[ActualArgs] |= AnMapObjTypeToBtype (NextParamType);
167                     NextParamType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
168                     NextParamType = NextParamType->Asl.Next;
169                 }
170             }
171             else
172             {
173                 MethodInfo->ValidArgTypes[ActualArgs] =
174                     AnMapObjTypeToBtype (NextType);
175                 NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
176                 ActualArgs++;
177             }
178
179             NextType = NextType->Asl.Next;
180         }
181
182         if ((MethodInfo->NumArguments) &&
183             (MethodInfo->NumArguments != ActualArgs))
184         {
185             /* error: Param list did not match number of args */
186         }
187
188         /* Allow numarguments == 0 for Function() */
189
190         if ((!MethodInfo->NumArguments) && (ActualArgs))
191         {
192             MethodInfo->NumArguments = ActualArgs;
193             ArgNode->Asl.Value.Integer |= ActualArgs;
194         }
195
196         /*
197          * Actual arguments are initialized at method entry.
198          * All other ArgX "registers" can be used as locals, so we
199          * track their initialization.
200          */
201         for (i = 0; i < MethodInfo->NumArguments; i++)
202         {
203             MethodInfo->ArgInitialized[i] = TRUE;
204         }
205         break;
206
207     case PARSEOP_METHODCALL:
208
209         if (MethodInfo &&
210            (Op->Asl.Node == MethodInfo->Op->Asl.Node))
211         {
212             AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName);
213         }
214         break;
215
216     case PARSEOP_LOCAL0:
217     case PARSEOP_LOCAL1:
218     case PARSEOP_LOCAL2:
219     case PARSEOP_LOCAL3:
220     case PARSEOP_LOCAL4:
221     case PARSEOP_LOCAL5:
222     case PARSEOP_LOCAL6:
223     case PARSEOP_LOCAL7:
224
225         if (!MethodInfo)
226         {
227             /*
228              * Local was used outside a control method, or there was an error
229              * in the method declaration.
230              */
231             AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName);
232             return (AE_ERROR);
233         }
234
235         RegisterNumber = (Op->Asl.AmlOpcode & 0x000F);
236
237         /*
238          * If the local is being used as a target, mark the local
239          * initialized
240          */
241         if (Op->Asl.CompileFlags & NODE_IS_TARGET)
242         {
243             MethodInfo->LocalInitialized[RegisterNumber] = TRUE;
244         }
245
246         /*
247          * Otherwise, this is a reference, check if the local
248          * has been previously initialized.
249          *
250          * The only operator that accepts an uninitialized value is ObjectType()
251          */
252         else if ((!MethodInfo->LocalInitialized[RegisterNumber]) &&
253                  (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
254         {
255             LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30);
256             AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName);
257         }
258         break;
259
260     case PARSEOP_ARG0:
261     case PARSEOP_ARG1:
262     case PARSEOP_ARG2:
263     case PARSEOP_ARG3:
264     case PARSEOP_ARG4:
265     case PARSEOP_ARG5:
266     case PARSEOP_ARG6:
267
268         if (!MethodInfo)
269         {
270             /*
271              * Arg was used outside a control method, or there was an error
272              * in the method declaration.
273              */
274             AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName);
275             return (AE_ERROR);
276         }
277
278         RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8;
279         ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30);
280
281         /*
282          * If the Arg is being used as a target, mark the local
283          * initialized
284          */
285         if (Op->Asl.CompileFlags & NODE_IS_TARGET)
286         {
287             MethodInfo->ArgInitialized[RegisterNumber] = TRUE;
288         }
289
290         /*
291          * Otherwise, this is a reference, check if the Arg
292          * has been previously initialized.
293          *
294          * The only operator that accepts an uninitialized value is ObjectType()
295          */
296         else if ((!MethodInfo->ArgInitialized[RegisterNumber]) &&
297                  (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
298         {
299             AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName);
300         }
301
302         /* Flag this arg if it is not a "real" argument to the method */
303
304         if (RegisterNumber >= MethodInfo->NumArguments)
305         {
306             AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName);
307         }
308         break;
309
310     case PARSEOP_RETURN:
311
312         if (!MethodInfo)
313         {
314             /*
315              * Probably was an error in the method declaration,
316              * no additional error here
317              */
318             ACPI_WARNING ((AE_INFO, "%p, No parent method", Op));
319             return (AE_ERROR);
320         }
321
322         /*
323          * A child indicates a possible return value. A simple Return or
324          * Return() is marked with NODE_IS_NULL_RETURN by the parser so
325          * that it is not counted as a "real" return-with-value, although
326          * the AML code that is actually emitted is Return(0). The AML
327          * definition of Return has a required parameter, so we are
328          * forced to convert a null return to Return(0).
329          */
330         if ((Op->Asl.Child) &&
331             (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) &&
332             (!(Op->Asl.Child->Asl.CompileFlags & NODE_IS_NULL_RETURN)))
333         {
334             MethodInfo->NumReturnWithValue++;
335         }
336         else
337         {
338             MethodInfo->NumReturnNoValue++;
339         }
340         break;
341
342     case PARSEOP_BREAK:
343     case PARSEOP_CONTINUE:
344
345         Next = Op->Asl.Parent;
346         while (Next)
347         {
348             if (Next->Asl.ParseOpcode == PARSEOP_WHILE)
349             {
350                 break;
351             }
352             Next = Next->Asl.Parent;
353         }
354
355         if (!Next)
356         {
357             AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL);
358         }
359         break;
360
361     case PARSEOP_STALL:
362
363         /* We can range check if the argument is an integer */
364
365         if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) &&
366             (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX))
367         {
368             AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL);
369         }
370         break;
371
372     case PARSEOP_DEVICE:
373     case PARSEOP_EVENT:
374     case PARSEOP_MUTEX:
375     case PARSEOP_OPERATIONREGION:
376     case PARSEOP_POWERRESOURCE:
377     case PARSEOP_PROCESSOR:
378     case PARSEOP_THERMALZONE:
379
380         /*
381          * The first operand is a name to be created in the namespace.
382          * Check against the reserved list.
383          */
384         i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg);
385         if (i < ACPI_VALID_RESERVED_NAME_MAX)
386         {
387             AslError (ASL_ERROR, ASL_MSG_RESERVED_USE, Op, Op->Asl.ExternalName);
388         }
389         break;
390
391     case PARSEOP_NAME:
392
393         /* Typecheck any predefined names statically defined with Name() */
394
395         ApCheckForPredefinedObject (Op, Op->Asl.NameSeg);
396
397         /* Special typechecking for _HID */
398
399         if (!ACPI_STRCMP (METHOD_NAME__HID, Op->Asl.NameSeg))
400         {
401             Next = Op->Asl.Child->Asl.Next;
402             AnCheckId (Next, ASL_TYPE_HID);
403         }
404
405         /* Special typechecking for _CID */
406
407         else if (!ACPI_STRCMP (METHOD_NAME__CID, Op->Asl.NameSeg))
408         {
409             Next = Op->Asl.Child->Asl.Next;
410
411             if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
412                 (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE))
413             {
414                 Next = Next->Asl.Child;
415                 while (Next)
416                 {
417                     AnCheckId (Next, ASL_TYPE_CID);
418                     Next = Next->Asl.Next;
419                 }
420             }
421             else
422             {
423                 AnCheckId (Next, ASL_TYPE_CID);
424             }
425         }
426
427         else if (!ACPI_STRCMP (METHOD_NAME__DSD, Op->Asl.NameSeg))
428         {
429             if (!ApFindNameInScope (METHOD_NAME__HID, Op))
430             {
431                 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
432                     "_DSD requires _HID in same scope");
433             }
434         }
435
436         break;
437
438     default:
439
440         break;
441     }
442
443     /* Check for named object creation within a non-serialized method */
444
445     MtCheckNamedObjectInMethod (Op, MethodInfo);
446     return (AE_OK);
447 }
448
449
450 /*******************************************************************************
451  *
452  * FUNCTION:    MtCheckNamedObjectInMethod
453  *
454  * PARAMETERS:  Op                  - Current parser op
455  *              MethodInfo          - Info for method being parsed
456  *
457  * RETURN:      None
458  *
459  * DESCRIPTION: Detect if a non-serialized method is creating a named object,
460  *              which could possibly cause problems if two threads execute
461  *              the method concurrently. Emit a remark in this case.
462  *
463  ******************************************************************************/
464
465 void
466 MtCheckNamedObjectInMethod (
467     ACPI_PARSE_OBJECT       *Op,
468     ASL_METHOD_INFO         *MethodInfo)
469 {
470     const ACPI_OPCODE_INFO  *OpInfo;
471
472
473     /* We don't care about actual method declarations */
474
475     if (Op->Asl.AmlOpcode == AML_METHOD_OP)
476     {
477         return;
478     }
479
480     /* Determine if we are creating a named object */
481
482     OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
483     if (OpInfo->Class == AML_CLASS_NAMED_OBJECT)
484     {
485         /*
486          * If we have a named object created within a non-serialized method,
487          * emit a remark that the method should be serialized.
488          *
489          * Reason: If a thread blocks within the method for any reason, and
490          * another thread enters the method, the method will fail because an
491          * attempt will be made to create the same object twice.
492          */
493         if (MethodInfo && !MethodInfo->ShouldBeSerialized)
494         {
495             AslError (ASL_REMARK, ASL_MSG_SERIALIZED_REQUIRED, MethodInfo->Op,
496                 "due to creation of named objects within");
497
498             /* Emit message only ONCE per method */
499
500             MethodInfo->ShouldBeSerialized = TRUE;
501         }
502     }
503 }
504
505
506 /*******************************************************************************
507  *
508  * FUNCTION:    MtMethodAnalysisWalkEnd
509  *
510  * PARAMETERS:  ASL_WALK_CALLBACK
511  *
512  * RETURN:      Status
513  *
514  * DESCRIPTION: Ascending callback for analysis walk. Complete method
515  *              return analysis.
516  *
517  ******************************************************************************/
518
519 ACPI_STATUS
520 MtMethodAnalysisWalkEnd (
521     ACPI_PARSE_OBJECT       *Op,
522     UINT32                  Level,
523     void                    *Context)
524 {
525     ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
526     ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack;
527
528
529     switch (Op->Asl.ParseOpcode)
530     {
531     case PARSEOP_METHOD:
532     case PARSEOP_RETURN:
533
534         if (!MethodInfo)
535         {
536             printf ("No method info for method! [%s]\n", Op->Asl.Namepath);
537             AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op,
538                 "No method info for this method");
539
540             CmCleanupAndExit ();
541             return (AE_AML_INTERNAL);
542         }
543         break;
544
545     default:
546
547         break;
548     }
549
550     switch (Op->Asl.ParseOpcode)
551     {
552     case PARSEOP_METHOD:
553
554         WalkInfo->MethodStack = MethodInfo->Next;
555
556         /*
557          * Check if there is no return statement at the end of the
558          * method AND we can actually get there -- i.e., the execution
559          * of the method can possibly terminate without a return statement.
560          */
561         if ((!AnLastStatementIsReturn (Op)) &&
562             (!(Op->Asl.CompileFlags & NODE_HAS_NO_EXIT)))
563         {
564             /*
565              * No return statement, and execution can possibly exit
566              * via this path. This is equivalent to Return ()
567              */
568             MethodInfo->NumReturnNoValue++;
569         }
570
571         /*
572          * Check for case where some return statements have a return value
573          * and some do not. Exit without a return statement is a return with
574          * no value
575          */
576         if (MethodInfo->NumReturnNoValue &&
577             MethodInfo->NumReturnWithValue)
578         {
579             AslError (ASL_WARNING, ASL_MSG_RETURN_TYPES, Op,
580                 Op->Asl.ExternalName);
581         }
582
583         /*
584          * If there are any RETURN() statements with no value, or there is a
585          * control path that allows the method to exit without a return value,
586          * we mark the method as a method that does not return a value. This
587          * knowledge can be used to check method invocations that expect a
588          * returned value.
589          */
590         if (MethodInfo->NumReturnNoValue)
591         {
592             if (MethodInfo->NumReturnWithValue)
593             {
594                 Op->Asl.CompileFlags |= NODE_METHOD_SOME_NO_RETVAL;
595             }
596             else
597             {
598                 Op->Asl.CompileFlags |= NODE_METHOD_NO_RETVAL;
599             }
600         }
601
602         /*
603          * Check predefined method names for correct return behavior
604          * and correct number of arguments. Also, some special checks
605          * For GPE and _REG methods.
606          */
607         if (ApCheckForPredefinedMethod (Op, MethodInfo))
608         {
609             /* Special check for two names like _L01 and _E01 in same scope */
610
611             ApCheckForGpeNameConflict (Op);
612
613             /*
614              * Special check for _REG: Must have an operation region definition
615              * within the same scope!
616              */
617             ApCheckRegMethod (Op);
618         }
619
620         ACPI_FREE (MethodInfo);
621         break;
622
623     case PARSEOP_NAME:
624
625          /* Special check for two names like _L01 and _E01 in same scope */
626
627         ApCheckForGpeNameConflict (Op);
628         break;
629
630     case PARSEOP_RETURN:
631
632         /*
633          * If the parent is a predefined method name, attempt to typecheck
634          * the return value. Only static types can be validated.
635          */
636         ApCheckPredefinedReturnValue (Op, MethodInfo);
637
638         /*
639          * The parent block does not "exit" and continue execution -- the
640          * method is terminated here with the Return() statement.
641          */
642         Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT;
643
644         /* Used in the "typing" pass later */
645
646         Op->Asl.ParentMethod = MethodInfo->Op;
647
648         /*
649          * If there is a peer node after the return statement, then this
650          * node is unreachable code -- i.e., it won't be executed because of
651          * the preceding Return() statement.
652          */
653         if (Op->Asl.Next)
654         {
655             AslError (ASL_WARNING, ASL_MSG_UNREACHABLE_CODE, Op->Asl.Next, NULL);
656         }
657         break;
658
659     case PARSEOP_IF:
660
661         if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) &&
662             (Op->Asl.Next) &&
663             (Op->Asl.Next->Asl.ParseOpcode == PARSEOP_ELSE))
664         {
665             /*
666              * This IF has a corresponding ELSE. The IF block has no exit,
667              * (it contains an unconditional Return)
668              * mark the ELSE block to remember this fact.
669              */
670             Op->Asl.Next->Asl.CompileFlags |= NODE_IF_HAS_NO_EXIT;
671         }
672         break;
673
674     case PARSEOP_ELSE:
675
676         if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) &&
677             (Op->Asl.CompileFlags & NODE_IF_HAS_NO_EXIT))
678         {
679             /*
680              * This ELSE block has no exit and the corresponding IF block
681              * has no exit either. Therefore, the parent node has no exit.
682              */
683             Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT;
684         }
685         break;
686
687
688     default:
689
690         if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) &&
691             (Op->Asl.Parent))
692         {
693             /* If this node has no exit, then the parent has no exit either */
694
695             Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT;
696         }
697         break;
698     }
699
700     return (AE_OK);
701 }