xref: /freebsd/sys/contrib/dev/acpica/compiler/aslwalks.c (revision 724b4bfdf1306e4f2c451b6d146fe0fe0353b2c8)
1 /******************************************************************************
2  *
3  * Module Name: aslwalks.c - major analytical parse tree walks
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2012, 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 preceding 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     ACPI_NAMESPACE_NODE     *Node;
1036 
1037 
1038     OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
1039 
1040     /*
1041      * Determine if an execution class operator actually does something by
1042      * checking if it has a target and/or the function return value is used.
1043      * (Target is optional, so a standalone statement can actually do nothing.)
1044      */
1045     if ((OpInfo->Class == AML_CLASS_EXECUTE) &&
1046         (OpInfo->Flags & AML_HAS_RETVAL) &&
1047         (!AnIsResultUsed (Op)))
1048     {
1049         if (OpInfo->Flags & AML_HAS_TARGET)
1050         {
1051             /*
1052              * Find the target node, it is always the last child. If the traget
1053              * is not specified in the ASL, a default node of type Zero was
1054              * created by the parser.
1055              */
1056             ArgNode = Op->Asl.Child;
1057             while (ArgNode->Asl.Next)
1058             {
1059                 PrevArgNode = ArgNode;
1060                 ArgNode = ArgNode->Asl.Next;
1061             }
1062 
1063             /* Divide() is the only weird case, it has two targets */
1064 
1065             if (Op->Asl.AmlOpcode == AML_DIVIDE_OP)
1066             {
1067                 if ((ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) &&
1068                     (PrevArgNode) &&
1069                     (PrevArgNode->Asl.ParseOpcode == PARSEOP_ZERO))
1070                 {
1071                     AslError (ASL_WARNING, ASL_MSG_RESULT_NOT_USED,
1072                         Op, Op->Asl.ExternalName);
1073                 }
1074             }
1075             else if (ArgNode->Asl.ParseOpcode == PARSEOP_ZERO)
1076             {
1077                 AslError (ASL_WARNING, ASL_MSG_RESULT_NOT_USED,
1078                     Op, Op->Asl.ExternalName);
1079             }
1080         }
1081         else
1082         {
1083             /*
1084              * Has no target and the result is not used. Only a couple opcodes
1085              * can have this combination.
1086              */
1087             switch (Op->Asl.ParseOpcode)
1088             {
1089             case PARSEOP_ACQUIRE:
1090             case PARSEOP_WAIT:
1091             case PARSEOP_LOADTABLE:
1092                 break;
1093 
1094             default:
1095                 AslError (ASL_WARNING, ASL_MSG_RESULT_NOT_USED,
1096                     Op, Op->Asl.ExternalName);
1097                 break;
1098             }
1099         }
1100     }
1101 
1102 
1103     /*
1104      * Semantic checks for individual ASL operators
1105      */
1106     switch (Op->Asl.ParseOpcode)
1107     {
1108     case PARSEOP_ACQUIRE:
1109     case PARSEOP_WAIT:
1110         /*
1111          * Emit a warning if the timeout parameter for these operators is not
1112          * ACPI_WAIT_FOREVER, and the result value from the operator is not
1113          * checked, meaning that a timeout could happen, but the code
1114          * would not know about it.
1115          */
1116 
1117         /* First child is the namepath, 2nd child is timeout */
1118 
1119         ArgNode = Op->Asl.Child;
1120         ArgNode = ArgNode->Asl.Next;
1121 
1122         /*
1123          * Check for the WAIT_FOREVER case - defined by the ACPI spec to be
1124          * 0xFFFF or greater
1125          */
1126         if (((ArgNode->Asl.ParseOpcode == PARSEOP_WORDCONST) ||
1127              (ArgNode->Asl.ParseOpcode == PARSEOP_INTEGER))  &&
1128              (ArgNode->Asl.Value.Integer >= (UINT64) ACPI_WAIT_FOREVER))
1129         {
1130             break;
1131         }
1132 
1133         /*
1134          * The operation could timeout. If the return value is not used
1135          * (indicates timeout occurred), issue a warning
1136          */
1137         if (!AnIsResultUsed (Op))
1138         {
1139             AslError (ASL_WARNING, ASL_MSG_TIMEOUT, ArgNode,
1140                 Op->Asl.ExternalName);
1141         }
1142         break;
1143 
1144     case PARSEOP_CREATEFIELD:
1145         /*
1146          * Check for a zero Length (NumBits) operand. NumBits is the 3rd operand
1147          */
1148         ArgNode = Op->Asl.Child;
1149         ArgNode = ArgNode->Asl.Next;
1150         ArgNode = ArgNode->Asl.Next;
1151 
1152         if ((ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) ||
1153            ((ArgNode->Asl.ParseOpcode == PARSEOP_INTEGER) &&
1154             (ArgNode->Asl.Value.Integer == 0)))
1155         {
1156             AslError (ASL_ERROR, ASL_MSG_NON_ZERO, ArgNode, NULL);
1157         }
1158         break;
1159 
1160     case PARSEOP_CONNECTION:
1161         /*
1162          * Ensure that the referenced operation region has the correct SPACE_ID.
1163          * From the grammar/parser, we know the parent is a FIELD definition.
1164          */
1165         ArgNode = Op->Asl.Parent;       /* Field definition */
1166         ArgNode = ArgNode->Asl.Child;   /* First child is the OpRegion Name */
1167         Node = ArgNode->Asl.Node;       /* OpRegion namespace node */
1168 
1169         ArgNode = Node->Op;             /* OpRegion definition */
1170         ArgNode = ArgNode->Asl.Child;   /* First child is the OpRegion Name */
1171         ArgNode = ArgNode->Asl.Next;    /* Next peer is the SPACE_ID (what we want) */
1172 
1173         /*
1174          * The Connection() operator is only valid for the following operation
1175          * region SpaceIds: GeneralPurposeIo and GenericSerialBus.
1176          */
1177         if ((ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GPIO) &&
1178             (ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GSBUS))
1179         {
1180             AslError (ASL_ERROR, ASL_MSG_CONNECTION_INVALID, Op, NULL);
1181         }
1182         break;
1183 
1184     case PARSEOP_FIELD:
1185         /*
1186          * Ensure that fields for GeneralPurposeIo and GenericSerialBus
1187          * contain at least one Connection() operator
1188          */
1189         ArgNode = Op->Asl.Child;        /* 1st child is the OpRegion Name */
1190         Node = ArgNode->Asl.Node;       /* OpRegion namespace node */
1191         if (!Node)
1192         {
1193             break;
1194         }
1195 
1196         ArgNode = Node->Op;             /* OpRegion definition */
1197         ArgNode = ArgNode->Asl.Child;   /* First child is the OpRegion Name */
1198         ArgNode = ArgNode->Asl.Next;    /* Next peer is the SPACE_ID (what we want) */
1199 
1200         /* We are only interested in GeneralPurposeIo and GenericSerialBus */
1201 
1202         if ((ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GPIO) &&
1203             (ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GSBUS))
1204         {
1205             break;
1206         }
1207 
1208         ArgNode = Op->Asl.Child;        /* 1st child is the OpRegion Name */
1209         ArgNode = ArgNode->Asl.Next;    /* AccessType */
1210         ArgNode = ArgNode->Asl.Next;    /* LockRule */
1211         ArgNode = ArgNode->Asl.Next;    /* UpdateRule */
1212         ArgNode = ArgNode->Asl.Next;    /* Start of FieldUnitList */
1213 
1214         /* Walk the FieldUnitList */
1215 
1216         while (ArgNode)
1217         {
1218             if (ArgNode->Asl.ParseOpcode == PARSEOP_CONNECTION)
1219             {
1220                 break;
1221             }
1222             else if (ArgNode->Asl.ParseOpcode == PARSEOP_NAMESEG)
1223             {
1224                 AslError (ASL_ERROR, ASL_MSG_CONNECTION_MISSING, ArgNode, NULL);
1225                 break;
1226             }
1227 
1228             ArgNode = ArgNode->Asl.Next;
1229         }
1230         break;
1231 
1232     default:
1233         break;
1234     }
1235 
1236     return (AE_OK);
1237 }
1238