1218585Sjkim/******************************************************************************
2218585Sjkim *
3245582Sjkim * Module Name: aslwalks.c - Miscellaneous analytical parse tree walks
4218585Sjkim *
5218585Sjkim *****************************************************************************/
6218585Sjkim
7218585Sjkim/*
8281075Sdim * Copyright (C) 2000 - 2015, Intel Corp.
9218585Sjkim * All rights reserved.
10218585Sjkim *
11218585Sjkim * Redistribution and use in source and binary forms, with or without
12218585Sjkim * modification, are permitted provided that the following conditions
13218585Sjkim * are met:
14218585Sjkim * 1. Redistributions of source code must retain the above copyright
15218585Sjkim *    notice, this list of conditions, and the following disclaimer,
16218585Sjkim *    without modification.
17218585Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18218585Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19218585Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20218585Sjkim *    including a substantially similar Disclaimer requirement for further
21218585Sjkim *    binary redistribution.
22218585Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23218585Sjkim *    of any contributors may be used to endorse or promote products derived
24218585Sjkim *    from this software without specific prior written permission.
25218585Sjkim *
26218585Sjkim * Alternatively, this software may be distributed under the terms of the
27218585Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28218585Sjkim * Software Foundation.
29218585Sjkim *
30218585Sjkim * NO WARRANTY
31218585Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32218585Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33218585Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34218585Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35218585Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36218585Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37218585Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38218585Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39218585Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40218585Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41218585Sjkim * POSSIBILITY OF SUCH DAMAGES.
42218585Sjkim */
43218585Sjkim
44218590Sjkim#include <contrib/dev/acpica/compiler/aslcompiler.h>
45218585Sjkim#include "aslcompiler.y.h"
46218590Sjkim#include <contrib/dev/acpica/include/acparser.h>
47218590Sjkim#include <contrib/dev/acpica/include/amlcode.h>
48218585Sjkim
49218585Sjkim
50218585Sjkim#define _COMPONENT          ACPI_COMPILER
51218585Sjkim        ACPI_MODULE_NAME    ("aslwalks")
52218585Sjkim
53218585Sjkim
54218585Sjkim/*******************************************************************************
55218585Sjkim *
56218585Sjkim * FUNCTION:    AnMethodTypingWalkEnd
57218585Sjkim *
58218585Sjkim * PARAMETERS:  ASL_WALK_CALLBACK
59218585Sjkim *
60218585Sjkim * RETURN:      Status
61218585Sjkim *
62218585Sjkim * DESCRIPTION: Ascending callback for typing walk. Complete the method
63218585Sjkim *              return analysis. Check methods for:
64218585Sjkim *              1) Initialized local variables
65218585Sjkim *              2) Valid arguments
66218585Sjkim *              3) Return types
67218585Sjkim *
68218585Sjkim ******************************************************************************/
69218585Sjkim
70218585SjkimACPI_STATUS
71218585SjkimAnMethodTypingWalkEnd (
72218585Sjkim    ACPI_PARSE_OBJECT       *Op,
73218585Sjkim    UINT32                  Level,
74218585Sjkim    void                    *Context)
75218585Sjkim{
76218585Sjkim    UINT32                  ThisNodeBtype;
77218585Sjkim
78218585Sjkim
79218585Sjkim    switch (Op->Asl.ParseOpcode)
80218585Sjkim    {
81218585Sjkim    case PARSEOP_METHOD:
82218585Sjkim
83218585Sjkim        Op->Asl.CompileFlags |= NODE_METHOD_TYPED;
84218585Sjkim        break;
85218585Sjkim
86218585Sjkim    case PARSEOP_RETURN:
87218585Sjkim
88218585Sjkim        if ((Op->Asl.Child) &&
89218585Sjkim            (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG))
90218585Sjkim        {
91218585Sjkim            ThisNodeBtype = AnGetBtype (Op->Asl.Child);
92218585Sjkim
93218585Sjkim            if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_METHODCALL) &&
94218585Sjkim                (ThisNodeBtype == (ACPI_UINT32_MAX -1)))
95218585Sjkim            {
96218585Sjkim                /*
97218585Sjkim                 * The called method is untyped at this time (typically a
98218585Sjkim                 * forward reference).
99218585Sjkim                 *
100218585Sjkim                 * Check for a recursive method call first.
101218585Sjkim                 */
102218585Sjkim                if (Op->Asl.ParentMethod != Op->Asl.Child->Asl.Node->Op)
103218585Sjkim                {
104218585Sjkim                    /* We must type the method here */
105218585Sjkim
106218585Sjkim                    TrWalkParseTree (Op->Asl.Child->Asl.Node->Op,
107218585Sjkim                        ASL_WALK_VISIT_UPWARD, NULL,
108218585Sjkim                        AnMethodTypingWalkEnd, NULL);
109218585Sjkim
110218585Sjkim                    ThisNodeBtype = AnGetBtype (Op->Asl.Child);
111218585Sjkim                }
112218585Sjkim            }
113218585Sjkim
114218585Sjkim            /* Returns a value, save the value type */
115218585Sjkim
116218585Sjkim            if (Op->Asl.ParentMethod)
117218585Sjkim            {
118218585Sjkim                Op->Asl.ParentMethod->Asl.AcpiBtype |= ThisNodeBtype;
119218585Sjkim            }
120218585Sjkim        }
121218585Sjkim        break;
122218585Sjkim
123218585Sjkim    default:
124250838Sjkim
125218585Sjkim        break;
126218585Sjkim    }
127218585Sjkim
128218585Sjkim    return (AE_OK);
129218585Sjkim}
130218585Sjkim
131218585Sjkim
132218585Sjkim/*******************************************************************************
133218585Sjkim *
134218585Sjkim * FUNCTION:    AnOperandTypecheckWalkEnd
135218585Sjkim *
136218585Sjkim * PARAMETERS:  ASL_WALK_CALLBACK
137218585Sjkim *
138218585Sjkim * RETURN:      Status
139218585Sjkim *
140218585Sjkim * DESCRIPTION: Ascending callback for analysis walk. Complete method
141218585Sjkim *              return analysis.
142218585Sjkim *
143218585Sjkim ******************************************************************************/
144218585Sjkim
145218585SjkimACPI_STATUS
146218585SjkimAnOperandTypecheckWalkEnd (
147218585Sjkim    ACPI_PARSE_OBJECT       *Op,
148218585Sjkim    UINT32                  Level,
149218585Sjkim    void                    *Context)
150218585Sjkim{
151218585Sjkim    const ACPI_OPCODE_INFO  *OpInfo;
152218585Sjkim    UINT32                  RuntimeArgTypes;
153218585Sjkim    UINT32                  RuntimeArgTypes2;
154218585Sjkim    UINT32                  RequiredBtypes;
155218585Sjkim    UINT32                  ThisNodeBtype;
156218585Sjkim    UINT32                  CommonBtypes;
157218585Sjkim    UINT32                  OpcodeClass;
158218585Sjkim    ACPI_PARSE_OBJECT       *ArgOp;
159218585Sjkim    UINT32                  ArgType;
160218585Sjkim
161218585Sjkim
162218585Sjkim    switch (Op->Asl.AmlOpcode)
163218585Sjkim    {
164218585Sjkim    case AML_RAW_DATA_BYTE:
165218585Sjkim    case AML_RAW_DATA_WORD:
166218585Sjkim    case AML_RAW_DATA_DWORD:
167218585Sjkim    case AML_RAW_DATA_QWORD:
168218585Sjkim    case AML_RAW_DATA_BUFFER:
169218585Sjkim    case AML_RAW_DATA_CHAIN:
170218585Sjkim    case AML_PACKAGE_LENGTH:
171218585Sjkim    case AML_UNASSIGNED_OPCODE:
172218585Sjkim    case AML_DEFAULT_ARG_OP:
173218585Sjkim
174218585Sjkim        /* Ignore the internal (compiler-only) AML opcodes */
175218585Sjkim
176218585Sjkim        return (AE_OK);
177218585Sjkim
178218585Sjkim    default:
179250838Sjkim
180218585Sjkim        break;
181218585Sjkim    }
182218585Sjkim
183218585Sjkim    OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
184218585Sjkim    if (!OpInfo)
185218585Sjkim    {
186218585Sjkim        return (AE_OK);
187218585Sjkim    }
188218585Sjkim
189218585Sjkim    ArgOp           = Op->Asl.Child;
190218585Sjkim    RuntimeArgTypes = OpInfo->RuntimeArgs;
191218585Sjkim    OpcodeClass     = OpInfo->Class;
192218585Sjkim
193218585Sjkim#ifdef ASL_ERROR_NAMED_OBJECT_IN_WHILE
194218585Sjkim    /*
195218585Sjkim     * Update 11/2008: In practice, we can't perform this check. A simple
196218585Sjkim     * analysis is not sufficient. Also, it can cause errors when compiling
197218585Sjkim     * disassembled code because of the way Switch operators are implemented
198218585Sjkim     * (a While(One) loop with a named temp variable created within.)
199218585Sjkim     */
200218585Sjkim
201218585Sjkim    /*
202218585Sjkim     * If we are creating a named object, check if we are within a while loop
203218585Sjkim     * by checking if the parent is a WHILE op. This is a simple analysis, but
204218585Sjkim     * probably sufficient for many cases.
205218585Sjkim     *
206218585Sjkim     * Allow Scope(), Buffer(), and Package().
207218585Sjkim     */
208218585Sjkim    if (((OpcodeClass == AML_CLASS_NAMED_OBJECT) && (Op->Asl.AmlOpcode != AML_SCOPE_OP)) ||
209218585Sjkim        ((OpcodeClass == AML_CLASS_CREATE) && (OpInfo->Flags & AML_NSNODE)))
210218585Sjkim    {
211218585Sjkim        if (Op->Asl.Parent->Asl.AmlOpcode == AML_WHILE_OP)
212218585Sjkim        {
213218585Sjkim            AslError (ASL_ERROR, ASL_MSG_NAMED_OBJECT_IN_WHILE, Op, NULL);
214218585Sjkim        }
215218585Sjkim    }
216218585Sjkim#endif
217218585Sjkim
218218585Sjkim    /*
219218585Sjkim     * Special case for control opcodes IF/RETURN/WHILE since they
220218585Sjkim     * have no runtime arg list (at this time)
221218585Sjkim     */
222218585Sjkim    switch (Op->Asl.AmlOpcode)
223218585Sjkim    {
224218585Sjkim    case AML_IF_OP:
225218585Sjkim    case AML_WHILE_OP:
226218585Sjkim    case AML_RETURN_OP:
227218585Sjkim
228218585Sjkim        if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL)
229218585Sjkim        {
230218585Sjkim            /* Check for an internal method */
231218585Sjkim
232218585Sjkim            if (AnIsInternalMethod (ArgOp))
233218585Sjkim            {
234218585Sjkim                return (AE_OK);
235218585Sjkim            }
236218585Sjkim
237218585Sjkim            /* The lone arg is a method call, check it */
238218585Sjkim
239218585Sjkim            RequiredBtypes = AnMapArgTypeToBtype (ARGI_INTEGER);
240218585Sjkim            if (Op->Asl.AmlOpcode == AML_RETURN_OP)
241218585Sjkim            {
242218585Sjkim                RequiredBtypes = 0xFFFFFFFF;
243218585Sjkim            }
244218585Sjkim
245218585Sjkim            ThisNodeBtype = AnGetBtype (ArgOp);
246218585Sjkim            if (ThisNodeBtype == ACPI_UINT32_MAX)
247218585Sjkim            {
248218585Sjkim                return (AE_OK);
249218585Sjkim            }
250218585Sjkim            AnCheckMethodReturnValue (Op, OpInfo, ArgOp,
251218585Sjkim                RequiredBtypes, ThisNodeBtype);
252218585Sjkim        }
253218585Sjkim        return (AE_OK);
254218585Sjkim
255281687Sjkim    case AML_EXTERNAL_OP:
256281687Sjkim        /*
257281687Sjkim         * Not really a "runtime" opcode since it used by disassembler only.
258281687Sjkim         * The parser will find any issues with the operands.
259281687Sjkim         */
260281687Sjkim        return (AE_OK);
261281687Sjkim
262218585Sjkim    default:
263250838Sjkim
264218585Sjkim        break;
265218585Sjkim    }
266218585Sjkim
267218585Sjkim    /* Ignore the non-executable opcodes */
268218585Sjkim
269218585Sjkim    if (RuntimeArgTypes == ARGI_INVALID_OPCODE)
270218585Sjkim    {
271218585Sjkim        return (AE_OK);
272218585Sjkim    }
273218585Sjkim
274218585Sjkim    switch (OpcodeClass)
275218585Sjkim    {
276218585Sjkim    case AML_CLASS_EXECUTE:
277218585Sjkim    case AML_CLASS_CREATE:
278218585Sjkim    case AML_CLASS_CONTROL:
279218585Sjkim    case AML_CLASS_RETURN_VALUE:
280218585Sjkim
281218585Sjkim        /* TBD: Change class or fix typechecking for these */
282218585Sjkim
283218585Sjkim        if ((Op->Asl.AmlOpcode == AML_BUFFER_OP)        ||
284218585Sjkim            (Op->Asl.AmlOpcode == AML_PACKAGE_OP)       ||
285218585Sjkim            (Op->Asl.AmlOpcode == AML_VAR_PACKAGE_OP))
286218585Sjkim        {
287218585Sjkim            break;
288218585Sjkim        }
289218585Sjkim
290218585Sjkim        /* Reverse the runtime argument list */
291218585Sjkim
292218585Sjkim        RuntimeArgTypes2 = 0;
293218585Sjkim        while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes)))
294218585Sjkim        {
295218585Sjkim            RuntimeArgTypes2 <<= ARG_TYPE_WIDTH;
296218585Sjkim            RuntimeArgTypes2 |= ArgType;
297218585Sjkim            INCREMENT_ARG_LIST (RuntimeArgTypes);
298218585Sjkim        }
299218585Sjkim
300218585Sjkim        while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes2)))
301218585Sjkim        {
302218585Sjkim            RequiredBtypes = AnMapArgTypeToBtype (ArgType);
303218585Sjkim
304281075Sdim            if (!ArgOp)
305281075Sdim            {
306281075Sdim                AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op,
307281075Sdim                    "Null ArgOp in argument loop");
308281075Sdim                AslAbort ();
309281075Sdim            }
310281075Sdim
311218585Sjkim            ThisNodeBtype = AnGetBtype (ArgOp);
312218585Sjkim            if (ThisNodeBtype == ACPI_UINT32_MAX)
313218585Sjkim            {
314218585Sjkim                goto NextArgument;
315218585Sjkim            }
316218585Sjkim
317218585Sjkim            /* Examine the arg based on the required type of the arg */
318218585Sjkim
319218585Sjkim            switch (ArgType)
320218585Sjkim            {
321218585Sjkim            case ARGI_TARGETREF:
322218585Sjkim
323218585Sjkim                if (ArgOp->Asl.ParseOpcode == PARSEOP_ZERO)
324218585Sjkim                {
325218585Sjkim                    /* ZERO is the placeholder for "don't store result" */
326218585Sjkim
327218585Sjkim                    ThisNodeBtype = RequiredBtypes;
328218585Sjkim                    break;
329218585Sjkim                }
330218585Sjkim
331218585Sjkim                if (ArgOp->Asl.ParseOpcode == PARSEOP_INTEGER)
332218585Sjkim                {
333218585Sjkim                    /*
334218585Sjkim                     * This is the case where an original reference to a resource
335218585Sjkim                     * descriptor field has been replaced by an (Integer) offset.
336218585Sjkim                     * These named fields are supported at compile-time only;
337218585Sjkim                     * the names are not passed to the interpreter (via the AML).
338218585Sjkim                     */
339218585Sjkim                    if ((ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE_FIELD) ||
340218585Sjkim                        (ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE))
341218585Sjkim                    {
342218585Sjkim                        AslError (ASL_ERROR, ASL_MSG_RESOURCE_FIELD, ArgOp, NULL);
343218585Sjkim                    }
344218585Sjkim                    else
345218585Sjkim                    {
346218585Sjkim                        AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, NULL);
347218585Sjkim                    }
348218585Sjkim                    break;
349218585Sjkim                }
350218585Sjkim
351218585Sjkim                if ((ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL) ||
352218585Sjkim                    (ArgOp->Asl.ParseOpcode == PARSEOP_DEREFOF))
353218585Sjkim                {
354218585Sjkim                    break;
355218585Sjkim                }
356218585Sjkim
357218585Sjkim                ThisNodeBtype = RequiredBtypes;
358218585Sjkim                break;
359218585Sjkim
360218585Sjkim
361218585Sjkim            case ARGI_REFERENCE:            /* References */
362218585Sjkim            case ARGI_INTEGER_REF:
363218585Sjkim            case ARGI_OBJECT_REF:
364218585Sjkim            case ARGI_DEVICE_REF:
365218585Sjkim
366218585Sjkim                switch (ArgOp->Asl.ParseOpcode)
367218585Sjkim                {
368218585Sjkim                case PARSEOP_LOCAL0:
369218585Sjkim                case PARSEOP_LOCAL1:
370218585Sjkim                case PARSEOP_LOCAL2:
371218585Sjkim                case PARSEOP_LOCAL3:
372218585Sjkim                case PARSEOP_LOCAL4:
373218585Sjkim                case PARSEOP_LOCAL5:
374218585Sjkim                case PARSEOP_LOCAL6:
375218585Sjkim                case PARSEOP_LOCAL7:
376218585Sjkim
377218585Sjkim                    /* TBD: implement analysis of current value (type) of the local */
378218585Sjkim                    /* For now, just treat any local as a typematch */
379218585Sjkim
380218585Sjkim                    /*ThisNodeBtype = RequiredBtypes;*/
381218585Sjkim                    break;
382218585Sjkim
383218585Sjkim                case PARSEOP_ARG0:
384218585Sjkim                case PARSEOP_ARG1:
385218585Sjkim                case PARSEOP_ARG2:
386218585Sjkim                case PARSEOP_ARG3:
387218585Sjkim                case PARSEOP_ARG4:
388218585Sjkim                case PARSEOP_ARG5:
389218585Sjkim                case PARSEOP_ARG6:
390218585Sjkim
391218585Sjkim                    /* Hard to analyze argument types, sow we won't */
392218585Sjkim                    /* For now, just treat any arg as a typematch */
393218585Sjkim
394218585Sjkim                    /* ThisNodeBtype = RequiredBtypes; */
395218585Sjkim                    break;
396218585Sjkim
397218585Sjkim                case PARSEOP_DEBUG:
398218585Sjkim                case PARSEOP_REFOF:
399218585Sjkim                case PARSEOP_INDEX:
400218585Sjkim                default:
401250838Sjkim
402218585Sjkim                    break;
403218585Sjkim
404218585Sjkim                }
405218585Sjkim                break;
406218585Sjkim
407218585Sjkim            case ARGI_INTEGER:
408218585Sjkim            default:
409250838Sjkim
410218585Sjkim                break;
411218585Sjkim            }
412218585Sjkim
413218585Sjkim
414218585Sjkim            CommonBtypes = ThisNodeBtype & RequiredBtypes;
415218585Sjkim
416218585Sjkim            if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL)
417218585Sjkim            {
418218585Sjkim                if (AnIsInternalMethod (ArgOp))
419218585Sjkim                {
420218585Sjkim                    return (AE_OK);
421218585Sjkim                }
422218585Sjkim
423218585Sjkim                /* Check a method call for a valid return value */
424218585Sjkim
425218585Sjkim                AnCheckMethodReturnValue (Op, OpInfo, ArgOp,
426218585Sjkim                    RequiredBtypes, ThisNodeBtype);
427218585Sjkim            }
428218585Sjkim
429218585Sjkim            /*
430218585Sjkim             * Now check if the actual type(s) match at least one
431218585Sjkim             * bit to the required type
432218585Sjkim             */
433218585Sjkim            else if (!CommonBtypes)
434218585Sjkim            {
435218585Sjkim                /* No match -- this is a type mismatch error */
436218585Sjkim
437218585Sjkim                AnFormatBtype (StringBuffer, ThisNodeBtype);
438218585Sjkim                AnFormatBtype (StringBuffer2, RequiredBtypes);
439218585Sjkim
440218585Sjkim                sprintf (MsgBuffer, "[%s] found, %s operator requires [%s]",
441218585Sjkim                            StringBuffer, OpInfo->Name, StringBuffer2);
442218585Sjkim
443218585Sjkim                AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, MsgBuffer);
444218585Sjkim            }
445218585Sjkim
446218585Sjkim        NextArgument:
447218585Sjkim            ArgOp = ArgOp->Asl.Next;
448218585Sjkim            INCREMENT_ARG_LIST (RuntimeArgTypes2);
449218585Sjkim        }
450218585Sjkim        break;
451218585Sjkim
452218585Sjkim    default:
453250838Sjkim
454218585Sjkim        break;
455218585Sjkim    }
456218585Sjkim
457218585Sjkim    return (AE_OK);
458218585Sjkim}
459218585Sjkim
460218585Sjkim
461218585Sjkim/*******************************************************************************
462218585Sjkim *
463218585Sjkim * FUNCTION:    AnOtherSemanticAnalysisWalkBegin
464218585Sjkim *
465218585Sjkim * PARAMETERS:  ASL_WALK_CALLBACK
466218585Sjkim *
467218585Sjkim * RETURN:      Status
468218585Sjkim *
469218585Sjkim * DESCRIPTION: Descending callback for the analysis walk. Checks for
470218585Sjkim *              miscellaneous issues in the code.
471218585Sjkim *
472218585Sjkim ******************************************************************************/
473218585Sjkim
474218585SjkimACPI_STATUS
475218585SjkimAnOtherSemanticAnalysisWalkBegin (
476218585Sjkim    ACPI_PARSE_OBJECT       *Op,
477218585Sjkim    UINT32                  Level,
478218585Sjkim    void                    *Context)
479218585Sjkim{
480218585Sjkim    ACPI_PARSE_OBJECT       *ArgNode;
481218585Sjkim    ACPI_PARSE_OBJECT       *PrevArgNode = NULL;
482218585Sjkim    const ACPI_OPCODE_INFO  *OpInfo;
483228110Sjkim    ACPI_NAMESPACE_NODE     *Node;
484218585Sjkim
485218585Sjkim
486218585Sjkim    OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
487218585Sjkim
488218585Sjkim    /*
489218585Sjkim     * Determine if an execution class operator actually does something by
490218585Sjkim     * checking if it has a target and/or the function return value is used.
491218585Sjkim     * (Target is optional, so a standalone statement can actually do nothing.)
492218585Sjkim     */
493218585Sjkim    if ((OpInfo->Class == AML_CLASS_EXECUTE) &&
494218585Sjkim        (OpInfo->Flags & AML_HAS_RETVAL) &&
495218585Sjkim        (!AnIsResultUsed (Op)))
496218585Sjkim    {
497218585Sjkim        if (OpInfo->Flags & AML_HAS_TARGET)
498218585Sjkim        {
499218585Sjkim            /*
500218585Sjkim             * Find the target node, it is always the last child. If the traget
501218585Sjkim             * is not specified in the ASL, a default node of type Zero was
502218585Sjkim             * created by the parser.
503218585Sjkim             */
504218585Sjkim            ArgNode = Op->Asl.Child;
505218585Sjkim            while (ArgNode->Asl.Next)
506218585Sjkim            {
507218585Sjkim                PrevArgNode = ArgNode;
508218585Sjkim                ArgNode = ArgNode->Asl.Next;
509218585Sjkim            }
510218585Sjkim
511218585Sjkim            /* Divide() is the only weird case, it has two targets */
512218585Sjkim
513218585Sjkim            if (Op->Asl.AmlOpcode == AML_DIVIDE_OP)
514218585Sjkim            {
515218585Sjkim                if ((ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) &&
516218585Sjkim                    (PrevArgNode) &&
517218585Sjkim                    (PrevArgNode->Asl.ParseOpcode == PARSEOP_ZERO))
518218585Sjkim                {
519249112Sjkim                    AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED,
520218585Sjkim                        Op, Op->Asl.ExternalName);
521218585Sjkim                }
522218585Sjkim            }
523218585Sjkim            else if (ArgNode->Asl.ParseOpcode == PARSEOP_ZERO)
524218585Sjkim            {
525249112Sjkim                AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED,
526218585Sjkim                    Op, Op->Asl.ExternalName);
527218585Sjkim            }
528218585Sjkim        }
529218585Sjkim        else
530218585Sjkim        {
531218585Sjkim            /*
532218585Sjkim             * Has no target and the result is not used. Only a couple opcodes
533218585Sjkim             * can have this combination.
534218585Sjkim             */
535218585Sjkim            switch (Op->Asl.ParseOpcode)
536218585Sjkim            {
537218585Sjkim            case PARSEOP_ACQUIRE:
538218585Sjkim            case PARSEOP_WAIT:
539218585Sjkim            case PARSEOP_LOADTABLE:
540250838Sjkim
541218585Sjkim                break;
542218585Sjkim
543218585Sjkim            default:
544250838Sjkim
545249112Sjkim                AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED,
546218585Sjkim                    Op, Op->Asl.ExternalName);
547218585Sjkim                break;
548218585Sjkim            }
549218585Sjkim        }
550218585Sjkim    }
551218585Sjkim
552218585Sjkim
553218585Sjkim    /*
554218585Sjkim     * Semantic checks for individual ASL operators
555218585Sjkim     */
556218585Sjkim    switch (Op->Asl.ParseOpcode)
557218585Sjkim    {
558218585Sjkim    case PARSEOP_ACQUIRE:
559218585Sjkim    case PARSEOP_WAIT:
560218585Sjkim        /*
561218585Sjkim         * Emit a warning if the timeout parameter for these operators is not
562218585Sjkim         * ACPI_WAIT_FOREVER, and the result value from the operator is not
563218585Sjkim         * checked, meaning that a timeout could happen, but the code
564218585Sjkim         * would not know about it.
565218585Sjkim         */
566218585Sjkim
567218585Sjkim        /* First child is the namepath, 2nd child is timeout */
568218585Sjkim
569218585Sjkim        ArgNode = Op->Asl.Child;
570218585Sjkim        ArgNode = ArgNode->Asl.Next;
571218585Sjkim
572218585Sjkim        /*
573218585Sjkim         * Check for the WAIT_FOREVER case - defined by the ACPI spec to be
574218585Sjkim         * 0xFFFF or greater
575218585Sjkim         */
576218585Sjkim        if (((ArgNode->Asl.ParseOpcode == PARSEOP_WORDCONST) ||
577218585Sjkim             (ArgNode->Asl.ParseOpcode == PARSEOP_INTEGER))  &&
578218585Sjkim             (ArgNode->Asl.Value.Integer >= (UINT64) ACPI_WAIT_FOREVER))
579218585Sjkim        {
580218585Sjkim            break;
581218585Sjkim        }
582218585Sjkim
583218585Sjkim        /*
584218585Sjkim         * The operation could timeout. If the return value is not used
585218585Sjkim         * (indicates timeout occurred), issue a warning
586218585Sjkim         */
587218585Sjkim        if (!AnIsResultUsed (Op))
588218585Sjkim        {
589218585Sjkim            AslError (ASL_WARNING, ASL_MSG_TIMEOUT, ArgNode,
590218585Sjkim                Op->Asl.ExternalName);
591218585Sjkim        }
592218585Sjkim        break;
593218585Sjkim
594218585Sjkim    case PARSEOP_CREATEFIELD:
595218585Sjkim        /*
596218585Sjkim         * Check for a zero Length (NumBits) operand. NumBits is the 3rd operand
597218585Sjkim         */
598218585Sjkim        ArgNode = Op->Asl.Child;
599218585Sjkim        ArgNode = ArgNode->Asl.Next;
600218585Sjkim        ArgNode = ArgNode->Asl.Next;
601218585Sjkim
602218585Sjkim        if ((ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) ||
603218585Sjkim           ((ArgNode->Asl.ParseOpcode == PARSEOP_INTEGER) &&
604218585Sjkim            (ArgNode->Asl.Value.Integer == 0)))
605218585Sjkim        {
606218585Sjkim            AslError (ASL_ERROR, ASL_MSG_NON_ZERO, ArgNode, NULL);
607218585Sjkim        }
608218585Sjkim        break;
609218585Sjkim
610228110Sjkim    case PARSEOP_CONNECTION:
611228110Sjkim        /*
612228110Sjkim         * Ensure that the referenced operation region has the correct SPACE_ID.
613228110Sjkim         * From the grammar/parser, we know the parent is a FIELD definition.
614228110Sjkim         */
615228110Sjkim        ArgNode = Op->Asl.Parent;       /* Field definition */
616228110Sjkim        ArgNode = ArgNode->Asl.Child;   /* First child is the OpRegion Name */
617228110Sjkim        Node = ArgNode->Asl.Node;       /* OpRegion namespace node */
618281075Sdim        if (!Node)
619281075Sdim        {
620281075Sdim            break;
621281075Sdim        }
622228110Sjkim
623228110Sjkim        ArgNode = Node->Op;             /* OpRegion definition */
624228110Sjkim        ArgNode = ArgNode->Asl.Child;   /* First child is the OpRegion Name */
625228110Sjkim        ArgNode = ArgNode->Asl.Next;    /* Next peer is the SPACE_ID (what we want) */
626228110Sjkim
627228110Sjkim        /*
628228110Sjkim         * The Connection() operator is only valid for the following operation
629228110Sjkim         * region SpaceIds: GeneralPurposeIo and GenericSerialBus.
630228110Sjkim         */
631228110Sjkim        if ((ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GPIO) &&
632228110Sjkim            (ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GSBUS))
633228110Sjkim        {
634228110Sjkim            AslError (ASL_ERROR, ASL_MSG_CONNECTION_INVALID, Op, NULL);
635228110Sjkim        }
636228110Sjkim        break;
637228110Sjkim
638228110Sjkim    case PARSEOP_FIELD:
639228110Sjkim        /*
640228110Sjkim         * Ensure that fields for GeneralPurposeIo and GenericSerialBus
641228110Sjkim         * contain at least one Connection() operator
642228110Sjkim         */
643228110Sjkim        ArgNode = Op->Asl.Child;        /* 1st child is the OpRegion Name */
644228110Sjkim        Node = ArgNode->Asl.Node;       /* OpRegion namespace node */
645228110Sjkim        if (!Node)
646228110Sjkim        {
647228110Sjkim            break;
648228110Sjkim        }
649228110Sjkim
650228110Sjkim        ArgNode = Node->Op;             /* OpRegion definition */
651228110Sjkim        ArgNode = ArgNode->Asl.Child;   /* First child is the OpRegion Name */
652228110Sjkim        ArgNode = ArgNode->Asl.Next;    /* Next peer is the SPACE_ID (what we want) */
653228110Sjkim
654228110Sjkim        /* We are only interested in GeneralPurposeIo and GenericSerialBus */
655228110Sjkim
656228110Sjkim        if ((ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GPIO) &&
657228110Sjkim            (ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GSBUS))
658228110Sjkim        {
659228110Sjkim            break;
660228110Sjkim        }
661228110Sjkim
662228110Sjkim        ArgNode = Op->Asl.Child;        /* 1st child is the OpRegion Name */
663228110Sjkim        ArgNode = ArgNode->Asl.Next;    /* AccessType */
664228110Sjkim        ArgNode = ArgNode->Asl.Next;    /* LockRule */
665228110Sjkim        ArgNode = ArgNode->Asl.Next;    /* UpdateRule */
666228110Sjkim        ArgNode = ArgNode->Asl.Next;    /* Start of FieldUnitList */
667228110Sjkim
668228110Sjkim        /* Walk the FieldUnitList */
669228110Sjkim
670228110Sjkim        while (ArgNode)
671228110Sjkim        {
672228110Sjkim            if (ArgNode->Asl.ParseOpcode == PARSEOP_CONNECTION)
673228110Sjkim            {
674228110Sjkim                break;
675228110Sjkim            }
676228110Sjkim            else if (ArgNode->Asl.ParseOpcode == PARSEOP_NAMESEG)
677228110Sjkim            {
678228110Sjkim                AslError (ASL_ERROR, ASL_MSG_CONNECTION_MISSING, ArgNode, NULL);
679228110Sjkim                break;
680228110Sjkim            }
681228110Sjkim
682228110Sjkim            ArgNode = ArgNode->Asl.Next;
683228110Sjkim        }
684228110Sjkim        break;
685228110Sjkim
686218585Sjkim    default:
687250838Sjkim
688218585Sjkim        break;
689218585Sjkim    }
690218585Sjkim
691218585Sjkim    return (AE_OK);
692218585Sjkim}
693