aslwalks.c revision 256281
1/******************************************************************************
2 *
3 * Module Name: aslwalks.c - Miscellaneous analytical parse tree walks
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2013, 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:    AnMethodTypingWalkEnd
58 *
59 * PARAMETERS:  ASL_WALK_CALLBACK
60 *
61 * RETURN:      Status
62 *
63 * DESCRIPTION: Ascending callback for typing walk. Complete the method
64 *              return analysis. Check methods for:
65 *              1) Initialized local variables
66 *              2) Valid arguments
67 *              3) Return types
68 *
69 ******************************************************************************/
70
71ACPI_STATUS
72AnMethodTypingWalkEnd (
73    ACPI_PARSE_OBJECT       *Op,
74    UINT32                  Level,
75    void                    *Context)
76{
77    UINT32                  ThisNodeBtype;
78
79
80    switch (Op->Asl.ParseOpcode)
81    {
82    case PARSEOP_METHOD:
83
84        Op->Asl.CompileFlags |= NODE_METHOD_TYPED;
85        break;
86
87    case PARSEOP_RETURN:
88
89        if ((Op->Asl.Child) &&
90            (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG))
91        {
92            ThisNodeBtype = AnGetBtype (Op->Asl.Child);
93
94            if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_METHODCALL) &&
95                (ThisNodeBtype == (ACPI_UINT32_MAX -1)))
96            {
97                /*
98                 * The called method is untyped at this time (typically a
99                 * forward reference).
100                 *
101                 * Check for a recursive method call first.
102                 */
103                if (Op->Asl.ParentMethod != Op->Asl.Child->Asl.Node->Op)
104                {
105                    /* We must type the method here */
106
107                    TrWalkParseTree (Op->Asl.Child->Asl.Node->Op,
108                        ASL_WALK_VISIT_UPWARD, NULL,
109                        AnMethodTypingWalkEnd, NULL);
110
111                    ThisNodeBtype = AnGetBtype (Op->Asl.Child);
112                }
113            }
114
115            /* Returns a value, save the value type */
116
117            if (Op->Asl.ParentMethod)
118            {
119                Op->Asl.ParentMethod->Asl.AcpiBtype |= ThisNodeBtype;
120            }
121        }
122        break;
123
124    default:
125
126        break;
127    }
128
129    return (AE_OK);
130}
131
132
133/*******************************************************************************
134 *
135 * FUNCTION:    AnOperandTypecheckWalkEnd
136 *
137 * PARAMETERS:  ASL_WALK_CALLBACK
138 *
139 * RETURN:      Status
140 *
141 * DESCRIPTION: Ascending callback for analysis walk. Complete method
142 *              return analysis.
143 *
144 ******************************************************************************/
145
146ACPI_STATUS
147AnOperandTypecheckWalkEnd (
148    ACPI_PARSE_OBJECT       *Op,
149    UINT32                  Level,
150    void                    *Context)
151{
152    const ACPI_OPCODE_INFO  *OpInfo;
153    UINT32                  RuntimeArgTypes;
154    UINT32                  RuntimeArgTypes2;
155    UINT32                  RequiredBtypes;
156    UINT32                  ThisNodeBtype;
157    UINT32                  CommonBtypes;
158    UINT32                  OpcodeClass;
159    ACPI_PARSE_OBJECT       *ArgOp;
160    UINT32                  ArgType;
161
162
163    switch (Op->Asl.AmlOpcode)
164    {
165    case AML_RAW_DATA_BYTE:
166    case AML_RAW_DATA_WORD:
167    case AML_RAW_DATA_DWORD:
168    case AML_RAW_DATA_QWORD:
169    case AML_RAW_DATA_BUFFER:
170    case AML_RAW_DATA_CHAIN:
171    case AML_PACKAGE_LENGTH:
172    case AML_UNASSIGNED_OPCODE:
173    case AML_DEFAULT_ARG_OP:
174
175        /* Ignore the internal (compiler-only) AML opcodes */
176
177        return (AE_OK);
178
179    default:
180
181        break;
182    }
183
184    OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
185    if (!OpInfo)
186    {
187        return (AE_OK);
188    }
189
190    ArgOp           = Op->Asl.Child;
191    RuntimeArgTypes = OpInfo->RuntimeArgs;
192    OpcodeClass     = OpInfo->Class;
193
194#ifdef ASL_ERROR_NAMED_OBJECT_IN_WHILE
195    /*
196     * Update 11/2008: In practice, we can't perform this check. A simple
197     * analysis is not sufficient. Also, it can cause errors when compiling
198     * disassembled code because of the way Switch operators are implemented
199     * (a While(One) loop with a named temp variable created within.)
200     */
201
202    /*
203     * If we are creating a named object, check if we are within a while loop
204     * by checking if the parent is a WHILE op. This is a simple analysis, but
205     * probably sufficient for many cases.
206     *
207     * Allow Scope(), Buffer(), and Package().
208     */
209    if (((OpcodeClass == AML_CLASS_NAMED_OBJECT) && (Op->Asl.AmlOpcode != AML_SCOPE_OP)) ||
210        ((OpcodeClass == AML_CLASS_CREATE) && (OpInfo->Flags & AML_NSNODE)))
211    {
212        if (Op->Asl.Parent->Asl.AmlOpcode == AML_WHILE_OP)
213        {
214            AslError (ASL_ERROR, ASL_MSG_NAMED_OBJECT_IN_WHILE, Op, NULL);
215        }
216    }
217#endif
218
219    /*
220     * Special case for control opcodes IF/RETURN/WHILE since they
221     * have no runtime arg list (at this time)
222     */
223    switch (Op->Asl.AmlOpcode)
224    {
225    case AML_IF_OP:
226    case AML_WHILE_OP:
227    case AML_RETURN_OP:
228
229        if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL)
230        {
231            /* Check for an internal method */
232
233            if (AnIsInternalMethod (ArgOp))
234            {
235                return (AE_OK);
236            }
237
238            /* The lone arg is a method call, check it */
239
240            RequiredBtypes = AnMapArgTypeToBtype (ARGI_INTEGER);
241            if (Op->Asl.AmlOpcode == AML_RETURN_OP)
242            {
243                RequiredBtypes = 0xFFFFFFFF;
244            }
245
246            ThisNodeBtype = AnGetBtype (ArgOp);
247            if (ThisNodeBtype == ACPI_UINT32_MAX)
248            {
249                return (AE_OK);
250            }
251            AnCheckMethodReturnValue (Op, OpInfo, ArgOp,
252                RequiredBtypes, ThisNodeBtype);
253        }
254        return (AE_OK);
255
256    default:
257
258        break;
259    }
260
261    /* Ignore the non-executable opcodes */
262
263    if (RuntimeArgTypes == ARGI_INVALID_OPCODE)
264    {
265        return (AE_OK);
266    }
267
268    switch (OpcodeClass)
269    {
270    case AML_CLASS_EXECUTE:
271    case AML_CLASS_CREATE:
272    case AML_CLASS_CONTROL:
273    case AML_CLASS_RETURN_VALUE:
274
275        /* TBD: Change class or fix typechecking for these */
276
277        if ((Op->Asl.AmlOpcode == AML_BUFFER_OP)        ||
278            (Op->Asl.AmlOpcode == AML_PACKAGE_OP)       ||
279            (Op->Asl.AmlOpcode == AML_VAR_PACKAGE_OP))
280        {
281            break;
282        }
283
284        /* Reverse the runtime argument list */
285
286        RuntimeArgTypes2 = 0;
287        while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes)))
288        {
289            RuntimeArgTypes2 <<= ARG_TYPE_WIDTH;
290            RuntimeArgTypes2 |= ArgType;
291            INCREMENT_ARG_LIST (RuntimeArgTypes);
292        }
293
294        while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes2)))
295        {
296            RequiredBtypes = AnMapArgTypeToBtype (ArgType);
297
298            ThisNodeBtype = AnGetBtype (ArgOp);
299            if (ThisNodeBtype == ACPI_UINT32_MAX)
300            {
301                goto NextArgument;
302            }
303
304            /* Examine the arg based on the required type of the arg */
305
306            switch (ArgType)
307            {
308            case ARGI_TARGETREF:
309
310                if (ArgOp->Asl.ParseOpcode == PARSEOP_ZERO)
311                {
312                    /* ZERO is the placeholder for "don't store result" */
313
314                    ThisNodeBtype = RequiredBtypes;
315                    break;
316                }
317
318                if (ArgOp->Asl.ParseOpcode == PARSEOP_INTEGER)
319                {
320                    /*
321                     * This is the case where an original reference to a resource
322                     * descriptor field has been replaced by an (Integer) offset.
323                     * These named fields are supported at compile-time only;
324                     * the names are not passed to the interpreter (via the AML).
325                     */
326                    if ((ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE_FIELD) ||
327                        (ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE))
328                    {
329                        AslError (ASL_ERROR, ASL_MSG_RESOURCE_FIELD, ArgOp, NULL);
330                    }
331                    else
332                    {
333                        AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, NULL);
334                    }
335                    break;
336                }
337
338                if ((ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL) ||
339                    (ArgOp->Asl.ParseOpcode == PARSEOP_DEREFOF))
340                {
341                    break;
342                }
343
344                ThisNodeBtype = RequiredBtypes;
345                break;
346
347
348            case ARGI_REFERENCE:            /* References */
349            case ARGI_INTEGER_REF:
350            case ARGI_OBJECT_REF:
351            case ARGI_DEVICE_REF:
352
353                switch (ArgOp->Asl.ParseOpcode)
354                {
355                case PARSEOP_LOCAL0:
356                case PARSEOP_LOCAL1:
357                case PARSEOP_LOCAL2:
358                case PARSEOP_LOCAL3:
359                case PARSEOP_LOCAL4:
360                case PARSEOP_LOCAL5:
361                case PARSEOP_LOCAL6:
362                case PARSEOP_LOCAL7:
363
364                    /* TBD: implement analysis of current value (type) of the local */
365                    /* For now, just treat any local as a typematch */
366
367                    /*ThisNodeBtype = RequiredBtypes;*/
368                    break;
369
370                case PARSEOP_ARG0:
371                case PARSEOP_ARG1:
372                case PARSEOP_ARG2:
373                case PARSEOP_ARG3:
374                case PARSEOP_ARG4:
375                case PARSEOP_ARG5:
376                case PARSEOP_ARG6:
377
378                    /* Hard to analyze argument types, sow we won't */
379                    /* For now, just treat any arg as a typematch */
380
381                    /* ThisNodeBtype = RequiredBtypes; */
382                    break;
383
384                case PARSEOP_DEBUG:
385
386                    break;
387
388                case PARSEOP_REFOF:
389                case PARSEOP_INDEX:
390                default:
391
392                    break;
393
394                }
395                break;
396
397            case ARGI_INTEGER:
398            default:
399
400                break;
401            }
402
403
404            CommonBtypes = ThisNodeBtype & RequiredBtypes;
405
406            if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL)
407            {
408                if (AnIsInternalMethod (ArgOp))
409                {
410                    return (AE_OK);
411                }
412
413                /* Check a method call for a valid return value */
414
415                AnCheckMethodReturnValue (Op, OpInfo, ArgOp,
416                    RequiredBtypes, ThisNodeBtype);
417            }
418
419            /*
420             * Now check if the actual type(s) match at least one
421             * bit to the required type
422             */
423            else if (!CommonBtypes)
424            {
425                /* No match -- this is a type mismatch error */
426
427                AnFormatBtype (StringBuffer, ThisNodeBtype);
428                AnFormatBtype (StringBuffer2, RequiredBtypes);
429
430                sprintf (MsgBuffer, "[%s] found, %s operator requires [%s]",
431                            StringBuffer, OpInfo->Name, StringBuffer2);
432
433                AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, MsgBuffer);
434            }
435
436        NextArgument:
437            ArgOp = ArgOp->Asl.Next;
438            INCREMENT_ARG_LIST (RuntimeArgTypes2);
439        }
440        break;
441
442    default:
443
444        break;
445    }
446
447    return (AE_OK);
448}
449
450
451/*******************************************************************************
452 *
453 * FUNCTION:    AnOtherSemanticAnalysisWalkBegin
454 *
455 * PARAMETERS:  ASL_WALK_CALLBACK
456 *
457 * RETURN:      Status
458 *
459 * DESCRIPTION: Descending callback for the analysis walk. Checks for
460 *              miscellaneous issues in the code.
461 *
462 ******************************************************************************/
463
464ACPI_STATUS
465AnOtherSemanticAnalysisWalkBegin (
466    ACPI_PARSE_OBJECT       *Op,
467    UINT32                  Level,
468    void                    *Context)
469{
470    ACPI_PARSE_OBJECT       *ArgNode;
471    ACPI_PARSE_OBJECT       *PrevArgNode = NULL;
472    const ACPI_OPCODE_INFO  *OpInfo;
473    ACPI_NAMESPACE_NODE     *Node;
474
475
476    OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
477
478    /*
479     * Determine if an execution class operator actually does something by
480     * checking if it has a target and/or the function return value is used.
481     * (Target is optional, so a standalone statement can actually do nothing.)
482     */
483    if ((OpInfo->Class == AML_CLASS_EXECUTE) &&
484        (OpInfo->Flags & AML_HAS_RETVAL) &&
485        (!AnIsResultUsed (Op)))
486    {
487        if (OpInfo->Flags & AML_HAS_TARGET)
488        {
489            /*
490             * Find the target node, it is always the last child. If the traget
491             * is not specified in the ASL, a default node of type Zero was
492             * created by the parser.
493             */
494            ArgNode = Op->Asl.Child;
495            while (ArgNode->Asl.Next)
496            {
497                PrevArgNode = ArgNode;
498                ArgNode = ArgNode->Asl.Next;
499            }
500
501            /* Divide() is the only weird case, it has two targets */
502
503            if (Op->Asl.AmlOpcode == AML_DIVIDE_OP)
504            {
505                if ((ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) &&
506                    (PrevArgNode) &&
507                    (PrevArgNode->Asl.ParseOpcode == PARSEOP_ZERO))
508                {
509                    AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED,
510                        Op, Op->Asl.ExternalName);
511                }
512            }
513            else if (ArgNode->Asl.ParseOpcode == PARSEOP_ZERO)
514            {
515                AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED,
516                    Op, Op->Asl.ExternalName);
517            }
518        }
519        else
520        {
521            /*
522             * Has no target and the result is not used. Only a couple opcodes
523             * can have this combination.
524             */
525            switch (Op->Asl.ParseOpcode)
526            {
527            case PARSEOP_ACQUIRE:
528            case PARSEOP_WAIT:
529            case PARSEOP_LOADTABLE:
530
531                break;
532
533            default:
534
535                AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED,
536                    Op, Op->Asl.ExternalName);
537                break;
538            }
539        }
540    }
541
542
543    /*
544     * Semantic checks for individual ASL operators
545     */
546    switch (Op->Asl.ParseOpcode)
547    {
548    case PARSEOP_ACQUIRE:
549    case PARSEOP_WAIT:
550        /*
551         * Emit a warning if the timeout parameter for these operators is not
552         * ACPI_WAIT_FOREVER, and the result value from the operator is not
553         * checked, meaning that a timeout could happen, but the code
554         * would not know about it.
555         */
556
557        /* First child is the namepath, 2nd child is timeout */
558
559        ArgNode = Op->Asl.Child;
560        ArgNode = ArgNode->Asl.Next;
561
562        /*
563         * Check for the WAIT_FOREVER case - defined by the ACPI spec to be
564         * 0xFFFF or greater
565         */
566        if (((ArgNode->Asl.ParseOpcode == PARSEOP_WORDCONST) ||
567             (ArgNode->Asl.ParseOpcode == PARSEOP_INTEGER))  &&
568             (ArgNode->Asl.Value.Integer >= (UINT64) ACPI_WAIT_FOREVER))
569        {
570            break;
571        }
572
573        /*
574         * The operation could timeout. If the return value is not used
575         * (indicates timeout occurred), issue a warning
576         */
577        if (!AnIsResultUsed (Op))
578        {
579            AslError (ASL_WARNING, ASL_MSG_TIMEOUT, ArgNode,
580                Op->Asl.ExternalName);
581        }
582        break;
583
584    case PARSEOP_CREATEFIELD:
585        /*
586         * Check for a zero Length (NumBits) operand. NumBits is the 3rd operand
587         */
588        ArgNode = Op->Asl.Child;
589        ArgNode = ArgNode->Asl.Next;
590        ArgNode = ArgNode->Asl.Next;
591
592        if ((ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) ||
593           ((ArgNode->Asl.ParseOpcode == PARSEOP_INTEGER) &&
594            (ArgNode->Asl.Value.Integer == 0)))
595        {
596            AslError (ASL_ERROR, ASL_MSG_NON_ZERO, ArgNode, NULL);
597        }
598        break;
599
600    case PARSEOP_CONNECTION:
601        /*
602         * Ensure that the referenced operation region has the correct SPACE_ID.
603         * From the grammar/parser, we know the parent is a FIELD definition.
604         */
605        ArgNode = Op->Asl.Parent;       /* Field definition */
606        ArgNode = ArgNode->Asl.Child;   /* First child is the OpRegion Name */
607        Node = ArgNode->Asl.Node;       /* OpRegion namespace node */
608
609        ArgNode = Node->Op;             /* OpRegion definition */
610        ArgNode = ArgNode->Asl.Child;   /* First child is the OpRegion Name */
611        ArgNode = ArgNode->Asl.Next;    /* Next peer is the SPACE_ID (what we want) */
612
613        /*
614         * The Connection() operator is only valid for the following operation
615         * region SpaceIds: GeneralPurposeIo and GenericSerialBus.
616         */
617        if ((ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GPIO) &&
618            (ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GSBUS))
619        {
620            AslError (ASL_ERROR, ASL_MSG_CONNECTION_INVALID, Op, NULL);
621        }
622        break;
623
624    case PARSEOP_FIELD:
625        /*
626         * Ensure that fields for GeneralPurposeIo and GenericSerialBus
627         * contain at least one Connection() operator
628         */
629        ArgNode = Op->Asl.Child;        /* 1st child is the OpRegion Name */
630        Node = ArgNode->Asl.Node;       /* OpRegion namespace node */
631        if (!Node)
632        {
633            break;
634        }
635
636        ArgNode = Node->Op;             /* OpRegion definition */
637        ArgNode = ArgNode->Asl.Child;   /* First child is the OpRegion Name */
638        ArgNode = ArgNode->Asl.Next;    /* Next peer is the SPACE_ID (what we want) */
639
640        /* We are only interested in GeneralPurposeIo and GenericSerialBus */
641
642        if ((ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GPIO) &&
643            (ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GSBUS))
644        {
645            break;
646        }
647
648        ArgNode = Op->Asl.Child;        /* 1st child is the OpRegion Name */
649        ArgNode = ArgNode->Asl.Next;    /* AccessType */
650        ArgNode = ArgNode->Asl.Next;    /* LockRule */
651        ArgNode = ArgNode->Asl.Next;    /* UpdateRule */
652        ArgNode = ArgNode->Asl.Next;    /* Start of FieldUnitList */
653
654        /* Walk the FieldUnitList */
655
656        while (ArgNode)
657        {
658            if (ArgNode->Asl.ParseOpcode == PARSEOP_CONNECTION)
659            {
660                break;
661            }
662            else if (ArgNode->Asl.ParseOpcode == PARSEOP_NAMESEG)
663            {
664                AslError (ASL_ERROR, ASL_MSG_CONNECTION_MISSING, ArgNode, NULL);
665                break;
666            }
667
668            ArgNode = ArgNode->Asl.Next;
669        }
670        break;
671
672    default:
673
674        break;
675    }
676
677    return (AE_OK);
678}
679