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