]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/contrib/dev/acpica/compiler/aslwalks.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / contrib / dev / acpica / compiler / aslwalks.c
1 /******************************************************************************
2  *
3  * Module Name: aslwalks.c - major analytical parse tree walks
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2011, 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 <contrib/dev/acpica/compiler/aslcompiler.h>
46 #include "aslcompiler.y.h"
47 #include <contrib/dev/acpica/include/acparser.h>
48 #include <contrib/dev/acpica/include/amlcode.h>
49
50
51 #define _COMPONENT          ACPI_COMPILER
52         ACPI_MODULE_NAME    ("aslwalks")
53
54
55 /*******************************************************************************
56  *
57  * FUNCTION:    AnMethodAnalysisWalkBegin
58  *
59  * PARAMETERS:  ASL_WALK_CALLBACK
60  *
61  * RETURN:      Status
62  *
63  * DESCRIPTION: Descending callback for the analysis walk. Check methods for:
64  *              1) Initialized local variables
65  *              2) Valid arguments
66  *              3) Return types
67  *
68  ******************************************************************************/
69
70 ACPI_STATUS
71 AnMethodAnalysisWalkBegin (
72     ACPI_PARSE_OBJECT       *Op,
73     UINT32                  Level,
74     void                    *Context)
75 {
76     ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
77     ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack;
78     ACPI_PARSE_OBJECT       *Next;
79     UINT32                  RegisterNumber;
80     UINT32                  i;
81     char                    LocalName[] = "Local0";
82     char                    ArgName[] = "Arg0";
83     ACPI_PARSE_OBJECT       *ArgNode;
84     ACPI_PARSE_OBJECT       *NextType;
85     ACPI_PARSE_OBJECT       *NextParamType;
86     UINT8                   ActualArgs = 0;
87
88
89     switch (Op->Asl.ParseOpcode)
90     {
91     case PARSEOP_METHOD:
92
93         TotalMethods++;
94
95         /* Create and init method info */
96
97         MethodInfo       = UtLocalCalloc (sizeof (ASL_METHOD_INFO));
98         MethodInfo->Next = WalkInfo->MethodStack;
99         MethodInfo->Op = Op;
100
101         WalkInfo->MethodStack = MethodInfo;
102
103         /* Get the name node, ignored here */
104
105         Next = Op->Asl.Child;
106
107         /* Get the NumArguments node */
108
109         Next = Next->Asl.Next;
110         MethodInfo->NumArguments = (UINT8)
111             (((UINT8) Next->Asl.Value.Integer) & 0x07);
112
113         /* Get the SerializeRule and SyncLevel nodes, ignored here */
114
115         Next = Next->Asl.Next;
116         Next = Next->Asl.Next;
117         ArgNode = Next;
118
119         /* Get the ReturnType node */
120
121         Next = Next->Asl.Next;
122
123         NextType = Next->Asl.Child;
124         while (NextType)
125         {
126             /* Get and map each of the ReturnTypes */
127
128             MethodInfo->ValidReturnTypes |= AnMapObjTypeToBtype (NextType);
129             NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
130             NextType = NextType->Asl.Next;
131         }
132
133         /* Get the ParameterType node */
134
135         Next = Next->Asl.Next;
136
137         NextType = Next->Asl.Child;
138         while (NextType)
139         {
140             if (NextType->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
141             {
142                 NextParamType = NextType->Asl.Child;
143                 while (NextParamType)
144                 {
145                     MethodInfo->ValidArgTypes[ActualArgs] |= AnMapObjTypeToBtype (NextParamType);
146                     NextParamType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
147                     NextParamType = NextParamType->Asl.Next;
148                 }
149             }
150             else
151             {
152                 MethodInfo->ValidArgTypes[ActualArgs] =
153                     AnMapObjTypeToBtype (NextType);
154                 NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
155                 ActualArgs++;
156             }
157
158             NextType = NextType->Asl.Next;
159         }
160
161         if ((MethodInfo->NumArguments) &&
162             (MethodInfo->NumArguments != ActualArgs))
163         {
164             /* error: Param list did not match number of args */
165         }
166
167         /* Allow numarguments == 0 for Function() */
168
169         if ((!MethodInfo->NumArguments) && (ActualArgs))
170         {
171             MethodInfo->NumArguments = ActualArgs;
172             ArgNode->Asl.Value.Integer |= ActualArgs;
173         }
174
175         /*
176          * Actual arguments are initialized at method entry.
177          * All other ArgX "registers" can be used as locals, so we
178          * track their initialization.
179          */
180         for (i = 0; i < MethodInfo->NumArguments; i++)
181         {
182             MethodInfo->ArgInitialized[i] = TRUE;
183         }
184         break;
185
186
187     case PARSEOP_METHODCALL:
188
189         if (MethodInfo &&
190            (Op->Asl.Node == MethodInfo->Op->Asl.Node))
191         {
192             AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName);
193         }
194         break;
195
196
197     case PARSEOP_LOCAL0:
198     case PARSEOP_LOCAL1:
199     case PARSEOP_LOCAL2:
200     case PARSEOP_LOCAL3:
201     case PARSEOP_LOCAL4:
202     case PARSEOP_LOCAL5:
203     case PARSEOP_LOCAL6:
204     case PARSEOP_LOCAL7:
205
206         if (!MethodInfo)
207         {
208             /*
209              * Local was used outside a control method, or there was an error
210              * in the method declaration.
211              */
212             AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName);
213             return (AE_ERROR);
214         }
215
216         RegisterNumber = (Op->Asl.AmlOpcode & 0x000F);
217
218         /*
219          * If the local is being used as a target, mark the local
220          * initialized
221          */
222         if (Op->Asl.CompileFlags & NODE_IS_TARGET)
223         {
224             MethodInfo->LocalInitialized[RegisterNumber] = TRUE;
225         }
226
227         /*
228          * Otherwise, this is a reference, check if the local
229          * has been previously initialized.
230          *
231          * The only operator that accepts an uninitialized value is ObjectType()
232          */
233         else if ((!MethodInfo->LocalInitialized[RegisterNumber]) &&
234                  (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
235         {
236             LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30);
237             AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName);
238         }
239         break;
240
241
242     case PARSEOP_ARG0:
243     case PARSEOP_ARG1:
244     case PARSEOP_ARG2:
245     case PARSEOP_ARG3:
246     case PARSEOP_ARG4:
247     case PARSEOP_ARG5:
248     case PARSEOP_ARG6:
249
250         if (!MethodInfo)
251         {
252             /*
253              * Arg was used outside a control method, or there was an error
254              * in the method declaration.
255              */
256             AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName);
257             return (AE_ERROR);
258         }
259
260         RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8;
261         ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30);
262
263         /*
264          * If the Arg is being used as a target, mark the local
265          * initialized
266          */
267         if (Op->Asl.CompileFlags & NODE_IS_TARGET)
268         {
269             MethodInfo->ArgInitialized[RegisterNumber] = TRUE;
270         }
271
272         /*
273          * Otherwise, this is a reference, check if the Arg
274          * has been previously initialized.
275          *
276          * The only operator that accepts an uninitialized value is ObjectType()
277          */
278         else if ((!MethodInfo->ArgInitialized[RegisterNumber]) &&
279                  (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
280         {
281             AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName);
282         }
283
284         /* Flag this arg if it is not a "real" argument to the method */
285
286         if (RegisterNumber >= MethodInfo->NumArguments)
287         {
288             AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName);
289         }
290         break;
291
292
293     case PARSEOP_RETURN:
294
295         if (!MethodInfo)
296         {
297             /*
298              * Probably was an error in the method declaration,
299              * no additional error here
300              */
301             ACPI_WARNING ((AE_INFO, "%p, No parent method", Op));
302             return (AE_ERROR);
303         }
304
305         /*
306          * A child indicates a possible return value. A simple Return or
307          * Return() is marked with NODE_IS_NULL_RETURN by the parser so
308          * that it is not counted as a "real" return-with-value, although
309          * the AML code that is actually emitted is Return(0). The AML
310          * definition of Return has a required parameter, so we are
311          * forced to convert a null return to Return(0).
312          */
313         if ((Op->Asl.Child) &&
314             (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) &&
315             (!(Op->Asl.Child->Asl.CompileFlags & NODE_IS_NULL_RETURN)))
316         {
317             MethodInfo->NumReturnWithValue++;
318         }
319         else
320         {
321             MethodInfo->NumReturnNoValue++;
322         }
323         break;
324
325
326     case PARSEOP_BREAK:
327     case PARSEOP_CONTINUE:
328
329         Next = Op->Asl.Parent;
330         while (Next)
331         {
332             if (Next->Asl.ParseOpcode == PARSEOP_WHILE)
333             {
334                 break;
335             }
336             Next = Next->Asl.Parent;
337         }
338
339         if (!Next)
340         {
341             AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL);
342         }
343         break;
344
345
346     case PARSEOP_STALL:
347
348         /* We can range check if the argument is an integer */
349
350         if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) &&
351             (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX))
352         {
353             AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL);
354         }
355         break;
356
357
358     case PARSEOP_DEVICE:
359     case PARSEOP_EVENT:
360     case PARSEOP_MUTEX:
361     case PARSEOP_OPERATIONREGION:
362     case PARSEOP_POWERRESOURCE:
363     case PARSEOP_PROCESSOR:
364     case PARSEOP_THERMALZONE:
365
366         /*
367          * The first operand is a name to be created in the namespace.
368          * Check against the reserved list.
369          */
370         i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg);
371         if (i < ACPI_VALID_RESERVED_NAME_MAX)
372         {
373             AslError (ASL_ERROR, ASL_MSG_RESERVED_USE, Op, Op->Asl.ExternalName);
374         }
375         break;
376
377
378     case PARSEOP_NAME:
379
380         /* Typecheck any predefined names statically defined with Name() */
381
382         ApCheckForPredefinedObject (Op, Op->Asl.NameSeg);
383
384         /* Special typechecking for _HID */
385
386         if (!ACPI_STRCMP (METHOD_NAME__HID, Op->Asl.NameSeg))
387         {
388             Next = Op->Asl.Child->Asl.Next;
389             AnCheckId (Next, ASL_TYPE_HID);
390         }
391
392         /* Special typechecking for _CID */
393
394         else if (!ACPI_STRCMP (METHOD_NAME__CID, Op->Asl.NameSeg))
395         {
396             Next = Op->Asl.Child->Asl.Next;
397
398             if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
399                 (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE))
400             {
401                 Next = Next->Asl.Child;
402                 while (Next)
403                 {
404                     AnCheckId (Next, ASL_TYPE_CID);
405                     Next = Next->Asl.Next;
406                 }
407             }
408             else
409             {
410                 AnCheckId (Next, ASL_TYPE_CID);
411             }
412         }
413         break;
414
415
416     default:
417         break;
418     }
419
420     return (AE_OK);
421 }
422
423
424 /*******************************************************************************
425  *
426  * FUNCTION:    AnMethodAnalysisWalkEnd
427  *
428  * PARAMETERS:  ASL_WALK_CALLBACK
429  *
430  * RETURN:      Status
431  *
432  * DESCRIPTION: Ascending callback for analysis walk. Complete method
433  *              return analysis.
434  *
435  ******************************************************************************/
436
437 ACPI_STATUS
438 AnMethodAnalysisWalkEnd (
439     ACPI_PARSE_OBJECT       *Op,
440     UINT32                  Level,
441     void                    *Context)
442 {
443     ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
444     ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack;
445
446
447     switch (Op->Asl.ParseOpcode)
448     {
449     case PARSEOP_METHOD:
450     case PARSEOP_RETURN:
451         if (!MethodInfo)
452         {
453             printf ("No method info for method! [%s]\n", Op->Asl.Namepath);
454             AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op,
455                 "No method info for this method");
456
457             CmCleanupAndExit ();
458             return (AE_AML_INTERNAL);
459         }
460         break;
461
462     default:
463         break;
464     }
465
466     switch (Op->Asl.ParseOpcode)
467     {
468     case PARSEOP_METHOD:
469
470         WalkInfo->MethodStack = MethodInfo->Next;
471
472         /*
473          * Check if there is no return statement at the end of the
474          * method AND we can actually get there -- i.e., the execution
475          * of the method can possibly terminate without a return statement.
476          */
477         if ((!AnLastStatementIsReturn (Op)) &&
478             (!(Op->Asl.CompileFlags & NODE_HAS_NO_EXIT)))
479         {
480             /*
481              * No return statement, and execution can possibly exit
482              * via this path. This is equivalent to Return ()
483              */
484             MethodInfo->NumReturnNoValue++;
485         }
486
487         /*
488          * Check for case where some return statements have a return value
489          * and some do not. Exit without a return statement is a return with
490          * no value
491          */
492         if (MethodInfo->NumReturnNoValue &&
493             MethodInfo->NumReturnWithValue)
494         {
495             AslError (ASL_WARNING, ASL_MSG_RETURN_TYPES, Op,
496                 Op->Asl.ExternalName);
497         }
498
499         /*
500          * If there are any RETURN() statements with no value, or there is a
501          * control path that allows the method to exit without a return value,
502          * we mark the method as a method that does not return a value. This
503          * knowledge can be used to check method invocations that expect a
504          * returned value.
505          */
506         if (MethodInfo->NumReturnNoValue)
507         {
508             if (MethodInfo->NumReturnWithValue)
509             {
510                 Op->Asl.CompileFlags |= NODE_METHOD_SOME_NO_RETVAL;
511             }
512             else
513             {
514                 Op->Asl.CompileFlags |= NODE_METHOD_NO_RETVAL;
515             }
516         }
517
518         /*
519          * Check predefined method names for correct return behavior
520          * and correct number of arguments. Also, some special checks
521          * For GPE and _REG methods.
522          */
523         if (ApCheckForPredefinedMethod (Op, MethodInfo))
524         {
525             /* Special check for two names like _L01 and _E01 in same scope */
526
527             ApCheckForGpeNameConflict (Op);
528
529             /*
530              * Special check for _REG: Must have an operation region definition
531              * within the same scope!
532              */
533             ApCheckRegMethod (Op);
534         }
535
536         ACPI_FREE (MethodInfo);
537         break;
538
539
540     case PARSEOP_NAME:
541
542          /* Special check for two names like _L01 and _E01 in same scope */
543
544         ApCheckForGpeNameConflict (Op);
545         break;
546
547
548     case PARSEOP_RETURN:
549
550         /*
551          * If the parent is a predefined method name, attempt to typecheck
552          * the return value. Only static types can be validated.
553          */
554         ApCheckPredefinedReturnValue (Op, MethodInfo);
555
556         /*
557          * The parent block does not "exit" and continue execution -- the
558          * method is terminated here with the Return() statement.
559          */
560         Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT;
561
562         /* Used in the "typing" pass later */
563
564         Op->Asl.ParentMethod = MethodInfo->Op;
565
566         /*
567          * If there is a peer node after the return statement, then this
568          * node is unreachable code -- i.e., it won't be executed because of
569          * the preceeding Return() statement.
570          */
571         if (Op->Asl.Next)
572         {
573             AslError (ASL_WARNING, ASL_MSG_UNREACHABLE_CODE, Op->Asl.Next, NULL);
574         }
575         break;
576
577
578     case PARSEOP_IF:
579
580         if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) &&
581             (Op->Asl.Next) &&
582             (Op->Asl.Next->Asl.ParseOpcode == PARSEOP_ELSE))
583         {
584             /*
585              * This IF has a corresponding ELSE. The IF block has no exit,
586              * (it contains an unconditional Return)
587              * mark the ELSE block to remember this fact.
588              */
589             Op->Asl.Next->Asl.CompileFlags |= NODE_IF_HAS_NO_EXIT;
590         }
591         break;
592
593
594     case PARSEOP_ELSE:
595
596         if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) &&
597             (Op->Asl.CompileFlags & NODE_IF_HAS_NO_EXIT))
598         {
599             /*
600              * This ELSE block has no exit and the corresponding IF block
601              * has no exit either. Therefore, the parent node has no exit.
602              */
603             Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT;
604         }
605         break;
606
607
608     default:
609
610         if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) &&
611             (Op->Asl.Parent))
612         {
613             /* If this node has no exit, then the parent has no exit either */
614
615             Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT;
616         }
617         break;
618     }
619
620     return (AE_OK);
621 }
622
623
624 /*******************************************************************************
625  *
626  * FUNCTION:    AnMethodTypingWalkEnd
627  *
628  * PARAMETERS:  ASL_WALK_CALLBACK
629  *
630  * RETURN:      Status
631  *
632  * DESCRIPTION: Ascending callback for typing walk. Complete the method
633  *              return analysis. Check methods for:
634  *              1) Initialized local variables
635  *              2) Valid arguments
636  *              3) Return types
637  *
638  ******************************************************************************/
639
640 ACPI_STATUS
641 AnMethodTypingWalkEnd (
642     ACPI_PARSE_OBJECT       *Op,
643     UINT32                  Level,
644     void                    *Context)
645 {
646     UINT32                  ThisNodeBtype;
647
648
649     switch (Op->Asl.ParseOpcode)
650     {
651     case PARSEOP_METHOD:
652
653         Op->Asl.CompileFlags |= NODE_METHOD_TYPED;
654         break;
655
656     case PARSEOP_RETURN:
657
658         if ((Op->Asl.Child) &&
659             (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG))
660         {
661             ThisNodeBtype = AnGetBtype (Op->Asl.Child);
662
663             if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_METHODCALL) &&
664                 (ThisNodeBtype == (ACPI_UINT32_MAX -1)))
665             {
666                 /*
667                  * The called method is untyped at this time (typically a
668                  * forward reference).
669                  *
670                  * Check for a recursive method call first.
671                  */
672                 if (Op->Asl.ParentMethod != Op->Asl.Child->Asl.Node->Op)
673                 {
674                     /* We must type the method here */
675
676                     TrWalkParseTree (Op->Asl.Child->Asl.Node->Op,
677                         ASL_WALK_VISIT_UPWARD, NULL,
678                         AnMethodTypingWalkEnd, NULL);
679
680                     ThisNodeBtype = AnGetBtype (Op->Asl.Child);
681                 }
682             }
683
684             /* Returns a value, save the value type */
685
686             if (Op->Asl.ParentMethod)
687             {
688                 Op->Asl.ParentMethod->Asl.AcpiBtype |= ThisNodeBtype;
689             }
690         }
691         break;
692
693     default:
694         break;
695     }
696
697     return (AE_OK);
698 }
699
700
701 /*******************************************************************************
702  *
703  * FUNCTION:    AnOperandTypecheckWalkEnd
704  *
705  * PARAMETERS:  ASL_WALK_CALLBACK
706  *
707  * RETURN:      Status
708  *
709  * DESCRIPTION: Ascending callback for analysis walk. Complete method
710  *              return analysis.
711  *
712  ******************************************************************************/
713
714 ACPI_STATUS
715 AnOperandTypecheckWalkEnd (
716     ACPI_PARSE_OBJECT       *Op,
717     UINT32                  Level,
718     void                    *Context)
719 {
720     const ACPI_OPCODE_INFO  *OpInfo;
721     UINT32                  RuntimeArgTypes;
722     UINT32                  RuntimeArgTypes2;
723     UINT32                  RequiredBtypes;
724     UINT32                  ThisNodeBtype;
725     UINT32                  CommonBtypes;
726     UINT32                  OpcodeClass;
727     ACPI_PARSE_OBJECT       *ArgOp;
728     UINT32                  ArgType;
729
730
731     switch (Op->Asl.AmlOpcode)
732     {
733     case AML_RAW_DATA_BYTE:
734     case AML_RAW_DATA_WORD:
735     case AML_RAW_DATA_DWORD:
736     case AML_RAW_DATA_QWORD:
737     case AML_RAW_DATA_BUFFER:
738     case AML_RAW_DATA_CHAIN:
739     case AML_PACKAGE_LENGTH:
740     case AML_UNASSIGNED_OPCODE:
741     case AML_DEFAULT_ARG_OP:
742
743         /* Ignore the internal (compiler-only) AML opcodes */
744
745         return (AE_OK);
746
747     default:
748         break;
749     }
750
751     OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
752     if (!OpInfo)
753     {
754         return (AE_OK);
755     }
756
757     ArgOp           = Op->Asl.Child;
758     RuntimeArgTypes = OpInfo->RuntimeArgs;
759     OpcodeClass     = OpInfo->Class;
760
761 #ifdef ASL_ERROR_NAMED_OBJECT_IN_WHILE
762     /*
763      * Update 11/2008: In practice, we can't perform this check. A simple
764      * analysis is not sufficient. Also, it can cause errors when compiling
765      * disassembled code because of the way Switch operators are implemented
766      * (a While(One) loop with a named temp variable created within.)
767      */
768
769     /*
770      * If we are creating a named object, check if we are within a while loop
771      * by checking if the parent is a WHILE op. This is a simple analysis, but
772      * probably sufficient for many cases.
773      *
774      * Allow Scope(), Buffer(), and Package().
775      */
776     if (((OpcodeClass == AML_CLASS_NAMED_OBJECT) && (Op->Asl.AmlOpcode != AML_SCOPE_OP)) ||
777         ((OpcodeClass == AML_CLASS_CREATE) && (OpInfo->Flags & AML_NSNODE)))
778     {
779         if (Op->Asl.Parent->Asl.AmlOpcode == AML_WHILE_OP)
780         {
781             AslError (ASL_ERROR, ASL_MSG_NAMED_OBJECT_IN_WHILE, Op, NULL);
782         }
783     }
784 #endif
785
786     /*
787      * Special case for control opcodes IF/RETURN/WHILE since they
788      * have no runtime arg list (at this time)
789      */
790     switch (Op->Asl.AmlOpcode)
791     {
792     case AML_IF_OP:
793     case AML_WHILE_OP:
794     case AML_RETURN_OP:
795
796         if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL)
797         {
798             /* Check for an internal method */
799
800             if (AnIsInternalMethod (ArgOp))
801             {
802                 return (AE_OK);
803             }
804
805             /* The lone arg is a method call, check it */
806
807             RequiredBtypes = AnMapArgTypeToBtype (ARGI_INTEGER);
808             if (Op->Asl.AmlOpcode == AML_RETURN_OP)
809             {
810                 RequiredBtypes = 0xFFFFFFFF;
811             }
812
813             ThisNodeBtype = AnGetBtype (ArgOp);
814             if (ThisNodeBtype == ACPI_UINT32_MAX)
815             {
816                 return (AE_OK);
817             }
818             AnCheckMethodReturnValue (Op, OpInfo, ArgOp,
819                 RequiredBtypes, ThisNodeBtype);
820         }
821         return (AE_OK);
822
823     default:
824         break;
825     }
826
827     /* Ignore the non-executable opcodes */
828
829     if (RuntimeArgTypes == ARGI_INVALID_OPCODE)
830     {
831         return (AE_OK);
832     }
833
834     switch (OpcodeClass)
835     {
836     case AML_CLASS_EXECUTE:
837     case AML_CLASS_CREATE:
838     case AML_CLASS_CONTROL:
839     case AML_CLASS_RETURN_VALUE:
840
841         /* TBD: Change class or fix typechecking for these */
842
843         if ((Op->Asl.AmlOpcode == AML_BUFFER_OP)        ||
844             (Op->Asl.AmlOpcode == AML_PACKAGE_OP)       ||
845             (Op->Asl.AmlOpcode == AML_VAR_PACKAGE_OP))
846         {
847             break;
848         }
849
850         /* Reverse the runtime argument list */
851
852         RuntimeArgTypes2 = 0;
853         while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes)))
854         {
855             RuntimeArgTypes2 <<= ARG_TYPE_WIDTH;
856             RuntimeArgTypes2 |= ArgType;
857             INCREMENT_ARG_LIST (RuntimeArgTypes);
858         }
859
860         while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes2)))
861         {
862             RequiredBtypes = AnMapArgTypeToBtype (ArgType);
863
864             ThisNodeBtype = AnGetBtype (ArgOp);
865             if (ThisNodeBtype == ACPI_UINT32_MAX)
866             {
867                 goto NextArgument;
868             }
869
870             /* Examine the arg based on the required type of the arg */
871
872             switch (ArgType)
873             {
874             case ARGI_TARGETREF:
875
876                 if (ArgOp->Asl.ParseOpcode == PARSEOP_ZERO)
877                 {
878                     /* ZERO is the placeholder for "don't store result" */
879
880                     ThisNodeBtype = RequiredBtypes;
881                     break;
882                 }
883
884                 if (ArgOp->Asl.ParseOpcode == PARSEOP_INTEGER)
885                 {
886                     /*
887                      * This is the case where an original reference to a resource
888                      * descriptor field has been replaced by an (Integer) offset.
889                      * These named fields are supported at compile-time only;
890                      * the names are not passed to the interpreter (via the AML).
891                      */
892                     if ((ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE_FIELD) ||
893                         (ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE))
894                     {
895                         AslError (ASL_ERROR, ASL_MSG_RESOURCE_FIELD, ArgOp, NULL);
896                     }
897                     else
898                     {
899                         AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, NULL);
900                     }
901                     break;
902                 }
903
904                 if ((ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL) ||
905                     (ArgOp->Asl.ParseOpcode == PARSEOP_DEREFOF))
906                 {
907                     break;
908                 }
909
910                 ThisNodeBtype = RequiredBtypes;
911                 break;
912
913
914             case ARGI_REFERENCE:            /* References */
915             case ARGI_INTEGER_REF:
916             case ARGI_OBJECT_REF:
917             case ARGI_DEVICE_REF:
918
919                 switch (ArgOp->Asl.ParseOpcode)
920                 {
921                 case PARSEOP_LOCAL0:
922                 case PARSEOP_LOCAL1:
923                 case PARSEOP_LOCAL2:
924                 case PARSEOP_LOCAL3:
925                 case PARSEOP_LOCAL4:
926                 case PARSEOP_LOCAL5:
927                 case PARSEOP_LOCAL6:
928                 case PARSEOP_LOCAL7:
929
930                     /* TBD: implement analysis of current value (type) of the local */
931                     /* For now, just treat any local as a typematch */
932
933                     /*ThisNodeBtype = RequiredBtypes;*/
934                     break;
935
936                 case PARSEOP_ARG0:
937                 case PARSEOP_ARG1:
938                 case PARSEOP_ARG2:
939                 case PARSEOP_ARG3:
940                 case PARSEOP_ARG4:
941                 case PARSEOP_ARG5:
942                 case PARSEOP_ARG6:
943
944                     /* Hard to analyze argument types, sow we won't */
945                     /* For now, just treat any arg as a typematch */
946
947                     /* ThisNodeBtype = RequiredBtypes; */
948                     break;
949
950                 case PARSEOP_DEBUG:
951                     break;
952
953                 case PARSEOP_REFOF:
954                 case PARSEOP_INDEX:
955                 default:
956                     break;
957
958                 }
959                 break;
960
961             case ARGI_INTEGER:
962             default:
963                 break;
964             }
965
966
967             CommonBtypes = ThisNodeBtype & RequiredBtypes;
968
969             if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL)
970             {
971                 if (AnIsInternalMethod (ArgOp))
972                 {
973                     return (AE_OK);
974                 }
975
976                 /* Check a method call for a valid return value */
977
978                 AnCheckMethodReturnValue (Op, OpInfo, ArgOp,
979                     RequiredBtypes, ThisNodeBtype);
980             }
981
982             /*
983              * Now check if the actual type(s) match at least one
984              * bit to the required type
985              */
986             else if (!CommonBtypes)
987             {
988                 /* No match -- this is a type mismatch error */
989
990                 AnFormatBtype (StringBuffer, ThisNodeBtype);
991                 AnFormatBtype (StringBuffer2, RequiredBtypes);
992
993                 sprintf (MsgBuffer, "[%s] found, %s operator requires [%s]",
994                             StringBuffer, OpInfo->Name, StringBuffer2);
995
996                 AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, MsgBuffer);
997             }
998
999         NextArgument:
1000             ArgOp = ArgOp->Asl.Next;
1001             INCREMENT_ARG_LIST (RuntimeArgTypes2);
1002         }
1003         break;
1004
1005     default:
1006         break;
1007     }
1008
1009     return (AE_OK);
1010 }
1011
1012
1013 /*******************************************************************************
1014  *
1015  * FUNCTION:    AnOtherSemanticAnalysisWalkBegin
1016  *
1017  * PARAMETERS:  ASL_WALK_CALLBACK
1018  *
1019  * RETURN:      Status
1020  *
1021  * DESCRIPTION: Descending callback for the analysis walk. Checks for
1022  *              miscellaneous issues in the code.
1023  *
1024  ******************************************************************************/
1025
1026 ACPI_STATUS
1027 AnOtherSemanticAnalysisWalkBegin (
1028     ACPI_PARSE_OBJECT       *Op,
1029     UINT32                  Level,
1030     void                    *Context)
1031 {
1032     ACPI_PARSE_OBJECT       *ArgNode;
1033     ACPI_PARSE_OBJECT       *PrevArgNode = NULL;
1034     const ACPI_OPCODE_INFO  *OpInfo;
1035
1036
1037     OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
1038
1039     /*
1040      * Determine if an execution class operator actually does something by
1041      * checking if it has a target and/or the function return value is used.
1042      * (Target is optional, so a standalone statement can actually do nothing.)
1043      */
1044     if ((OpInfo->Class == AML_CLASS_EXECUTE) &&
1045         (OpInfo->Flags & AML_HAS_RETVAL) &&
1046         (!AnIsResultUsed (Op)))
1047     {
1048         if (OpInfo->Flags & AML_HAS_TARGET)
1049         {
1050             /*
1051              * Find the target node, it is always the last child. If the traget
1052              * is not specified in the ASL, a default node of type Zero was
1053              * created by the parser.
1054              */
1055             ArgNode = Op->Asl.Child;
1056             while (ArgNode->Asl.Next)
1057             {
1058                 PrevArgNode = ArgNode;
1059                 ArgNode = ArgNode->Asl.Next;
1060             }
1061
1062             /* Divide() is the only weird case, it has two targets */
1063
1064             if (Op->Asl.AmlOpcode == AML_DIVIDE_OP)
1065             {
1066                 if ((ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) &&
1067                     (PrevArgNode) &&
1068                     (PrevArgNode->Asl.ParseOpcode == PARSEOP_ZERO))
1069                 {
1070                     AslError (ASL_WARNING, ASL_MSG_RESULT_NOT_USED,
1071                         Op, Op->Asl.ExternalName);
1072                 }
1073             }
1074             else if (ArgNode->Asl.ParseOpcode == PARSEOP_ZERO)
1075             {
1076                 AslError (ASL_WARNING, ASL_MSG_RESULT_NOT_USED,
1077                     Op, Op->Asl.ExternalName);
1078             }
1079         }
1080         else
1081         {
1082             /*
1083              * Has no target and the result is not used. Only a couple opcodes
1084              * can have this combination.
1085              */
1086             switch (Op->Asl.ParseOpcode)
1087             {
1088             case PARSEOP_ACQUIRE:
1089             case PARSEOP_WAIT:
1090             case PARSEOP_LOADTABLE:
1091                 break;
1092
1093             default:
1094                 AslError (ASL_WARNING, ASL_MSG_RESULT_NOT_USED,
1095                     Op, Op->Asl.ExternalName);
1096                 break;
1097             }
1098         }
1099     }
1100
1101
1102     /*
1103      * Semantic checks for individual ASL operators
1104      */
1105     switch (Op->Asl.ParseOpcode)
1106     {
1107     case PARSEOP_ACQUIRE:
1108     case PARSEOP_WAIT:
1109         /*
1110          * Emit a warning if the timeout parameter for these operators is not
1111          * ACPI_WAIT_FOREVER, and the result value from the operator is not
1112          * checked, meaning that a timeout could happen, but the code
1113          * would not know about it.
1114          */
1115
1116         /* First child is the namepath, 2nd child is timeout */
1117
1118         ArgNode = Op->Asl.Child;
1119         ArgNode = ArgNode->Asl.Next;
1120
1121         /*
1122          * Check for the WAIT_FOREVER case - defined by the ACPI spec to be
1123          * 0xFFFF or greater
1124          */
1125         if (((ArgNode->Asl.ParseOpcode == PARSEOP_WORDCONST) ||
1126              (ArgNode->Asl.ParseOpcode == PARSEOP_INTEGER))  &&
1127              (ArgNode->Asl.Value.Integer >= (UINT64) ACPI_WAIT_FOREVER))
1128         {
1129             break;
1130         }
1131
1132         /*
1133          * The operation could timeout. If the return value is not used
1134          * (indicates timeout occurred), issue a warning
1135          */
1136         if (!AnIsResultUsed (Op))
1137         {
1138             AslError (ASL_WARNING, ASL_MSG_TIMEOUT, ArgNode,
1139                 Op->Asl.ExternalName);
1140         }
1141         break;
1142
1143     case PARSEOP_CREATEFIELD:
1144         /*
1145          * Check for a zero Length (NumBits) operand. NumBits is the 3rd operand
1146          */
1147         ArgNode = Op->Asl.Child;
1148         ArgNode = ArgNode->Asl.Next;
1149         ArgNode = ArgNode->Asl.Next;
1150
1151         if ((ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) ||
1152            ((ArgNode->Asl.ParseOpcode == PARSEOP_INTEGER) &&
1153             (ArgNode->Asl.Value.Integer == 0)))
1154         {
1155             AslError (ASL_ERROR, ASL_MSG_NON_ZERO, ArgNode, NULL);
1156         }
1157         break;
1158
1159     default:
1160         break;
1161     }
1162
1163     return (AE_OK);
1164 }