xref: /freebsd/sys/contrib/dev/acpica/compiler/aslwalks.c (revision 2710751bc309af25c6dea1171781678258e83840)
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 
71 ACPI_STATUS
72 AnMethodTypingWalkEnd (
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 
145 ACPI_STATUS
146 AnOperandTypecheckWalkEnd (
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 
457 ACPI_STATUS
458 AnOtherSemanticAnalysisWalkBegin (
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_ERROR, ASL_MSG_RESULT_NOT_USED,
503                         Op, Op->Asl.ExternalName);
504                 }
505             }
506             else if (ArgNode->Asl.ParseOpcode == PARSEOP_ZERO)
507             {
508                 AslError (ASL_ERROR, 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_ERROR, 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