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