aslwalks.c revision 218590
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
70ACPI_STATUS
71AnMethodAnalysisWalkBegin (
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        /* Child indicates a return value */
306
307        if ((Op->Asl.Child) &&
308            (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG))
309        {
310            MethodInfo->NumReturnWithValue++;
311        }
312        else
313        {
314            MethodInfo->NumReturnNoValue++;
315        }
316        break;
317
318
319    case PARSEOP_BREAK:
320    case PARSEOP_CONTINUE:
321
322        Next = Op->Asl.Parent;
323        while (Next)
324        {
325            if (Next->Asl.ParseOpcode == PARSEOP_WHILE)
326            {
327                break;
328            }
329            Next = Next->Asl.Parent;
330        }
331
332        if (!Next)
333        {
334            AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL);
335        }
336        break;
337
338
339    case PARSEOP_STALL:
340
341        /* We can range check if the argument is an integer */
342
343        if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) &&
344            (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX))
345        {
346            AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL);
347        }
348        break;
349
350
351    case PARSEOP_DEVICE:
352    case PARSEOP_EVENT:
353    case PARSEOP_MUTEX:
354    case PARSEOP_OPERATIONREGION:
355    case PARSEOP_POWERRESOURCE:
356    case PARSEOP_PROCESSOR:
357    case PARSEOP_THERMALZONE:
358
359        /*
360         * The first operand is a name to be created in the namespace.
361         * Check against the reserved list.
362         */
363        i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg);
364        if (i < ACPI_VALID_RESERVED_NAME_MAX)
365        {
366            AslError (ASL_ERROR, ASL_MSG_RESERVED_USE, Op, Op->Asl.ExternalName);
367        }
368        break;
369
370
371    case PARSEOP_NAME:
372
373        /* Typecheck any predefined names statically defined with Name() */
374
375        ApCheckForPredefinedObject (Op, Op->Asl.NameSeg);
376
377        /* Special typechecking for _HID */
378
379        if (!ACPI_STRCMP (METHOD_NAME__HID, Op->Asl.NameSeg))
380        {
381            Next = Op->Asl.Child->Asl.Next;
382            AnCheckId (Next, ASL_TYPE_HID);
383        }
384
385        /* Special typechecking for _CID */
386
387        else if (!ACPI_STRCMP (METHOD_NAME__CID, Op->Asl.NameSeg))
388        {
389            Next = Op->Asl.Child->Asl.Next;
390
391            if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
392                (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE))
393            {
394                Next = Next->Asl.Child;
395                while (Next)
396                {
397                    AnCheckId (Next, ASL_TYPE_CID);
398                    Next = Next->Asl.Next;
399                }
400            }
401            else
402            {
403                AnCheckId (Next, ASL_TYPE_CID);
404            }
405        }
406        break;
407
408
409    default:
410        break;
411    }
412
413    return (AE_OK);
414}
415
416
417/*******************************************************************************
418 *
419 * FUNCTION:    AnMethodAnalysisWalkEnd
420 *
421 * PARAMETERS:  ASL_WALK_CALLBACK
422 *
423 * RETURN:      Status
424 *
425 * DESCRIPTION: Ascending callback for analysis walk. Complete method
426 *              return analysis.
427 *
428 ******************************************************************************/
429
430ACPI_STATUS
431AnMethodAnalysisWalkEnd (
432    ACPI_PARSE_OBJECT       *Op,
433    UINT32                  Level,
434    void                    *Context)
435{
436    ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
437    ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack;
438
439
440    switch (Op->Asl.ParseOpcode)
441    {
442    case PARSEOP_METHOD:
443    case PARSEOP_RETURN:
444        if (!MethodInfo)
445        {
446            printf ("No method info for method! [%s]\n", Op->Asl.Namepath);
447            AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op,
448                "No method info for this method");
449
450            CmCleanupAndExit ();
451            return (AE_AML_INTERNAL);
452        }
453        break;
454
455    default:
456        break;
457    }
458
459    switch (Op->Asl.ParseOpcode)
460    {
461    case PARSEOP_METHOD:
462
463        WalkInfo->MethodStack = MethodInfo->Next;
464
465        /*
466         * Check if there is no return statement at the end of the
467         * method AND we can actually get there -- i.e., the execution
468         * of the method can possibly terminate without a return statement.
469         */
470        if ((!AnLastStatementIsReturn (Op)) &&
471            (!(Op->Asl.CompileFlags & NODE_HAS_NO_EXIT)))
472        {
473            /*
474             * No return statement, and execution can possibly exit
475             * via this path. This is equivalent to Return ()
476             */
477            MethodInfo->NumReturnNoValue++;
478        }
479
480        /*
481         * Check for case where some return statements have a return value
482         * and some do not. Exit without a return statement is a return with
483         * no value
484         */
485        if (MethodInfo->NumReturnNoValue &&
486            MethodInfo->NumReturnWithValue)
487        {
488            AslError (ASL_WARNING, ASL_MSG_RETURN_TYPES, Op,
489                Op->Asl.ExternalName);
490        }
491
492        /*
493         * If there are any RETURN() statements with no value, or there is a
494         * control path that allows the method to exit without a return value,
495         * we mark the method as a method that does not return a value. This
496         * knowledge can be used to check method invocations that expect a
497         * returned value.
498         */
499        if (MethodInfo->NumReturnNoValue)
500        {
501            if (MethodInfo->NumReturnWithValue)
502            {
503                Op->Asl.CompileFlags |= NODE_METHOD_SOME_NO_RETVAL;
504            }
505            else
506            {
507                Op->Asl.CompileFlags |= NODE_METHOD_NO_RETVAL;
508            }
509        }
510
511        /*
512         * Check predefined method names for correct return behavior
513         * and correct number of arguments
514         */
515        ApCheckForPredefinedMethod (Op, MethodInfo);
516
517        /* Special check for two names like _L01 and _E01 in same scope */
518
519        ApCheckForGpeNameConflict (Op);
520        ACPI_FREE (MethodInfo);
521        break;
522
523
524    case PARSEOP_NAME:
525
526         /* Special check for two names like _L01 and _E01 in same scope */
527
528        ApCheckForGpeNameConflict (Op);
529        break;
530
531
532    case PARSEOP_RETURN:
533
534        /*
535         * If the parent is a predefined method name, attempt to typecheck
536         * the return value. Only static types can be validated.
537         */
538        ApCheckPredefinedReturnValue (Op, MethodInfo);
539
540        /*
541         * The parent block does not "exit" and continue execution -- the
542         * method is terminated here with the Return() statement.
543         */
544        Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT;
545
546        /* Used in the "typing" pass later */
547
548        Op->Asl.ParentMethod = MethodInfo->Op;
549
550        /*
551         * If there is a peer node after the return statement, then this
552         * node is unreachable code -- i.e., it won't be executed because of
553         * the preceeding Return() statement.
554         */
555        if (Op->Asl.Next)
556        {
557            AslError (ASL_WARNING, ASL_MSG_UNREACHABLE_CODE, Op->Asl.Next, NULL);
558        }
559        break;
560
561
562    case PARSEOP_IF:
563
564        if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) &&
565            (Op->Asl.Next) &&
566            (Op->Asl.Next->Asl.ParseOpcode == PARSEOP_ELSE))
567        {
568            /*
569             * This IF has a corresponding ELSE. The IF block has no exit,
570             * (it contains an unconditional Return)
571             * mark the ELSE block to remember this fact.
572             */
573            Op->Asl.Next->Asl.CompileFlags |= NODE_IF_HAS_NO_EXIT;
574        }
575        break;
576
577
578    case PARSEOP_ELSE:
579
580        if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) &&
581            (Op->Asl.CompileFlags & NODE_IF_HAS_NO_EXIT))
582        {
583            /*
584             * This ELSE block has no exit and the corresponding IF block
585             * has no exit either. Therefore, the parent node has no exit.
586             */
587            Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT;
588        }
589        break;
590
591
592    default:
593
594        if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) &&
595            (Op->Asl.Parent))
596        {
597            /* If this node has no exit, then the parent has no exit either */
598
599            Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT;
600        }
601        break;
602    }
603
604    return (AE_OK);
605}
606
607
608/*******************************************************************************
609 *
610 * FUNCTION:    AnMethodTypingWalkEnd
611 *
612 * PARAMETERS:  ASL_WALK_CALLBACK
613 *
614 * RETURN:      Status
615 *
616 * DESCRIPTION: Ascending callback for typing walk. Complete the method
617 *              return analysis. Check methods for:
618 *              1) Initialized local variables
619 *              2) Valid arguments
620 *              3) Return types
621 *
622 ******************************************************************************/
623
624ACPI_STATUS
625AnMethodTypingWalkEnd (
626    ACPI_PARSE_OBJECT       *Op,
627    UINT32                  Level,
628    void                    *Context)
629{
630    UINT32                  ThisNodeBtype;
631
632
633    switch (Op->Asl.ParseOpcode)
634    {
635    case PARSEOP_METHOD:
636
637        Op->Asl.CompileFlags |= NODE_METHOD_TYPED;
638        break;
639
640    case PARSEOP_RETURN:
641
642        if ((Op->Asl.Child) &&
643            (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG))
644        {
645            ThisNodeBtype = AnGetBtype (Op->Asl.Child);
646
647            if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_METHODCALL) &&
648                (ThisNodeBtype == (ACPI_UINT32_MAX -1)))
649            {
650                /*
651                 * The called method is untyped at this time (typically a
652                 * forward reference).
653                 *
654                 * Check for a recursive method call first.
655                 */
656                if (Op->Asl.ParentMethod != Op->Asl.Child->Asl.Node->Op)
657                {
658                    /* We must type the method here */
659
660                    TrWalkParseTree (Op->Asl.Child->Asl.Node->Op,
661                        ASL_WALK_VISIT_UPWARD, NULL,
662                        AnMethodTypingWalkEnd, NULL);
663
664                    ThisNodeBtype = AnGetBtype (Op->Asl.Child);
665                }
666            }
667
668            /* Returns a value, save the value type */
669
670            if (Op->Asl.ParentMethod)
671            {
672                Op->Asl.ParentMethod->Asl.AcpiBtype |= ThisNodeBtype;
673            }
674        }
675        break;
676
677    default:
678        break;
679    }
680
681    return (AE_OK);
682}
683
684
685/*******************************************************************************
686 *
687 * FUNCTION:    AnOperandTypecheckWalkEnd
688 *
689 * PARAMETERS:  ASL_WALK_CALLBACK
690 *
691 * RETURN:      Status
692 *
693 * DESCRIPTION: Ascending callback for analysis walk. Complete method
694 *              return analysis.
695 *
696 ******************************************************************************/
697
698ACPI_STATUS
699AnOperandTypecheckWalkEnd (
700    ACPI_PARSE_OBJECT       *Op,
701    UINT32                  Level,
702    void                    *Context)
703{
704    const ACPI_OPCODE_INFO  *OpInfo;
705    UINT32                  RuntimeArgTypes;
706    UINT32                  RuntimeArgTypes2;
707    UINT32                  RequiredBtypes;
708    UINT32                  ThisNodeBtype;
709    UINT32                  CommonBtypes;
710    UINT32                  OpcodeClass;
711    ACPI_PARSE_OBJECT       *ArgOp;
712    UINT32                  ArgType;
713
714
715    switch (Op->Asl.AmlOpcode)
716    {
717    case AML_RAW_DATA_BYTE:
718    case AML_RAW_DATA_WORD:
719    case AML_RAW_DATA_DWORD:
720    case AML_RAW_DATA_QWORD:
721    case AML_RAW_DATA_BUFFER:
722    case AML_RAW_DATA_CHAIN:
723    case AML_PACKAGE_LENGTH:
724    case AML_UNASSIGNED_OPCODE:
725    case AML_DEFAULT_ARG_OP:
726
727        /* Ignore the internal (compiler-only) AML opcodes */
728
729        return (AE_OK);
730
731    default:
732        break;
733    }
734
735    OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
736    if (!OpInfo)
737    {
738        return (AE_OK);
739    }
740
741    ArgOp           = Op->Asl.Child;
742    RuntimeArgTypes = OpInfo->RuntimeArgs;
743    OpcodeClass     = OpInfo->Class;
744
745#ifdef ASL_ERROR_NAMED_OBJECT_IN_WHILE
746    /*
747     * Update 11/2008: In practice, we can't perform this check. A simple
748     * analysis is not sufficient. Also, it can cause errors when compiling
749     * disassembled code because of the way Switch operators are implemented
750     * (a While(One) loop with a named temp variable created within.)
751     */
752
753    /*
754     * If we are creating a named object, check if we are within a while loop
755     * by checking if the parent is a WHILE op. This is a simple analysis, but
756     * probably sufficient for many cases.
757     *
758     * Allow Scope(), Buffer(), and Package().
759     */
760    if (((OpcodeClass == AML_CLASS_NAMED_OBJECT) && (Op->Asl.AmlOpcode != AML_SCOPE_OP)) ||
761        ((OpcodeClass == AML_CLASS_CREATE) && (OpInfo->Flags & AML_NSNODE)))
762    {
763        if (Op->Asl.Parent->Asl.AmlOpcode == AML_WHILE_OP)
764        {
765            AslError (ASL_ERROR, ASL_MSG_NAMED_OBJECT_IN_WHILE, Op, NULL);
766        }
767    }
768#endif
769
770    /*
771     * Special case for control opcodes IF/RETURN/WHILE since they
772     * have no runtime arg list (at this time)
773     */
774    switch (Op->Asl.AmlOpcode)
775    {
776    case AML_IF_OP:
777    case AML_WHILE_OP:
778    case AML_RETURN_OP:
779
780        if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL)
781        {
782            /* Check for an internal method */
783
784            if (AnIsInternalMethod (ArgOp))
785            {
786                return (AE_OK);
787            }
788
789            /* The lone arg is a method call, check it */
790
791            RequiredBtypes = AnMapArgTypeToBtype (ARGI_INTEGER);
792            if (Op->Asl.AmlOpcode == AML_RETURN_OP)
793            {
794                RequiredBtypes = 0xFFFFFFFF;
795            }
796
797            ThisNodeBtype = AnGetBtype (ArgOp);
798            if (ThisNodeBtype == ACPI_UINT32_MAX)
799            {
800                return (AE_OK);
801            }
802            AnCheckMethodReturnValue (Op, OpInfo, ArgOp,
803                RequiredBtypes, ThisNodeBtype);
804        }
805        return (AE_OK);
806
807    default:
808        break;
809    }
810
811    /* Ignore the non-executable opcodes */
812
813    if (RuntimeArgTypes == ARGI_INVALID_OPCODE)
814    {
815        return (AE_OK);
816    }
817
818    switch (OpcodeClass)
819    {
820    case AML_CLASS_EXECUTE:
821    case AML_CLASS_CREATE:
822    case AML_CLASS_CONTROL:
823    case AML_CLASS_RETURN_VALUE:
824
825        /* TBD: Change class or fix typechecking for these */
826
827        if ((Op->Asl.AmlOpcode == AML_BUFFER_OP)        ||
828            (Op->Asl.AmlOpcode == AML_PACKAGE_OP)       ||
829            (Op->Asl.AmlOpcode == AML_VAR_PACKAGE_OP))
830        {
831            break;
832        }
833
834        /* Reverse the runtime argument list */
835
836        RuntimeArgTypes2 = 0;
837        while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes)))
838        {
839            RuntimeArgTypes2 <<= ARG_TYPE_WIDTH;
840            RuntimeArgTypes2 |= ArgType;
841            INCREMENT_ARG_LIST (RuntimeArgTypes);
842        }
843
844        while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes2)))
845        {
846            RequiredBtypes = AnMapArgTypeToBtype (ArgType);
847
848            ThisNodeBtype = AnGetBtype (ArgOp);
849            if (ThisNodeBtype == ACPI_UINT32_MAX)
850            {
851                goto NextArgument;
852            }
853
854            /* Examine the arg based on the required type of the arg */
855
856            switch (ArgType)
857            {
858            case ARGI_TARGETREF:
859
860                if (ArgOp->Asl.ParseOpcode == PARSEOP_ZERO)
861                {
862                    /* ZERO is the placeholder for "don't store result" */
863
864                    ThisNodeBtype = RequiredBtypes;
865                    break;
866                }
867
868                if (ArgOp->Asl.ParseOpcode == PARSEOP_INTEGER)
869                {
870                    /*
871                     * This is the case where an original reference to a resource
872                     * descriptor field has been replaced by an (Integer) offset.
873                     * These named fields are supported at compile-time only;
874                     * the names are not passed to the interpreter (via the AML).
875                     */
876                    if ((ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE_FIELD) ||
877                        (ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE))
878                    {
879                        AslError (ASL_ERROR, ASL_MSG_RESOURCE_FIELD, ArgOp, NULL);
880                    }
881                    else
882                    {
883                        AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, NULL);
884                    }
885                    break;
886                }
887
888                if ((ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL) ||
889                    (ArgOp->Asl.ParseOpcode == PARSEOP_DEREFOF))
890                {
891                    break;
892                }
893
894                ThisNodeBtype = RequiredBtypes;
895                break;
896
897
898            case ARGI_REFERENCE:            /* References */
899            case ARGI_INTEGER_REF:
900            case ARGI_OBJECT_REF:
901            case ARGI_DEVICE_REF:
902
903                switch (ArgOp->Asl.ParseOpcode)
904                {
905                case PARSEOP_LOCAL0:
906                case PARSEOP_LOCAL1:
907                case PARSEOP_LOCAL2:
908                case PARSEOP_LOCAL3:
909                case PARSEOP_LOCAL4:
910                case PARSEOP_LOCAL5:
911                case PARSEOP_LOCAL6:
912                case PARSEOP_LOCAL7:
913
914                    /* TBD: implement analysis of current value (type) of the local */
915                    /* For now, just treat any local as a typematch */
916
917                    /*ThisNodeBtype = RequiredBtypes;*/
918                    break;
919
920                case PARSEOP_ARG0:
921                case PARSEOP_ARG1:
922                case PARSEOP_ARG2:
923                case PARSEOP_ARG3:
924                case PARSEOP_ARG4:
925                case PARSEOP_ARG5:
926                case PARSEOP_ARG6:
927
928                    /* Hard to analyze argument types, sow we won't */
929                    /* For now, just treat any arg as a typematch */
930
931                    /* ThisNodeBtype = RequiredBtypes; */
932                    break;
933
934                case PARSEOP_DEBUG:
935                    break;
936
937                case PARSEOP_REFOF:
938                case PARSEOP_INDEX:
939                default:
940                    break;
941
942                }
943                break;
944
945            case ARGI_INTEGER:
946            default:
947                break;
948            }
949
950
951            CommonBtypes = ThisNodeBtype & RequiredBtypes;
952
953            if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL)
954            {
955                if (AnIsInternalMethod (ArgOp))
956                {
957                    return (AE_OK);
958                }
959
960                /* Check a method call for a valid return value */
961
962                AnCheckMethodReturnValue (Op, OpInfo, ArgOp,
963                    RequiredBtypes, ThisNodeBtype);
964            }
965
966            /*
967             * Now check if the actual type(s) match at least one
968             * bit to the required type
969             */
970            else if (!CommonBtypes)
971            {
972                /* No match -- this is a type mismatch error */
973
974                AnFormatBtype (StringBuffer, ThisNodeBtype);
975                AnFormatBtype (StringBuffer2, RequiredBtypes);
976
977                sprintf (MsgBuffer, "[%s] found, %s operator requires [%s]",
978                            StringBuffer, OpInfo->Name, StringBuffer2);
979
980                AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, MsgBuffer);
981            }
982
983        NextArgument:
984            ArgOp = ArgOp->Asl.Next;
985            INCREMENT_ARG_LIST (RuntimeArgTypes2);
986        }
987        break;
988
989    default:
990        break;
991    }
992
993    return (AE_OK);
994}
995
996
997/*******************************************************************************
998 *
999 * FUNCTION:    AnOtherSemanticAnalysisWalkBegin
1000 *
1001 * PARAMETERS:  ASL_WALK_CALLBACK
1002 *
1003 * RETURN:      Status
1004 *
1005 * DESCRIPTION: Descending callback for the analysis walk. Checks for
1006 *              miscellaneous issues in the code.
1007 *
1008 ******************************************************************************/
1009
1010ACPI_STATUS
1011AnOtherSemanticAnalysisWalkBegin (
1012    ACPI_PARSE_OBJECT       *Op,
1013    UINT32                  Level,
1014    void                    *Context)
1015{
1016    ACPI_PARSE_OBJECT       *ArgNode;
1017    ACPI_PARSE_OBJECT       *PrevArgNode = NULL;
1018    const ACPI_OPCODE_INFO  *OpInfo;
1019
1020
1021    OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
1022
1023    /*
1024     * Determine if an execution class operator actually does something by
1025     * checking if it has a target and/or the function return value is used.
1026     * (Target is optional, so a standalone statement can actually do nothing.)
1027     */
1028    if ((OpInfo->Class == AML_CLASS_EXECUTE) &&
1029        (OpInfo->Flags & AML_HAS_RETVAL) &&
1030        (!AnIsResultUsed (Op)))
1031    {
1032        if (OpInfo->Flags & AML_HAS_TARGET)
1033        {
1034            /*
1035             * Find the target node, it is always the last child. If the traget
1036             * is not specified in the ASL, a default node of type Zero was
1037             * created by the parser.
1038             */
1039            ArgNode = Op->Asl.Child;
1040            while (ArgNode->Asl.Next)
1041            {
1042                PrevArgNode = ArgNode;
1043                ArgNode = ArgNode->Asl.Next;
1044            }
1045
1046            /* Divide() is the only weird case, it has two targets */
1047
1048            if (Op->Asl.AmlOpcode == AML_DIVIDE_OP)
1049            {
1050                if ((ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) &&
1051                    (PrevArgNode) &&
1052                    (PrevArgNode->Asl.ParseOpcode == PARSEOP_ZERO))
1053                {
1054                    AslError (ASL_WARNING, ASL_MSG_RESULT_NOT_USED,
1055                        Op, Op->Asl.ExternalName);
1056                }
1057            }
1058            else if (ArgNode->Asl.ParseOpcode == PARSEOP_ZERO)
1059            {
1060                AslError (ASL_WARNING, ASL_MSG_RESULT_NOT_USED,
1061                    Op, Op->Asl.ExternalName);
1062            }
1063        }
1064        else
1065        {
1066            /*
1067             * Has no target and the result is not used. Only a couple opcodes
1068             * can have this combination.
1069             */
1070            switch (Op->Asl.ParseOpcode)
1071            {
1072            case PARSEOP_ACQUIRE:
1073            case PARSEOP_WAIT:
1074            case PARSEOP_LOADTABLE:
1075                break;
1076
1077            default:
1078                AslError (ASL_WARNING, ASL_MSG_RESULT_NOT_USED,
1079                    Op, Op->Asl.ExternalName);
1080                break;
1081            }
1082        }
1083    }
1084
1085
1086    /*
1087     * Semantic checks for individual ASL operators
1088     */
1089    switch (Op->Asl.ParseOpcode)
1090    {
1091    case PARSEOP_ACQUIRE:
1092    case PARSEOP_WAIT:
1093        /*
1094         * Emit a warning if the timeout parameter for these operators is not
1095         * ACPI_WAIT_FOREVER, and the result value from the operator is not
1096         * checked, meaning that a timeout could happen, but the code
1097         * would not know about it.
1098         */
1099
1100        /* First child is the namepath, 2nd child is timeout */
1101
1102        ArgNode = Op->Asl.Child;
1103        ArgNode = ArgNode->Asl.Next;
1104
1105        /*
1106         * Check for the WAIT_FOREVER case - defined by the ACPI spec to be
1107         * 0xFFFF or greater
1108         */
1109        if (((ArgNode->Asl.ParseOpcode == PARSEOP_WORDCONST) ||
1110             (ArgNode->Asl.ParseOpcode == PARSEOP_INTEGER))  &&
1111             (ArgNode->Asl.Value.Integer >= (UINT64) ACPI_WAIT_FOREVER))
1112        {
1113            break;
1114        }
1115
1116        /*
1117         * The operation could timeout. If the return value is not used
1118         * (indicates timeout occurred), issue a warning
1119         */
1120        if (!AnIsResultUsed (Op))
1121        {
1122            AslError (ASL_WARNING, ASL_MSG_TIMEOUT, ArgNode,
1123                Op->Asl.ExternalName);
1124        }
1125        break;
1126
1127    case PARSEOP_CREATEFIELD:
1128        /*
1129         * Check for a zero Length (NumBits) operand. NumBits is the 3rd operand
1130         */
1131        ArgNode = Op->Asl.Child;
1132        ArgNode = ArgNode->Asl.Next;
1133        ArgNode = ArgNode->Asl.Next;
1134
1135        if ((ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) ||
1136           ((ArgNode->Asl.ParseOpcode == PARSEOP_INTEGER) &&
1137            (ArgNode->Asl.Value.Integer == 0)))
1138        {
1139            AslError (ASL_ERROR, ASL_MSG_NON_ZERO, ArgNode, NULL);
1140        }
1141        break;
1142
1143    default:
1144        break;
1145    }
1146
1147    return (AE_OK);
1148}
1149