Home | History | Annotate | Line # | Download | only in compiler
aslmethod.c revision 1.1.1.17
      1 /******************************************************************************
      2  *
      3  * Module Name: aslmethod.c - Control method analysis walk
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2021, 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 MERCHANTABILITY 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 "aslcompiler.h"
     45 #include "aslcompiler.y.h"
     46 #include "acnamesp.h"
     47 #include "acparser.h"
     48 #include "amlcode.h"
     49 
     50 
     51 #define _COMPONENT          ACPI_COMPILER
     52         ACPI_MODULE_NAME    ("aslmethod")
     53 
     54 
     55 /* Local prototypes */
     56 
     57 static void
     58 MtCheckNamedObjectInMethod (
     59     ACPI_PARSE_OBJECT       *Op,
     60     ASL_METHOD_INFO         *MethodInfo);
     61 
     62 static void
     63 MtCheckStaticOperationRegionInMethod (
     64     ACPI_PARSE_OBJECT       *Op);
     65 
     66 
     67 /*******************************************************************************
     68  *
     69  * FUNCTION:    MtMethodAnalysisWalkBegin
     70  *
     71  * PARAMETERS:  ASL_WALK_CALLBACK
     72  *
     73  * RETURN:      Status
     74  *
     75  * DESCRIPTION: Descending callback for the analysis walk. Check methods for:
     76  *              1) Initialized local variables
     77  *              2) Valid arguments
     78  *              3) Return types
     79  *
     80  ******************************************************************************/
     81 
     82 ACPI_STATUS
     83 MtMethodAnalysisWalkBegin (
     84     ACPI_PARSE_OBJECT       *Op,
     85     UINT32                  Level,
     86     void                    *Context)
     87 {
     88     ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
     89     ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack;
     90     ACPI_PARSE_OBJECT       *Next;
     91     UINT32                  RegisterNumber;
     92     UINT32                  i;
     93     char                    LocalName[] = "Local0";
     94     char                    ArgName[] = "Arg0";
     95     ACPI_PARSE_OBJECT       *ArgNode;
     96     ACPI_PARSE_OBJECT       *NextType;
     97     UINT8                   ActualArgs = 0;
     98     BOOLEAN                 HidExists;
     99     BOOLEAN                 AdrExists;
    100     BOOLEAN                 PrsExists;
    101     BOOLEAN                 CrsExists;
    102     BOOLEAN                 SrsExists;
    103     BOOLEAN                 DisExists;
    104 
    105 
    106     /* Build cross-reference output file if requested */
    107 
    108     if (AslGbl_CrossReferenceOutput)
    109     {
    110         OtXrefWalkPart1 (Op, Level, MethodInfo);
    111     }
    112 
    113     switch (Op->Asl.ParseOpcode)
    114     {
    115     case PARSEOP_METHOD:
    116 
    117         AslGbl_TotalMethods++;
    118 
    119         /* Create and init method info */
    120 
    121         MethodInfo = UtLocalCalloc (sizeof (ASL_METHOD_INFO));
    122         MethodInfo->Next = WalkInfo->MethodStack;
    123         MethodInfo->Op = Op;
    124 
    125         WalkInfo->MethodStack = MethodInfo;
    126 
    127         /*
    128          * Special handling for _PSx methods. Dependency rules (same scope):
    129          *
    130          * 1) _PS0 - One of these must exist: _PS1, _PS2, _PS3
    131          * 2) _PS1/_PS2/_PS3: A _PS0 must exist
    132          */
    133         if (ACPI_COMPARE_NAMESEG (METHOD_NAME__PS0, Op->Asl.NameSeg))
    134         {
    135             /* For _PS0, one of _PS1/_PS2/_PS3 must exist */
    136 
    137             if ((!ApFindNameInScope (METHOD_NAME__PS1, Op)) &&
    138                 (!ApFindNameInScope (METHOD_NAME__PS2, Op)) &&
    139                 (!ApFindNameInScope (METHOD_NAME__PS3, Op)))
    140             {
    141                 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
    142                     "_PS0 requires one of _PS1/_PS2/_PS3 in same scope");
    143             }
    144         }
    145         else if (
    146             ACPI_COMPARE_NAMESEG (METHOD_NAME__PS1, Op->Asl.NameSeg) ||
    147             ACPI_COMPARE_NAMESEG (METHOD_NAME__PS2, Op->Asl.NameSeg) ||
    148             ACPI_COMPARE_NAMESEG (METHOD_NAME__PS3, Op->Asl.NameSeg))
    149         {
    150             /* For _PS1/_PS2/_PS3, a _PS0 must exist */
    151 
    152             if (!ApFindNameInScope (METHOD_NAME__PS0, Op))
    153             {
    154                 sprintf (AslGbl_MsgBuffer,
    155                     "%4.4s requires _PS0 in same scope", Op->Asl.NameSeg);
    156 
    157                 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
    158                     AslGbl_MsgBuffer);
    159             }
    160         }
    161 
    162         /* Get the name node */
    163 
    164         Next = Op->Asl.Child;
    165 
    166         /* Get the NumArguments node */
    167 
    168         Next = Next->Asl.Next;
    169         MethodInfo->NumArguments = (UINT8)
    170             (((UINT8) Next->Asl.Value.Integer) & 0x07);
    171 
    172         /* Get the SerializeRule and SyncLevel nodes, ignored here */
    173 
    174         Next = Next->Asl.Next;
    175         MethodInfo->ShouldBeSerialized = (UINT8) Next->Asl.Value.Integer;
    176 
    177         Next = Next->Asl.Next;
    178         ArgNode = Next;
    179 
    180         /* Get the ReturnType node */
    181 
    182         Next = Next->Asl.Next;
    183 
    184         NextType = Next->Asl.Child;
    185 
    186         MethodInfo->ValidReturnTypes = MtProcessTypeOp (NextType);
    187         Op->Asl.AcpiBtype |= MethodInfo->ValidReturnTypes;
    188 
    189         /* Get the ParameterType node */
    190 
    191         Next = Next->Asl.Next;
    192 
    193         NextType = Next->Asl.Child;
    194         if (!NextType)
    195         {
    196             /*
    197              * The optional parameter types list was omitted  at the source
    198              * level. Use the Argument count parameter instead.
    199              */
    200             ActualArgs = MethodInfo->NumArguments;
    201         }
    202         else
    203         {
    204             ActualArgs = MtProcessParameterTypeList (NextType,
    205                 MethodInfo->ValidArgTypes);
    206             MethodInfo->NumArguments = ActualArgs;
    207             ArgNode->Asl.Value.Integer |= ActualArgs;
    208         }
    209 
    210         if ((MethodInfo->NumArguments) &&
    211             (MethodInfo->NumArguments != ActualArgs))
    212         {
    213             sprintf (AslGbl_MsgBuffer,
    214                 "Length = %u", ActualArgs);
    215             AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_MISMATCH,
    216                 Op->Asl.Child->Asl.Next, AslGbl_MsgBuffer);
    217         }
    218 
    219         /* Allow numarguments == 0 for Function() */
    220 
    221         if ((!MethodInfo->NumArguments) && (ActualArgs))
    222         {
    223             MethodInfo->NumArguments = ActualArgs;
    224             ArgNode->Asl.Value.Integer |= ActualArgs;
    225         }
    226 
    227         /*
    228          * Actual arguments are initialized at method entry.
    229          * All other ArgX "registers" can be used as locals, so we
    230          * track their initialization.
    231          */
    232         for (i = 0; i < MethodInfo->NumArguments; i++)
    233         {
    234             MethodInfo->ArgInitialized[i] = TRUE;
    235         }
    236         break;
    237 
    238     case PARSEOP_METHODCALL:
    239 
    240         /* Check for a recursive method call */
    241 
    242         if (MethodInfo &&
    243            (Op->Asl.Node == MethodInfo->Op->Asl.Node))
    244         {
    245             if (MethodInfo->CreatesNamedObjects)
    246             {
    247                 /*
    248                  * This is an error, as it will fail at runtime on all ACPI
    249                  * implementations. Any named object declarations will be
    250                  * executed twice, causing failure the second time. Note,
    251                  * this is independent of whether the method is declared
    252                  * Serialized, because the same thread is attempting to
    253                  * reenter the method, and this will always succeed.
    254                  */
    255                 AslDualParseOpError (ASL_ERROR, ASL_MSG_ILLEGAL_RECURSION, Op,
    256                     Op->Asl.Value.String, ASL_MSG_FOUND_HERE, MethodInfo->Op,
    257                     MethodInfo->Op->Asl.ExternalName);
    258             }
    259             else
    260             {
    261                 /* Method does not create objects, issue a remark */
    262 
    263                 AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName);
    264             }
    265         }
    266         break;
    267 
    268     case PARSEOP_LOCAL0:
    269     case PARSEOP_LOCAL1:
    270     case PARSEOP_LOCAL2:
    271     case PARSEOP_LOCAL3:
    272     case PARSEOP_LOCAL4:
    273     case PARSEOP_LOCAL5:
    274     case PARSEOP_LOCAL6:
    275     case PARSEOP_LOCAL7:
    276 
    277         if (!MethodInfo)
    278         {
    279             /*
    280              * Local was used outside a control method, or there was an error
    281              * in the method declaration.
    282              */
    283             AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD,
    284                 Op, Op->Asl.ExternalName);
    285             return (AE_ERROR);
    286         }
    287 
    288         RegisterNumber = (Op->Asl.AmlOpcode & 0x0007);
    289 
    290         /*
    291          * If the local is being used as a target, mark the local
    292          * initialized
    293          */
    294         if (Op->Asl.CompileFlags & OP_IS_TARGET)
    295         {
    296             MethodInfo->LocalInitialized[RegisterNumber] = TRUE;
    297         }
    298 
    299         /*
    300          * Otherwise, this is a reference, check if the local
    301          * has been previously initialized.
    302          *
    303          * The only operator that accepts an uninitialized value is ObjectType()
    304          */
    305         else if ((!MethodInfo->LocalInitialized[RegisterNumber]) &&
    306                  (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
    307         {
    308             LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30);
    309             AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName);
    310         }
    311         break;
    312 
    313     case PARSEOP_ARG0:
    314     case PARSEOP_ARG1:
    315     case PARSEOP_ARG2:
    316     case PARSEOP_ARG3:
    317     case PARSEOP_ARG4:
    318     case PARSEOP_ARG5:
    319     case PARSEOP_ARG6:
    320 
    321         if (!MethodInfo)
    322         {
    323             /*
    324              * Arg was used outside a control method, or there was an error
    325              * in the method declaration.
    326              */
    327             AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD,
    328                 Op, Op->Asl.ExternalName);
    329             return (AE_ERROR);
    330         }
    331 
    332         RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8;
    333         ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30);
    334 
    335         /*
    336          * If the Arg is being used as a target, mark the local
    337          * initialized
    338          */
    339         if (Op->Asl.CompileFlags & OP_IS_TARGET)
    340         {
    341             MethodInfo->ArgInitialized[RegisterNumber] = TRUE;
    342         }
    343 
    344         /*
    345          * Otherwise, this is a reference, check if the Arg
    346          * has been previously initialized.
    347          *
    348          * The only operator that accepts an uninitialized value is ObjectType()
    349          */
    350         else if ((!MethodInfo->ArgInitialized[RegisterNumber]) &&
    351             (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
    352         {
    353             AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName);
    354         }
    355 
    356         /* Flag this arg if it is not a "real" argument to the method */
    357 
    358         if (RegisterNumber >= MethodInfo->NumArguments)
    359         {
    360             AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName);
    361         }
    362         break;
    363 
    364     case PARSEOP_RETURN:
    365 
    366         if (!MethodInfo)
    367         {
    368             /*
    369              * Probably was an error in the method declaration,
    370              * no additional error here
    371              */
    372             ACPI_WARNING ((AE_INFO, "%p, No parent method", Op));
    373             return (AE_ERROR);
    374         }
    375 
    376         /*
    377          * A child indicates a possible return value. A simple Return or
    378          * Return() is marked with OP_IS_NULL_RETURN by the parser so
    379          * that it is not counted as a "real" return-with-value, although
    380          * the AML code that is actually emitted is Return(0). The AML
    381          * definition of Return has a required parameter, so we are
    382          * forced to convert a null return to Return(0).
    383          */
    384         if ((Op->Asl.Child) &&
    385             (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) &&
    386             (!(Op->Asl.Child->Asl.CompileFlags & OP_IS_NULL_RETURN)))
    387         {
    388             MethodInfo->NumReturnWithValue++;
    389         }
    390         else
    391         {
    392             MethodInfo->NumReturnNoValue++;
    393         }
    394         break;
    395 
    396     case PARSEOP_BREAK:
    397     case PARSEOP_CONTINUE:
    398 
    399         Next = Op->Asl.Parent;
    400         while (Next)
    401         {
    402             if (Next->Asl.ParseOpcode == PARSEOP_WHILE)
    403             {
    404                 break;
    405             }
    406             Next = Next->Asl.Parent;
    407         }
    408 
    409         if (!Next)
    410         {
    411             AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL);
    412         }
    413         break;
    414 
    415     case PARSEOP_STALL:
    416 
    417         /* We can range check if the argument is an integer */
    418 
    419         if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) &&
    420             (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX))
    421         {
    422             AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL);
    423         }
    424         break;
    425 
    426     case PARSEOP_DEVICE:
    427 
    428         /* Check usage of _HID and _ADR objects */
    429 
    430         HidExists = ApFindNameInDeviceTree (METHOD_NAME__HID, Op);
    431         AdrExists = ApFindNameInDeviceTree (METHOD_NAME__ADR, Op);
    432 
    433         if (!HidExists && !AdrExists)
    434         {
    435             AslError (ASL_ERROR, ASL_MSG_MISSING_DEPENDENCY, Op,
    436                 "Device object requires a _HID or _ADR");
    437         }
    438         else if (HidExists && AdrExists)
    439         {
    440             /*
    441              * According to the ACPI spec, "A device object must contain
    442              * either an _HID object or an _ADR object, but should not contain
    443              * both".
    444              */
    445             AslError (ASL_WARNING, ASL_MSG_MULTIPLE_TYPES, Op,
    446                 "Device object requires either a _HID or _ADR, but not both");
    447         }
    448 
    449         /*
    450          * Check usage of _CRS, _DIS, _PRS, and _SRS objects (July 2021).
    451          *
    452          * Under the Device Object:
    453          *
    454          * 1) If _PRS present, must have _CRS and _SRS
    455          * 2) If _SRS present, must have _PRS (_PRS requires _CRS and _SRS)
    456          * 3) If _DIS present, must have _SRS (_SRS requires _PRS, _PRS requires _CRS and _SRS)
    457          * 4) If _SRS present, probably should have a _DIS (Remark only)
    458          */
    459         CrsExists = ApFindNameInDeviceTree (METHOD_NAME__CRS, Op);
    460         DisExists = ApFindNameInDeviceTree (METHOD_NAME__DIS, Op);
    461         PrsExists = ApFindNameInDeviceTree (METHOD_NAME__PRS, Op);
    462         SrsExists = ApFindNameInDeviceTree (METHOD_NAME__SRS, Op);
    463 
    464         /* 1) If _PRS is present, must have a _CRS and _SRS */
    465 
    466         if (PrsExists)
    467         {
    468             if (!CrsExists)
    469             {
    470                 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
    471                     "Device has a _PRS, missing a _CRS, required");
    472             }
    473             if (!SrsExists)
    474             {
    475                 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
    476                     "Device has a _PRS, missing a _SRS, required");
    477             }
    478         }
    479 
    480         /* 2) If _SRS is present, must have _PRS (_PRS requires _CRS and _SRS) */
    481 
    482         if ((SrsExists) && (!PrsExists))
    483         {
    484             AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
    485                 "Device has a _SRS, missing a _PRS, required");
    486         }
    487 
    488         /* 3) If _DIS is present, must have a _SRS */
    489 
    490         if ((DisExists) && (!SrsExists))
    491         {
    492             AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
    493                 "Device has a _DIS, missing a _SRS, required");
    494         }
    495 
    496         /*
    497          * 4) If _SRS is present, should have a _DIS (_PRS requires _CRS
    498          * and _SRS)  Remark only.
    499          */
    500         if ((SrsExists) && (!DisExists))
    501         {
    502             AslError (ASL_REMARK, ASL_MSG_MISSING_DEPENDENCY, Op,
    503                 "Device has a _SRS, no corresponding _DIS");
    504         }
    505         break;
    506 
    507     case PARSEOP_EVENT:
    508     case PARSEOP_MUTEX:
    509     case PARSEOP_OPERATIONREGION:
    510     case PARSEOP_POWERRESOURCE:
    511     case PARSEOP_PROCESSOR:
    512     case PARSEOP_THERMALZONE:
    513 
    514         /*
    515          * The first operand is a name to be created in the namespace.
    516          * Check against the reserved list.
    517          */
    518         i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg);
    519         if (i < ACPI_VALID_RESERVED_NAME_MAX)
    520         {
    521             AslError (ASL_ERROR, ASL_MSG_RESERVED_USE,
    522                 Op, Op->Asl.ExternalName);
    523         }
    524 
    525         MtCheckStaticOperationRegionInMethod (Op);
    526         break;
    527 
    528     case PARSEOP_NAME:
    529 
    530         /* Typecheck any predefined names statically defined with Name() */
    531 
    532         ApCheckForPredefinedObject (Op, Op->Asl.NameSeg);
    533 
    534         /* Special typechecking for _HID */
    535 
    536         if (ACPI_COMPARE_NAMESEG (METHOD_NAME__HID, Op->Asl.NameSeg))
    537         {
    538             Next = Op->Asl.Child->Asl.Next;
    539             AnCheckId (Next, ASL_TYPE_HID);
    540         }
    541 
    542         /* Special typechecking for _CID */
    543 
    544         else if (ACPI_COMPARE_NAMESEG (METHOD_NAME__CID, Op->Asl.NameSeg))
    545         {
    546             Next = Op->Asl.Child->Asl.Next;
    547 
    548             if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
    549                 (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE))
    550             {
    551                 Next = Next->Asl.Child;
    552                 while (Next)
    553                 {
    554                     AnCheckId (Next, ASL_TYPE_CID);
    555                     Next = Next->Asl.Next;
    556                 }
    557             }
    558             else
    559             {
    560                 AnCheckId (Next, ASL_TYPE_CID);
    561             }
    562         }
    563 
    564         break;
    565 
    566     default:
    567 
    568         break;
    569     }
    570 
    571     /* Check for named object creation within a non-serialized method */
    572 
    573     MtCheckNamedObjectInMethod (Op, MethodInfo);
    574     return (AE_OK);
    575 }
    576 
    577 
    578 /*******************************************************************************
    579  *
    580  * FUNCTION:    MtProcessTypeOp
    581  *
    582  * PARAMETERS:  Op                  - Op representing a btype
    583  *
    584  * RETURN:      Btype represented by Op
    585  *
    586  * DESCRIPTION: Process a parse object that represents single parameter type or
    587  *              a return type in method, function, and external declarations.
    588  *
    589  ******************************************************************************/
    590 
    591 UINT32
    592 MtProcessTypeOp (
    593     ACPI_PARSE_OBJECT       *TypeOp)
    594 {
    595     UINT32                  Btype = ACPI_BTYPE_ANY;
    596 
    597 
    598     while (TypeOp)
    599     {
    600         Btype |= AnMapObjTypeToBtype (TypeOp);
    601         TypeOp->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
    602         TypeOp = TypeOp->Asl.Next;
    603     }
    604 
    605     return (Btype);
    606 }
    607 
    608 
    609 /*******************************************************************************
    610  *
    611  * FUNCTION:    MtProcessParameterTypeList
    612  *
    613  * PARAMETERS:  Op                  - Op representing a btype
    614  *
    615  * RETURN:      Btype represented by Op
    616  *
    617  * DESCRIPTION: Process a parse object that represents a parameter type list in
    618  *              method, function, and external declarations.
    619  *
    620  ******************************************************************************/
    621 
    622 UINT8
    623 MtProcessParameterTypeList (
    624     ACPI_PARSE_OBJECT       *ParamTypeOp,
    625     UINT32                  *TypeList)
    626 {
    627     UINT8                   ParameterCount = 0;
    628 
    629 
    630     if (ParamTypeOp && ParamTypeOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)
    631     {
    632         /* Special case for a single parameter without braces */
    633 
    634         TypeList[ParameterCount] =
    635             MtProcessTypeOp (ParamTypeOp);
    636 
    637         return (1);
    638     }
    639 
    640     while (ParamTypeOp)
    641     {
    642         TypeList[ParameterCount] =
    643             MtProcessTypeOp (ParamTypeOp->Asl.Child);
    644 
    645         ParameterCount++;
    646         ParamTypeOp = ParamTypeOp->Asl.Next;
    647     }
    648 
    649     return (ParameterCount);
    650 }
    651 
    652 
    653 /*******************************************************************************
    654  *
    655  * FUNCTION:    MtCheckNamedObjectInMethod
    656  *
    657  * PARAMETERS:  Op                  - Current parser op
    658  *              MethodInfo          - Info for method being parsed
    659  *
    660  * RETURN:      None
    661  *
    662  * DESCRIPTION: Detect if a non-serialized method is creating a named object,
    663  *              which could possibly cause problems if two threads execute
    664  *              the method concurrently. Emit a remark in this case.
    665  *
    666  ******************************************************************************/
    667 
    668 static void
    669 MtCheckNamedObjectInMethod (
    670     ACPI_PARSE_OBJECT       *Op,
    671     ASL_METHOD_INFO         *MethodInfo)
    672 {
    673     const ACPI_OPCODE_INFO  *OpInfo;
    674     char                    *ExternalPath;
    675 
    676 
    677     /* We don't care about actual method declarations or scopes */
    678 
    679     if ((Op->Asl.AmlOpcode == AML_METHOD_OP) ||
    680         (Op->Asl.AmlOpcode == AML_SCOPE_OP))
    681     {
    682         return;
    683     }
    684 
    685     /* Determine if we are creating a named object within a method */
    686 
    687     if (!MethodInfo)
    688     {
    689         return;
    690     }
    691 
    692     OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
    693     if ((OpInfo->Class == AML_CLASS_NAMED_OBJECT) && (Op->Asl.AmlOpcode != AML_FIELD_OP))
    694     {
    695         /*
    696          * 1) Mark the method as a method that creates named objects.
    697          *
    698          * 2) Issue a remark indicating the inefficiency of creating named
    699          * objects within a method (Except for compiler-emitted temporary
    700          * variables).
    701          *
    702          * 3) If the method is non-serialized, emit a remark that the method
    703          * should be serialized.
    704          *
    705          * Reason: If a thread blocks within the method for any reason, and
    706          * another thread enters the method, the method will fail because
    707          * an attempt will be made to create the same object twice.
    708          *
    709          * Note: The Field opcode is disallowed here because Field() does not
    710          * create a new named object.
    711          */
    712         ExternalPath = AcpiNsGetNormalizedPathname (MethodInfo->Op->Asl.Node, TRUE);
    713 
    714         /* No error for compiler temp variables (name starts with "_T_") */
    715 
    716         if ((Op->Asl.NameSeg[0] != '_') &&
    717             (Op->Asl.NameSeg[1] != 'T') &&
    718             (Op->Asl.NameSeg[2] != '_'))
    719         {
    720             AslError (ASL_REMARK, ASL_MSG_NAMED_OBJECT_CREATION, Op,
    721                 ExternalPath);
    722         }
    723 
    724         MethodInfo->CreatesNamedObjects = TRUE;
    725         if (!MethodInfo->ShouldBeSerialized)
    726         {
    727             AslError (ASL_REMARK, ASL_MSG_SERIALIZED_REQUIRED, MethodInfo->Op,
    728                 ExternalPath);
    729 
    730             /* Emit message only ONCE per method */
    731 
    732             MethodInfo->ShouldBeSerialized = TRUE;
    733         }
    734 
    735         if (ExternalPath)
    736         {
    737             ACPI_FREE (ExternalPath);
    738         }
    739     }
    740 }
    741 
    742 
    743 /*******************************************************************************
    744  *
    745  * FUNCTION:    MtCheckStaticOperationRegionInMethod
    746  *
    747  * PARAMETERS:  Op                  - Current parser op
    748  *
    749  * RETURN:      None
    750  *
    751  * DESCRIPTION: Warns if an Operation Region with static address or length
    752  *              is declared inside a control method
    753  *
    754  ******************************************************************************/
    755 
    756 static void
    757 MtCheckStaticOperationRegionInMethod(
    758     ACPI_PARSE_OBJECT*       Op)
    759 {
    760     ACPI_PARSE_OBJECT*       AddressOp;
    761     ACPI_PARSE_OBJECT*       LengthOp;
    762 
    763 
    764     if (Op->Asl.ParseOpcode != PARSEOP_OPERATIONREGION)
    765     {
    766         return;
    767     }
    768 
    769     /*
    770      * OperationRegion should have 4 arguments defined. At this point, we
    771      * assume that the parse tree is well-formed.
    772      */
    773     AddressOp = Op->Asl.Child->Asl.Next->Asl.Next;
    774     LengthOp = Op->Asl.Child->Asl.Next->Asl.Next->Asl.Next;
    775 
    776     if (UtGetParentMethodOp (Op) &&
    777         AddressOp->Asl.ParseOpcode == PARSEOP_INTEGER &&
    778         LengthOp->Asl.ParseOpcode == PARSEOP_INTEGER)
    779     {
    780         /*
    781          * At this point, a static operation region declared inside of a
    782          * control method has been found. Throw a warning because this is
    783          * highly inefficient.
    784          */
    785         AslError(ASL_WARNING, ASL_MSG_STATIC_OPREGION_IN_METHOD, Op, NULL);
    786     }
    787 
    788     return;
    789 }
    790 
    791 
    792 /*******************************************************************************
    793  *
    794  * FUNCTION:    MtMethodAnalysisWalkEnd
    795  *
    796  * PARAMETERS:  ASL_WALK_CALLBACK
    797  *
    798  * RETURN:      Status
    799  *
    800  * DESCRIPTION: Ascending callback for analysis walk. Complete method
    801  *              return analysis.
    802  *
    803  ******************************************************************************/
    804 
    805 ACPI_STATUS
    806 MtMethodAnalysisWalkEnd (
    807     ACPI_PARSE_OBJECT       *Op,
    808     UINT32                  Level,
    809     void                    *Context)
    810 {
    811     ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
    812     ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack;
    813     char                    *ExternalPath;
    814 
    815 
    816     switch (Op->Asl.ParseOpcode)
    817     {
    818     case PARSEOP_METHOD:
    819     case PARSEOP_RETURN:
    820 
    821         if (!MethodInfo)
    822         {
    823             printf ("No method info for method! [%s]\n", Op->Asl.Namepath);
    824             AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op,
    825                 "No method info for this method");
    826 
    827             CmCleanupAndExit ();
    828             return (AE_AML_INTERNAL);
    829         }
    830         break;
    831 
    832     default:
    833 
    834         break;
    835     }
    836 
    837     switch (Op->Asl.ParseOpcode)
    838     {
    839     case PARSEOP_METHOD:
    840 
    841         WalkInfo->MethodStack = MethodInfo->Next;
    842 
    843         /*
    844          * Check if there is no return statement at the end of the
    845          * method AND we can actually get there -- i.e., the execution
    846          * of the method can possibly terminate without a return statement.
    847          */
    848         if ((!AnLastStatementIsReturn (Op)) &&
    849             (!(Op->Asl.CompileFlags & OP_HAS_NO_EXIT)))
    850         {
    851             /*
    852              * No return statement, and execution can possibly exit
    853              * via this path. This is equivalent to Return ()
    854              */
    855             MethodInfo->NumReturnNoValue++;
    856         }
    857 
    858         /*
    859          * Check for case where some return statements have a return value
    860          * and some do not. Exit without a return statement is a return with
    861          * no value
    862          */
    863         if (MethodInfo->NumReturnNoValue &&
    864             MethodInfo->NumReturnWithValue)
    865         {
    866             ExternalPath = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE);
    867 
    868             AslError (ASL_WARNING, ASL_MSG_RETURN_TYPES, Op,
    869                 ExternalPath);
    870 
    871             if (ExternalPath)
    872             {
    873                 ACPI_FREE (ExternalPath);
    874             }
    875         }
    876 
    877         /*
    878          * If there are any RETURN() statements with no value, or there is a
    879          * control path that allows the method to exit without a return value,
    880          * we mark the method as a method that does not return a value. This
    881          * knowledge can be used to check method invocations that expect a
    882          * returned value.
    883          */
    884         if (MethodInfo->NumReturnNoValue)
    885         {
    886             if (MethodInfo->NumReturnWithValue)
    887             {
    888                 Op->Asl.CompileFlags |= OP_METHOD_SOME_NO_RETVAL;
    889             }
    890             else
    891             {
    892                 Op->Asl.CompileFlags |= OP_METHOD_NO_RETVAL;
    893             }
    894         }
    895 
    896         /*
    897          * Check predefined method names for correct return behavior
    898          * and correct number of arguments. Also, some special checks
    899          * For GPE and _REG methods.
    900          */
    901         if (ApCheckForPredefinedMethod (Op, MethodInfo))
    902         {
    903             /* Special check for two names like _L01 and _E01 in same scope */
    904 
    905             ApCheckForGpeNameConflict (Op);
    906 
    907             /*
    908              * Special check for _REG: Must have an operation region definition
    909              * within the same scope!
    910              */
    911             ApCheckRegMethod (Op);
    912         }
    913 
    914         ACPI_FREE (MethodInfo);
    915         break;
    916 
    917     case PARSEOP_NAME:
    918 
    919          /* Special check for two names like _L01 and _E01 in same scope */
    920 
    921         ApCheckForGpeNameConflict (Op);
    922         break;
    923 
    924     case PARSEOP_RETURN:
    925 
    926         /*
    927          * If the parent is a predefined method name, attempt to typecheck
    928          * the return value. Only static types can be validated.
    929          */
    930         ApCheckPredefinedReturnValue (Op, MethodInfo);
    931 
    932         /*
    933          * The parent block does not "exit" and continue execution -- the
    934          * method is terminated here with the Return() statement.
    935          */
    936         Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
    937 
    938         /* Used in the "typing" pass later */
    939 
    940         Op->Asl.ParentMethod = MethodInfo->Op;
    941 
    942         /*
    943          * If there is a peer node after the return statement, then this
    944          * node is unreachable code -- i.e., it won't be executed because of
    945          * the preceding Return() statement.
    946          */
    947         if (Op->Asl.Next)
    948         {
    949             AslError (ASL_WARNING, ASL_MSG_UNREACHABLE_CODE,
    950                 Op->Asl.Next, NULL);
    951         }
    952         break;
    953 
    954     case PARSEOP_IF:
    955 
    956         if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
    957             (Op->Asl.Next) &&
    958             (Op->Asl.Next->Asl.ParseOpcode == PARSEOP_ELSE))
    959         {
    960             /*
    961              * This IF has a corresponding ELSE. The IF block has no exit,
    962              * (it contains an unconditional Return)
    963              * mark the ELSE block to remember this fact.
    964              */
    965             Op->Asl.Next->Asl.CompileFlags |= OP_IF_HAS_NO_EXIT;
    966         }
    967         break;
    968 
    969     case PARSEOP_ELSE:
    970 
    971         if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
    972             (Op->Asl.CompileFlags & OP_IF_HAS_NO_EXIT))
    973         {
    974             /*
    975              * This ELSE block has no exit and the corresponding IF block
    976              * has no exit either. Therefore, the parent node has no exit.
    977              */
    978             Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
    979         }
    980         break;
    981 
    982 
    983     default:
    984 
    985         if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
    986             (Op->Asl.Parent))
    987         {
    988             /* If this node has no exit, then the parent has no exit either */
    989 
    990             Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
    991         }
    992         break;
    993     }
    994 
    995     return (AE_OK);
    996 }
    997