aslmethod.c revision 256281
1/******************************************************************************
2 *
3 * Module Name: aslmethod.c - Control method analysis walk
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    ("aslmethod")
53
54
55/* Local prototypes */
56
57void
58MtCheckNamedObjectInMethod (
59    ACPI_PARSE_OBJECT       *Op,
60    ASL_METHOD_INFO         *MethodInfo);
61
62
63/*******************************************************************************
64 *
65 * FUNCTION:    MtMethodAnalysisWalkBegin
66 *
67 * PARAMETERS:  ASL_WALK_CALLBACK
68 *
69 * RETURN:      Status
70 *
71 * DESCRIPTION: Descending callback for the analysis walk. Check methods for:
72 *              1) Initialized local variables
73 *              2) Valid arguments
74 *              3) Return types
75 *
76 ******************************************************************************/
77
78ACPI_STATUS
79MtMethodAnalysisWalkBegin (
80    ACPI_PARSE_OBJECT       *Op,
81    UINT32                  Level,
82    void                    *Context)
83{
84    ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
85    ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack;
86    ACPI_PARSE_OBJECT       *Next;
87    UINT32                  RegisterNumber;
88    UINT32                  i;
89    char                    LocalName[] = "Local0";
90    char                    ArgName[] = "Arg0";
91    ACPI_PARSE_OBJECT       *ArgNode;
92    ACPI_PARSE_OBJECT       *NextType;
93    ACPI_PARSE_OBJECT       *NextParamType;
94    UINT8                   ActualArgs = 0;
95
96
97    switch (Op->Asl.ParseOpcode)
98    {
99    case PARSEOP_METHOD:
100
101        TotalMethods++;
102
103        /* Create and init method info */
104
105        MethodInfo       = UtLocalCalloc (sizeof (ASL_METHOD_INFO));
106        MethodInfo->Next = WalkInfo->MethodStack;
107        MethodInfo->Op = Op;
108
109        WalkInfo->MethodStack = MethodInfo;
110
111        /* Get the name node, ignored here */
112
113        Next = Op->Asl.Child;
114
115        /* Get the NumArguments node */
116
117        Next = Next->Asl.Next;
118        MethodInfo->NumArguments = (UINT8)
119            (((UINT8) Next->Asl.Value.Integer) & 0x07);
120
121        /* Get the SerializeRule and SyncLevel nodes, ignored here */
122
123        Next = Next->Asl.Next;
124        MethodInfo->ShouldBeSerialized = (UINT8) Next->Asl.Value.Integer;
125
126        Next = Next->Asl.Next;
127        ArgNode = Next;
128
129        /* Get the ReturnType node */
130
131        Next = Next->Asl.Next;
132
133        NextType = Next->Asl.Child;
134        while (NextType)
135        {
136            /* Get and map each of the ReturnTypes */
137
138            MethodInfo->ValidReturnTypes |= AnMapObjTypeToBtype (NextType);
139            NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
140            NextType = NextType->Asl.Next;
141        }
142
143        /* Get the ParameterType node */
144
145        Next = Next->Asl.Next;
146
147        NextType = Next->Asl.Child;
148        while (NextType)
149        {
150            if (NextType->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
151            {
152                NextParamType = NextType->Asl.Child;
153                while (NextParamType)
154                {
155                    MethodInfo->ValidArgTypes[ActualArgs] |= AnMapObjTypeToBtype (NextParamType);
156                    NextParamType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
157                    NextParamType = NextParamType->Asl.Next;
158                }
159            }
160            else
161            {
162                MethodInfo->ValidArgTypes[ActualArgs] =
163                    AnMapObjTypeToBtype (NextType);
164                NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
165                ActualArgs++;
166            }
167
168            NextType = NextType->Asl.Next;
169        }
170
171        if ((MethodInfo->NumArguments) &&
172            (MethodInfo->NumArguments != ActualArgs))
173        {
174            /* error: Param list did not match number of args */
175        }
176
177        /* Allow numarguments == 0 for Function() */
178
179        if ((!MethodInfo->NumArguments) && (ActualArgs))
180        {
181            MethodInfo->NumArguments = ActualArgs;
182            ArgNode->Asl.Value.Integer |= ActualArgs;
183        }
184
185        /*
186         * Actual arguments are initialized at method entry.
187         * All other ArgX "registers" can be used as locals, so we
188         * track their initialization.
189         */
190        for (i = 0; i < MethodInfo->NumArguments; i++)
191        {
192            MethodInfo->ArgInitialized[i] = TRUE;
193        }
194        break;
195
196    case PARSEOP_METHODCALL:
197
198        if (MethodInfo &&
199           (Op->Asl.Node == MethodInfo->Op->Asl.Node))
200        {
201            AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName);
202        }
203        break;
204
205    case PARSEOP_LOCAL0:
206    case PARSEOP_LOCAL1:
207    case PARSEOP_LOCAL2:
208    case PARSEOP_LOCAL3:
209    case PARSEOP_LOCAL4:
210    case PARSEOP_LOCAL5:
211    case PARSEOP_LOCAL6:
212    case PARSEOP_LOCAL7:
213
214        if (!MethodInfo)
215        {
216            /*
217             * Local was used outside a control method, or there was an error
218             * in the method declaration.
219             */
220            AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName);
221            return (AE_ERROR);
222        }
223
224        RegisterNumber = (Op->Asl.AmlOpcode & 0x000F);
225
226        /*
227         * If the local is being used as a target, mark the local
228         * initialized
229         */
230        if (Op->Asl.CompileFlags & NODE_IS_TARGET)
231        {
232            MethodInfo->LocalInitialized[RegisterNumber] = TRUE;
233        }
234
235        /*
236         * Otherwise, this is a reference, check if the local
237         * has been previously initialized.
238         *
239         * The only operator that accepts an uninitialized value is ObjectType()
240         */
241        else if ((!MethodInfo->LocalInitialized[RegisterNumber]) &&
242                 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
243        {
244            LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30);
245            AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName);
246        }
247        break;
248
249    case PARSEOP_ARG0:
250    case PARSEOP_ARG1:
251    case PARSEOP_ARG2:
252    case PARSEOP_ARG3:
253    case PARSEOP_ARG4:
254    case PARSEOP_ARG5:
255    case PARSEOP_ARG6:
256
257        if (!MethodInfo)
258        {
259            /*
260             * Arg was used outside a control method, or there was an error
261             * in the method declaration.
262             */
263            AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName);
264            return (AE_ERROR);
265        }
266
267        RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8;
268        ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30);
269
270        /*
271         * If the Arg is being used as a target, mark the local
272         * initialized
273         */
274        if (Op->Asl.CompileFlags & NODE_IS_TARGET)
275        {
276            MethodInfo->ArgInitialized[RegisterNumber] = TRUE;
277        }
278
279        /*
280         * Otherwise, this is a reference, check if the Arg
281         * has been previously initialized.
282         *
283         * The only operator that accepts an uninitialized value is ObjectType()
284         */
285        else if ((!MethodInfo->ArgInitialized[RegisterNumber]) &&
286                 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
287        {
288            AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName);
289        }
290
291        /* Flag this arg if it is not a "real" argument to the method */
292
293        if (RegisterNumber >= MethodInfo->NumArguments)
294        {
295            AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName);
296        }
297        break;
298
299    case PARSEOP_RETURN:
300
301        if (!MethodInfo)
302        {
303            /*
304             * Probably was an error in the method declaration,
305             * no additional error here
306             */
307            ACPI_WARNING ((AE_INFO, "%p, No parent method", Op));
308            return (AE_ERROR);
309        }
310
311        /*
312         * A child indicates a possible return value. A simple Return or
313         * Return() is marked with NODE_IS_NULL_RETURN by the parser so
314         * that it is not counted as a "real" return-with-value, although
315         * the AML code that is actually emitted is Return(0). The AML
316         * definition of Return has a required parameter, so we are
317         * forced to convert a null return to Return(0).
318         */
319        if ((Op->Asl.Child) &&
320            (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) &&
321            (!(Op->Asl.Child->Asl.CompileFlags & NODE_IS_NULL_RETURN)))
322        {
323            MethodInfo->NumReturnWithValue++;
324        }
325        else
326        {
327            MethodInfo->NumReturnNoValue++;
328        }
329        break;
330
331    case PARSEOP_BREAK:
332    case PARSEOP_CONTINUE:
333
334        Next = Op->Asl.Parent;
335        while (Next)
336        {
337            if (Next->Asl.ParseOpcode == PARSEOP_WHILE)
338            {
339                break;
340            }
341            Next = Next->Asl.Parent;
342        }
343
344        if (!Next)
345        {
346            AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL);
347        }
348        break;
349
350    case PARSEOP_STALL:
351
352        /* We can range check if the argument is an integer */
353
354        if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) &&
355            (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX))
356        {
357            AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL);
358        }
359        break;
360
361    case PARSEOP_DEVICE:
362    case PARSEOP_EVENT:
363    case PARSEOP_MUTEX:
364    case PARSEOP_OPERATIONREGION:
365    case PARSEOP_POWERRESOURCE:
366    case PARSEOP_PROCESSOR:
367    case PARSEOP_THERMALZONE:
368
369        /*
370         * The first operand is a name to be created in the namespace.
371         * Check against the reserved list.
372         */
373        i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg);
374        if (i < ACPI_VALID_RESERVED_NAME_MAX)
375        {
376            AslError (ASL_ERROR, ASL_MSG_RESERVED_USE, Op, Op->Asl.ExternalName);
377        }
378        break;
379
380    case PARSEOP_NAME:
381
382        /* Typecheck any predefined names statically defined with Name() */
383
384        ApCheckForPredefinedObject (Op, Op->Asl.NameSeg);
385
386        /* Special typechecking for _HID */
387
388        if (!ACPI_STRCMP (METHOD_NAME__HID, Op->Asl.NameSeg))
389        {
390            Next = Op->Asl.Child->Asl.Next;
391            AnCheckId (Next, ASL_TYPE_HID);
392        }
393
394        /* Special typechecking for _CID */
395
396        else if (!ACPI_STRCMP (METHOD_NAME__CID, Op->Asl.NameSeg))
397        {
398            Next = Op->Asl.Child->Asl.Next;
399
400            if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
401                (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE))
402            {
403                Next = Next->Asl.Child;
404                while (Next)
405                {
406                    AnCheckId (Next, ASL_TYPE_CID);
407                    Next = Next->Asl.Next;
408                }
409            }
410            else
411            {
412                AnCheckId (Next, ASL_TYPE_CID);
413            }
414        }
415        break;
416
417    default:
418
419        break;
420    }
421
422    /* Check for named object creation within a non-serialized method */
423
424    MtCheckNamedObjectInMethod (Op, MethodInfo);
425    return (AE_OK);
426}
427
428
429/*******************************************************************************
430 *
431 * FUNCTION:    MtCheckNamedObjectInMethod
432 *
433 * PARAMETERS:  Op                  - Current parser op
434 *              MethodInfo          - Info for method being parsed
435 *
436 * RETURN:      None
437 *
438 * DESCRIPTION: Detect if a non-serialized method is creating a named object,
439 *              which could possibly cause problems if two threads execute
440 *              the method concurrently. Emit a remark in this case.
441 *
442 ******************************************************************************/
443
444void
445MtCheckNamedObjectInMethod (
446    ACPI_PARSE_OBJECT       *Op,
447    ASL_METHOD_INFO         *MethodInfo)
448{
449    const ACPI_OPCODE_INFO  *OpInfo;
450
451
452    /* We don't care about actual method declarations */
453
454    if (Op->Asl.AmlOpcode == AML_METHOD_OP)
455    {
456        return;
457    }
458
459    /* Determine if we are creating a named object */
460
461    OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
462    if (OpInfo->Class == AML_CLASS_NAMED_OBJECT)
463    {
464        /*
465         * If we have a named object created within a non-serialized method,
466         * emit a remark that the method should be serialized.
467         *
468         * Reason: If a thread blocks within the method for any reason, and
469         * another thread enters the method, the method will fail because an
470         * attempt will be made to create the same object twice.
471         */
472        if (MethodInfo && !MethodInfo->ShouldBeSerialized)
473        {
474            AslError (ASL_REMARK, ASL_MSG_SERIALIZED_REQUIRED, MethodInfo->Op,
475                "due to creation of named objects within");
476
477            /* Emit message only ONCE per method */
478
479            MethodInfo->ShouldBeSerialized = TRUE;
480        }
481    }
482}
483
484
485/*******************************************************************************
486 *
487 * FUNCTION:    MtMethodAnalysisWalkEnd
488 *
489 * PARAMETERS:  ASL_WALK_CALLBACK
490 *
491 * RETURN:      Status
492 *
493 * DESCRIPTION: Ascending callback for analysis walk. Complete method
494 *              return analysis.
495 *
496 ******************************************************************************/
497
498ACPI_STATUS
499MtMethodAnalysisWalkEnd (
500    ACPI_PARSE_OBJECT       *Op,
501    UINT32                  Level,
502    void                    *Context)
503{
504    ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
505    ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack;
506
507
508    switch (Op->Asl.ParseOpcode)
509    {
510    case PARSEOP_METHOD:
511    case PARSEOP_RETURN:
512
513        if (!MethodInfo)
514        {
515            printf ("No method info for method! [%s]\n", Op->Asl.Namepath);
516            AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op,
517                "No method info for this method");
518
519            CmCleanupAndExit ();
520            return (AE_AML_INTERNAL);
521        }
522        break;
523
524    default:
525
526        break;
527    }
528
529    switch (Op->Asl.ParseOpcode)
530    {
531    case PARSEOP_METHOD:
532
533        WalkInfo->MethodStack = MethodInfo->Next;
534
535        /*
536         * Check if there is no return statement at the end of the
537         * method AND we can actually get there -- i.e., the execution
538         * of the method can possibly terminate without a return statement.
539         */
540        if ((!AnLastStatementIsReturn (Op)) &&
541            (!(Op->Asl.CompileFlags & NODE_HAS_NO_EXIT)))
542        {
543            /*
544             * No return statement, and execution can possibly exit
545             * via this path. This is equivalent to Return ()
546             */
547            MethodInfo->NumReturnNoValue++;
548        }
549
550        /*
551         * Check for case where some return statements have a return value
552         * and some do not. Exit without a return statement is a return with
553         * no value
554         */
555        if (MethodInfo->NumReturnNoValue &&
556            MethodInfo->NumReturnWithValue)
557        {
558            AslError (ASL_WARNING, ASL_MSG_RETURN_TYPES, Op,
559                Op->Asl.ExternalName);
560        }
561
562        /*
563         * If there are any RETURN() statements with no value, or there is a
564         * control path that allows the method to exit without a return value,
565         * we mark the method as a method that does not return a value. This
566         * knowledge can be used to check method invocations that expect a
567         * returned value.
568         */
569        if (MethodInfo->NumReturnNoValue)
570        {
571            if (MethodInfo->NumReturnWithValue)
572            {
573                Op->Asl.CompileFlags |= NODE_METHOD_SOME_NO_RETVAL;
574            }
575            else
576            {
577                Op->Asl.CompileFlags |= NODE_METHOD_NO_RETVAL;
578            }
579        }
580
581        /*
582         * Check predefined method names for correct return behavior
583         * and correct number of arguments. Also, some special checks
584         * For GPE and _REG methods.
585         */
586        if (ApCheckForPredefinedMethod (Op, MethodInfo))
587        {
588            /* Special check for two names like _L01 and _E01 in same scope */
589
590            ApCheckForGpeNameConflict (Op);
591
592            /*
593             * Special check for _REG: Must have an operation region definition
594             * within the same scope!
595             */
596            ApCheckRegMethod (Op);
597        }
598
599        ACPI_FREE (MethodInfo);
600        break;
601
602    case PARSEOP_NAME:
603
604         /* Special check for two names like _L01 and _E01 in same scope */
605
606        ApCheckForGpeNameConflict (Op);
607        break;
608
609    case PARSEOP_RETURN:
610
611        /*
612         * If the parent is a predefined method name, attempt to typecheck
613         * the return value. Only static types can be validated.
614         */
615        ApCheckPredefinedReturnValue (Op, MethodInfo);
616
617        /*
618         * The parent block does not "exit" and continue execution -- the
619         * method is terminated here with the Return() statement.
620         */
621        Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT;
622
623        /* Used in the "typing" pass later */
624
625        Op->Asl.ParentMethod = MethodInfo->Op;
626
627        /*
628         * If there is a peer node after the return statement, then this
629         * node is unreachable code -- i.e., it won't be executed because of
630         * the preceding Return() statement.
631         */
632        if (Op->Asl.Next)
633        {
634            AslError (ASL_WARNING, ASL_MSG_UNREACHABLE_CODE, Op->Asl.Next, NULL);
635        }
636        break;
637
638    case PARSEOP_IF:
639
640        if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) &&
641            (Op->Asl.Next) &&
642            (Op->Asl.Next->Asl.ParseOpcode == PARSEOP_ELSE))
643        {
644            /*
645             * This IF has a corresponding ELSE. The IF block has no exit,
646             * (it contains an unconditional Return)
647             * mark the ELSE block to remember this fact.
648             */
649            Op->Asl.Next->Asl.CompileFlags |= NODE_IF_HAS_NO_EXIT;
650        }
651        break;
652
653    case PARSEOP_ELSE:
654
655        if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) &&
656            (Op->Asl.CompileFlags & NODE_IF_HAS_NO_EXIT))
657        {
658            /*
659             * This ELSE block has no exit and the corresponding IF block
660             * has no exit either. Therefore, the parent node has no exit.
661             */
662            Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT;
663        }
664        break;
665
666
667    default:
668
669        if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) &&
670            (Op->Asl.Parent))
671        {
672            /* If this node has no exit, then the parent has no exit either */
673
674            Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT;
675        }
676        break;
677    }
678
679    return (AE_OK);
680}
681