aslwalks.c revision 281075
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    default:
256
257        break;
258    }
259
260    /* Ignore the non-executable opcodes */
261
262    if (RuntimeArgTypes == ARGI_INVALID_OPCODE)
263    {
264        return (AE_OK);
265    }
266
267    switch (OpcodeClass)
268    {
269    case AML_CLASS_EXECUTE:
270    case AML_CLASS_CREATE:
271    case AML_CLASS_CONTROL:
272    case AML_CLASS_RETURN_VALUE:
273
274        /* TBD: Change class or fix typechecking for these */
275
276        if ((Op->Asl.AmlOpcode == AML_BUFFER_OP)        ||
277            (Op->Asl.AmlOpcode == AML_PACKAGE_OP)       ||
278            (Op->Asl.AmlOpcode == AML_VAR_PACKAGE_OP))
279        {
280            break;
281        }
282
283        /* Reverse the runtime argument list */
284
285        RuntimeArgTypes2 = 0;
286        while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes)))
287        {
288            RuntimeArgTypes2 <<= ARG_TYPE_WIDTH;
289            RuntimeArgTypes2 |= ArgType;
290            INCREMENT_ARG_LIST (RuntimeArgTypes);
291        }
292
293        while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes2)))
294        {
295            RequiredBtypes = AnMapArgTypeToBtype (ArgType);
296
297            if (!ArgOp)
298            {
299                AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op,
300                    "Null ArgOp in argument loop");
301                AslAbort ();
302            }
303
304            ThisNodeBtype = AnGetBtype (ArgOp);
305            if (ThisNodeBtype == ACPI_UINT32_MAX)
306            {
307                goto NextArgument;
308            }
309
310            /* Examine the arg based on the required type of the arg */
311
312            switch (ArgType)
313            {
314            case ARGI_TARGETREF:
315
316                if (ArgOp->Asl.ParseOpcode == PARSEOP_ZERO)
317                {
318                    /* ZERO is the placeholder for "don't store result" */
319
320                    ThisNodeBtype = RequiredBtypes;
321                    break;
322                }
323
324                if (ArgOp->Asl.ParseOpcode == PARSEOP_INTEGER)
325                {
326                    /*
327                     * This is the case where an original reference to a resource
328                     * descriptor field has been replaced by an (Integer) offset.
329                     * These named fields are supported at compile-time only;
330                     * the names are not passed to the interpreter (via the AML).
331                     */
332                    if ((ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE_FIELD) ||
333                        (ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE))
334                    {
335                        AslError (ASL_ERROR, ASL_MSG_RESOURCE_FIELD, ArgOp, NULL);
336                    }
337                    else
338                    {
339                        AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, NULL);
340                    }
341                    break;
342                }
343
344                if ((ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL) ||
345                    (ArgOp->Asl.ParseOpcode == PARSEOP_DEREFOF))
346                {
347                    break;
348                }
349
350                ThisNodeBtype = RequiredBtypes;
351                break;
352
353
354            case ARGI_REFERENCE:            /* References */
355            case ARGI_INTEGER_REF:
356            case ARGI_OBJECT_REF:
357            case ARGI_DEVICE_REF:
358
359                switch (ArgOp->Asl.ParseOpcode)
360                {
361                case PARSEOP_LOCAL0:
362                case PARSEOP_LOCAL1:
363                case PARSEOP_LOCAL2:
364                case PARSEOP_LOCAL3:
365                case PARSEOP_LOCAL4:
366                case PARSEOP_LOCAL5:
367                case PARSEOP_LOCAL6:
368                case PARSEOP_LOCAL7:
369
370                    /* TBD: implement analysis of current value (type) of the local */
371                    /* For now, just treat any local as a typematch */
372
373                    /*ThisNodeBtype = RequiredBtypes;*/
374                    break;
375
376                case PARSEOP_ARG0:
377                case PARSEOP_ARG1:
378                case PARSEOP_ARG2:
379                case PARSEOP_ARG3:
380                case PARSEOP_ARG4:
381                case PARSEOP_ARG5:
382                case PARSEOP_ARG6:
383
384                    /* Hard to analyze argument types, sow we won't */
385                    /* For now, just treat any arg as a typematch */
386
387                    /* ThisNodeBtype = RequiredBtypes; */
388                    break;
389
390                case PARSEOP_DEBUG:
391
392                    break;
393
394                case PARSEOP_REFOF:
395                case PARSEOP_INDEX:
396                default:
397
398                    break;
399
400                }
401                break;
402
403            case ARGI_INTEGER:
404            default:
405
406                break;
407            }
408
409
410            CommonBtypes = ThisNodeBtype & RequiredBtypes;
411
412            if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL)
413            {
414                if (AnIsInternalMethod (ArgOp))
415                {
416                    return (AE_OK);
417                }
418
419                /* Check a method call for a valid return value */
420
421                AnCheckMethodReturnValue (Op, OpInfo, ArgOp,
422                    RequiredBtypes, ThisNodeBtype);
423            }
424
425            /*
426             * Now check if the actual type(s) match at least one
427             * bit to the required type
428             */
429            else if (!CommonBtypes)
430            {
431                /* No match -- this is a type mismatch error */
432
433                AnFormatBtype (StringBuffer, ThisNodeBtype);
434                AnFormatBtype (StringBuffer2, RequiredBtypes);
435
436                sprintf (MsgBuffer, "[%s] found, %s operator requires [%s]",
437                            StringBuffer, OpInfo->Name, StringBuffer2);
438
439                AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, MsgBuffer);
440            }
441
442        NextArgument:
443            ArgOp = ArgOp->Asl.Next;
444            INCREMENT_ARG_LIST (RuntimeArgTypes2);
445        }
446        break;
447
448    default:
449
450        break;
451    }
452
453    return (AE_OK);
454}
455
456
457/*******************************************************************************
458 *
459 * FUNCTION:    AnOtherSemanticAnalysisWalkBegin
460 *
461 * PARAMETERS:  ASL_WALK_CALLBACK
462 *
463 * RETURN:      Status
464 *
465 * DESCRIPTION: Descending callback for the analysis walk. Checks for
466 *              miscellaneous issues in the code.
467 *
468 ******************************************************************************/
469
470ACPI_STATUS
471AnOtherSemanticAnalysisWalkBegin (
472    ACPI_PARSE_OBJECT       *Op,
473    UINT32                  Level,
474    void                    *Context)
475{
476    ACPI_PARSE_OBJECT       *ArgNode;
477    ACPI_PARSE_OBJECT       *PrevArgNode = NULL;
478    const ACPI_OPCODE_INFO  *OpInfo;
479    ACPI_NAMESPACE_NODE     *Node;
480
481
482    OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
483
484    /*
485     * Determine if an execution class operator actually does something by
486     * checking if it has a target and/or the function return value is used.
487     * (Target is optional, so a standalone statement can actually do nothing.)
488     */
489    if ((OpInfo->Class == AML_CLASS_EXECUTE) &&
490        (OpInfo->Flags & AML_HAS_RETVAL) &&
491        (!AnIsResultUsed (Op)))
492    {
493        if (OpInfo->Flags & AML_HAS_TARGET)
494        {
495            /*
496             * Find the target node, it is always the last child. If the traget
497             * is not specified in the ASL, a default node of type Zero was
498             * created by the parser.
499             */
500            ArgNode = Op->Asl.Child;
501            while (ArgNode->Asl.Next)
502            {
503                PrevArgNode = ArgNode;
504                ArgNode = ArgNode->Asl.Next;
505            }
506
507            /* Divide() is the only weird case, it has two targets */
508
509            if (Op->Asl.AmlOpcode == AML_DIVIDE_OP)
510            {
511                if ((ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) &&
512                    (PrevArgNode) &&
513                    (PrevArgNode->Asl.ParseOpcode == PARSEOP_ZERO))
514                {
515                    AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED,
516                        Op, Op->Asl.ExternalName);
517                }
518            }
519            else if (ArgNode->Asl.ParseOpcode == PARSEOP_ZERO)
520            {
521                AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED,
522                    Op, Op->Asl.ExternalName);
523            }
524        }
525        else
526        {
527            /*
528             * Has no target and the result is not used. Only a couple opcodes
529             * can have this combination.
530             */
531            switch (Op->Asl.ParseOpcode)
532            {
533            case PARSEOP_ACQUIRE:
534            case PARSEOP_WAIT:
535            case PARSEOP_LOADTABLE:
536
537                break;
538
539            default:
540
541                AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED,
542                    Op, Op->Asl.ExternalName);
543                break;
544            }
545        }
546    }
547
548
549    /*
550     * Semantic checks for individual ASL operators
551     */
552    switch (Op->Asl.ParseOpcode)
553    {
554    case PARSEOP_ACQUIRE:
555    case PARSEOP_WAIT:
556        /*
557         * Emit a warning if the timeout parameter for these operators is not
558         * ACPI_WAIT_FOREVER, and the result value from the operator is not
559         * checked, meaning that a timeout could happen, but the code
560         * would not know about it.
561         */
562
563        /* First child is the namepath, 2nd child is timeout */
564
565        ArgNode = Op->Asl.Child;
566        ArgNode = ArgNode->Asl.Next;
567
568        /*
569         * Check for the WAIT_FOREVER case - defined by the ACPI spec to be
570         * 0xFFFF or greater
571         */
572        if (((ArgNode->Asl.ParseOpcode == PARSEOP_WORDCONST) ||
573             (ArgNode->Asl.ParseOpcode == PARSEOP_INTEGER))  &&
574             (ArgNode->Asl.Value.Integer >= (UINT64) ACPI_WAIT_FOREVER))
575        {
576            break;
577        }
578
579        /*
580         * The operation could timeout. If the return value is not used
581         * (indicates timeout occurred), issue a warning
582         */
583        if (!AnIsResultUsed (Op))
584        {
585            AslError (ASL_WARNING, ASL_MSG_TIMEOUT, ArgNode,
586                Op->Asl.ExternalName);
587        }
588        break;
589
590    case PARSEOP_CREATEFIELD:
591        /*
592         * Check for a zero Length (NumBits) operand. NumBits is the 3rd operand
593         */
594        ArgNode = Op->Asl.Child;
595        ArgNode = ArgNode->Asl.Next;
596        ArgNode = ArgNode->Asl.Next;
597
598        if ((ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) ||
599           ((ArgNode->Asl.ParseOpcode == PARSEOP_INTEGER) &&
600            (ArgNode->Asl.Value.Integer == 0)))
601        {
602            AslError (ASL_ERROR, ASL_MSG_NON_ZERO, ArgNode, NULL);
603        }
604        break;
605
606    case PARSEOP_CONNECTION:
607        /*
608         * Ensure that the referenced operation region has the correct SPACE_ID.
609         * From the grammar/parser, we know the parent is a FIELD definition.
610         */
611        ArgNode = Op->Asl.Parent;       /* Field definition */
612        ArgNode = ArgNode->Asl.Child;   /* First child is the OpRegion Name */
613        Node = ArgNode->Asl.Node;       /* OpRegion namespace node */
614        if (!Node)
615        {
616            break;
617        }
618
619        ArgNode = Node->Op;             /* OpRegion definition */
620        ArgNode = ArgNode->Asl.Child;   /* First child is the OpRegion Name */
621        ArgNode = ArgNode->Asl.Next;    /* Next peer is the SPACE_ID (what we want) */
622
623        /*
624         * The Connection() operator is only valid for the following operation
625         * region SpaceIds: GeneralPurposeIo and GenericSerialBus.
626         */
627        if ((ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GPIO) &&
628            (ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GSBUS))
629        {
630            AslError (ASL_ERROR, ASL_MSG_CONNECTION_INVALID, Op, NULL);
631        }
632        break;
633
634    case PARSEOP_FIELD:
635        /*
636         * Ensure that fields for GeneralPurposeIo and GenericSerialBus
637         * contain at least one Connection() operator
638         */
639        ArgNode = Op->Asl.Child;        /* 1st child is the OpRegion Name */
640        Node = ArgNode->Asl.Node;       /* OpRegion namespace node */
641        if (!Node)
642        {
643            break;
644        }
645
646        ArgNode = Node->Op;             /* OpRegion definition */
647        ArgNode = ArgNode->Asl.Child;   /* First child is the OpRegion Name */
648        ArgNode = ArgNode->Asl.Next;    /* Next peer is the SPACE_ID (what we want) */
649
650        /* We are only interested in GeneralPurposeIo and GenericSerialBus */
651
652        if ((ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GPIO) &&
653            (ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GSBUS))
654        {
655            break;
656        }
657
658        ArgNode = Op->Asl.Child;        /* 1st child is the OpRegion Name */
659        ArgNode = ArgNode->Asl.Next;    /* AccessType */
660        ArgNode = ArgNode->Asl.Next;    /* LockRule */
661        ArgNode = ArgNode->Asl.Next;    /* UpdateRule */
662        ArgNode = ArgNode->Asl.Next;    /* Start of FieldUnitList */
663
664        /* Walk the FieldUnitList */
665
666        while (ArgNode)
667        {
668            if (ArgNode->Asl.ParseOpcode == PARSEOP_CONNECTION)
669            {
670                break;
671            }
672            else if (ArgNode->Asl.ParseOpcode == PARSEOP_NAMESEG)
673            {
674                AslError (ASL_ERROR, ASL_MSG_CONNECTION_MISSING, ArgNode, NULL);
675                break;
676            }
677
678            ArgNode = ArgNode->Asl.Next;
679        }
680        break;
681
682    default:
683
684        break;
685    }
686
687    return (AE_OK);
688}
689