Home | History | Annotate | Line # | Download | only in compiler
aslanalyze.c revision 1.1.1.3
      1 /******************************************************************************
      2  *
      3  * Module Name: aslanalyze.c - Support functions for parse tree walks
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2011, 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 "aslcompiler.h"
     46 #include "aslcompiler.y.h"
     47 #include <string.h>
     48 
     49 
     50 #define _COMPONENT          ACPI_COMPILER
     51         ACPI_MODULE_NAME    ("aslanalyze")
     52 
     53 
     54 /*******************************************************************************
     55  *
     56  * FUNCTION:    AnIsInternalMethod
     57  *
     58  * PARAMETERS:  Op                  - Current op
     59  *
     60  * RETURN:      Boolean
     61  *
     62  * DESCRIPTION: Check for an internal control method.
     63  *
     64  ******************************************************************************/
     65 
     66 BOOLEAN
     67 AnIsInternalMethod (
     68     ACPI_PARSE_OBJECT       *Op)
     69 {
     70 
     71     if ((!ACPI_STRCMP (Op->Asl.ExternalName, "\\_OSI")) ||
     72         (!ACPI_STRCMP (Op->Asl.ExternalName, "_OSI")))
     73     {
     74         return (TRUE);
     75     }
     76 
     77     return (FALSE);
     78 }
     79 
     80 
     81 /*******************************************************************************
     82  *
     83  * FUNCTION:    AnGetInternalMethodReturnType
     84  *
     85  * PARAMETERS:  Op                  - Current op
     86  *
     87  * RETURN:      Btype
     88  *
     89  * DESCRIPTION: Get the return type of an internal method
     90  *
     91  ******************************************************************************/
     92 
     93 UINT32
     94 AnGetInternalMethodReturnType (
     95     ACPI_PARSE_OBJECT       *Op)
     96 {
     97 
     98     if ((!ACPI_STRCMP (Op->Asl.ExternalName, "\\_OSI")) ||
     99         (!ACPI_STRCMP (Op->Asl.ExternalName, "_OSI")))
    100     {
    101         return (ACPI_BTYPE_STRING);
    102     }
    103 
    104     return (0);
    105 }
    106 
    107 
    108 /*******************************************************************************
    109  *
    110  * FUNCTION:    AnCheckId
    111  *
    112  * PARAMETERS:  Op                  - Current parse op
    113  *              Type                - HID or CID
    114  *
    115  * RETURN:      None
    116  *
    117  * DESCRIPTION: Perform various checks on _HID and _CID strings. Only limited
    118  *              checks can be performed on _CID strings.
    119  *
    120  ******************************************************************************/
    121 
    122 void
    123 AnCheckId (
    124     ACPI_PARSE_OBJECT       *Op,
    125     ACPI_NAME               Type)
    126 {
    127     UINT32                  i;
    128     ACPI_SIZE               Length;
    129     UINT32                  AlphaPrefixLength;
    130 
    131 
    132     /* Only care about string versions of _HID/_CID (integers are legal) */
    133 
    134     if (Op->Asl.ParseOpcode != PARSEOP_STRING_LITERAL)
    135     {
    136         return;
    137     }
    138 
    139     /* For both _HID and _CID, the string must be non-null */
    140 
    141     Length = strlen (Op->Asl.Value.String);
    142     if (!Length)
    143     {
    144         AslError (ASL_ERROR, ASL_MSG_NULL_STRING,
    145             Op, NULL);
    146         return;
    147     }
    148 
    149     /*
    150      * One of the things we want to catch here is the use of a leading
    151      * asterisk in the string -- an odd construct that certain platform
    152      * manufacturers are fond of. Technically, a leading asterisk is OK
    153      * for _CID, but a valid use of this has not been seen.
    154      */
    155     if (*Op->Asl.Value.String == '*')
    156     {
    157         AslError (ASL_ERROR, ASL_MSG_LEADING_ASTERISK,
    158             Op, Op->Asl.Value.String);
    159         return;
    160     }
    161 
    162     /* _CID strings are bus-specific, no more checks can be performed */
    163 
    164     if (Type == ASL_TYPE_CID)
    165     {
    166         return;
    167     }
    168 
    169     /* For _HID, all characters must be alphanumeric */
    170 
    171     for (i = 0; Op->Asl.Value.String[i]; i++)
    172     {
    173         if (!isalnum ((int) Op->Asl.Value.String[i]))
    174         {
    175             AslError (ASL_ERROR, ASL_MSG_ALPHANUMERIC_STRING,
    176                 Op, Op->Asl.Value.String);
    177             break;
    178         }
    179     }
    180 
    181     /* _HID String must be of the form "XXX####" or "ACPI####" */
    182 
    183     if ((Length < 7) || (Length > 8))
    184     {
    185         AslError (ASL_ERROR, ASL_MSG_HID_LENGTH,
    186             Op, Op->Asl.Value.String);
    187         return;
    188     }
    189 
    190     /* _HID Length is valid, now check for uppercase (first 3 or 4 chars) */
    191 
    192     AlphaPrefixLength = 3;
    193     if (Length >= 8)
    194     {
    195         AlphaPrefixLength = 4;
    196     }
    197 
    198     /* Ensure the alphabetic prefix is all uppercase */
    199 
    200     for (i = 0; (i < AlphaPrefixLength) && Op->Asl.Value.String[i]; i++)
    201     {
    202         if (!isupper ((int) Op->Asl.Value.String[i]))
    203         {
    204             AslError (ASL_ERROR, ASL_MSG_UPPER_CASE,
    205                 Op, &Op->Asl.Value.String[i]);
    206             break;
    207         }
    208     }
    209 }
    210 
    211 
    212 /*******************************************************************************
    213  *
    214  * FUNCTION:    AnLastStatementIsReturn
    215  *
    216  * PARAMETERS:  Op                  - A method parse node
    217  *
    218  * RETURN:      TRUE if last statement is an ASL RETURN. False otherwise
    219  *
    220  * DESCRIPTION: Walk down the list of top level statements within a method
    221  *              to find the last one. Check if that last statement is in
    222  *              fact a RETURN statement.
    223  *
    224  ******************************************************************************/
    225 
    226 BOOLEAN
    227 AnLastStatementIsReturn (
    228     ACPI_PARSE_OBJECT       *Op)
    229 {
    230     ACPI_PARSE_OBJECT       *Next;
    231 
    232 
    233     /* Check if last statement is a return */
    234 
    235     Next = ASL_GET_CHILD_NODE (Op);
    236     while (Next)
    237     {
    238         if ((!Next->Asl.Next) &&
    239             (Next->Asl.ParseOpcode == PARSEOP_RETURN))
    240         {
    241             return (TRUE);
    242         }
    243 
    244         Next = ASL_GET_PEER_NODE (Next);
    245     }
    246 
    247     return (FALSE);
    248 }
    249 
    250 
    251 /*******************************************************************************
    252  *
    253  * FUNCTION:    AnCheckMethodReturnValue
    254  *
    255  * PARAMETERS:  Op                  - Parent
    256  *              OpInfo              - Parent info
    257  *              ArgOp               - Method invocation op
    258  *              RequiredBtypes      - What caller requires
    259  *              ThisNodeBtype       - What this node returns (if anything)
    260  *
    261  * RETURN:      None
    262  *
    263  * DESCRIPTION: Check a method invocation for 1) A return value and if it does
    264  *              in fact return a value, 2) check the type of the return value.
    265  *
    266  ******************************************************************************/
    267 
    268 void
    269 AnCheckMethodReturnValue (
    270     ACPI_PARSE_OBJECT       *Op,
    271     const ACPI_OPCODE_INFO  *OpInfo,
    272     ACPI_PARSE_OBJECT       *ArgOp,
    273     UINT32                  RequiredBtypes,
    274     UINT32                  ThisNodeBtype)
    275 {
    276     ACPI_PARSE_OBJECT       *OwningOp;
    277     ACPI_NAMESPACE_NODE     *Node;
    278 
    279 
    280     Node = ArgOp->Asl.Node;
    281 
    282 
    283     /* Examine the parent op of this method */
    284 
    285     OwningOp = Node->Op;
    286     if (OwningOp->Asl.CompileFlags & NODE_METHOD_NO_RETVAL)
    287     {
    288         /* Method NEVER returns a value */
    289 
    290         AslError (ASL_ERROR, ASL_MSG_NO_RETVAL, Op, Op->Asl.ExternalName);
    291     }
    292     else if (OwningOp->Asl.CompileFlags & NODE_METHOD_SOME_NO_RETVAL)
    293     {
    294         /* Method SOMETIMES returns a value, SOMETIMES not */
    295 
    296         AslError (ASL_WARNING, ASL_MSG_SOME_NO_RETVAL, Op, Op->Asl.ExternalName);
    297     }
    298     else if (!(ThisNodeBtype & RequiredBtypes))
    299     {
    300         /* Method returns a value, but the type is wrong */
    301 
    302         AnFormatBtype (StringBuffer, ThisNodeBtype);
    303         AnFormatBtype (StringBuffer2, RequiredBtypes);
    304 
    305         /*
    306          * The case where the method does not return any value at all
    307          * was already handled in the namespace cross reference
    308          * -- Only issue an error if the method in fact returns a value,
    309          * but it is of the wrong type
    310          */
    311         if (ThisNodeBtype != 0)
    312         {
    313             sprintf (MsgBuffer,
    314                 "Method returns [%s], %s operator requires [%s]",
    315                 StringBuffer, OpInfo->Name, StringBuffer2);
    316 
    317             AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, MsgBuffer);
    318         }
    319     }
    320 }
    321 
    322 
    323 /*******************************************************************************
    324  *
    325  * FUNCTION:    AnIsResultUsed
    326  *
    327  * PARAMETERS:  Op                  - Parent op for the operator
    328  *
    329  * RETURN:      TRUE if result from this operation is actually consumed
    330  *
    331  * DESCRIPTION: Determine if the function result value from an operator is
    332  *              used.
    333  *
    334  ******************************************************************************/
    335 
    336 BOOLEAN
    337 AnIsResultUsed (
    338     ACPI_PARSE_OBJECT       *Op)
    339 {
    340     ACPI_PARSE_OBJECT       *Parent;
    341 
    342 
    343     switch (Op->Asl.ParseOpcode)
    344     {
    345     case PARSEOP_INCREMENT:
    346     case PARSEOP_DECREMENT:
    347 
    348         /* These are standalone operators, no return value */
    349 
    350         return (TRUE);
    351 
    352     default:
    353         break;
    354     }
    355 
    356     /* Examine parent to determine if the return value is used */
    357 
    358     Parent = Op->Asl.Parent;
    359     switch (Parent->Asl.ParseOpcode)
    360     {
    361     /* If/While - check if the operator is the predicate */
    362 
    363     case PARSEOP_IF:
    364     case PARSEOP_WHILE:
    365 
    366         /* First child is the predicate */
    367 
    368         if (Parent->Asl.Child == Op)
    369         {
    370             return (TRUE);
    371         }
    372         return (FALSE);
    373 
    374     /* Not used if one of these is the parent */
    375 
    376     case PARSEOP_METHOD:
    377     case PARSEOP_DEFINITIONBLOCK:
    378     case PARSEOP_ELSE:
    379 
    380         return (FALSE);
    381 
    382     default:
    383         /* Any other type of parent means that the result is used */
    384 
    385         return (TRUE);
    386     }
    387 }
    388 
    389 
    390 /*******************************************************************************
    391  *
    392  * FUNCTION:    ApCheckForGpeNameConflict
    393  *
    394  * PARAMETERS:  Op                  - Current parse op
    395  *
    396  * RETURN:      None
    397  *
    398  * DESCRIPTION: Check for a conflict between GPE names within this scope.
    399  *              Conflict means two GPE names with the same GPE number, but
    400  *              different types -- such as _L1C and _E1C.
    401  *
    402  ******************************************************************************/
    403 
    404 void
    405 ApCheckForGpeNameConflict (
    406     ACPI_PARSE_OBJECT       *Op)
    407 {
    408     ACPI_PARSE_OBJECT       *NextOp;
    409     UINT32                  GpeNumber;
    410     char                    Name[ACPI_NAME_SIZE + 1];
    411     char                    Target[ACPI_NAME_SIZE];
    412 
    413 
    414     /* Need a null-terminated string version of NameSeg */
    415 
    416     ACPI_MOVE_32_TO_32 (Name, &Op->Asl.NameSeg);
    417     Name[ACPI_NAME_SIZE] = 0;
    418 
    419     /*
    420      * For a GPE method:
    421      * 1st char must be underscore
    422      * 2nd char must be L or E
    423      * 3rd/4th chars must be a hex number
    424      */
    425     if ((Name[0] != '_') ||
    426        ((Name[1] != 'L') && (Name[1] != 'E')))
    427     {
    428         return;
    429     }
    430 
    431     /* Verify 3rd/4th chars are a valid hex value */
    432 
    433     GpeNumber = ACPI_STRTOUL (&Name[2], NULL, 16);
    434     if (GpeNumber == ACPI_UINT32_MAX)
    435     {
    436         return;
    437     }
    438 
    439     /*
    440      * We are now sure we have an _Lxx or _Exx.
    441      * Create the target name that would cause collision (Flip E/L)
    442      */
    443     ACPI_MOVE_32_TO_32 (Target, Name);
    444 
    445     /* Inject opposite letter ("L" versus "E") */
    446 
    447     if (Name[1] == 'L')
    448     {
    449         Target[1] = 'E';
    450     }
    451     else /* Name[1] == 'E' */
    452     {
    453         Target[1] = 'L';
    454     }
    455 
    456     /* Search all peers (objects within this scope) for target match */
    457 
    458     NextOp = Op->Asl.Next;
    459     while (NextOp)
    460     {
    461         /*
    462          * We mostly care about methods, but check Name() constructs also,
    463          * even though they will get another error for not being a method.
    464          * All GPE names must be defined as control methods.
    465          */
    466         if ((NextOp->Asl.ParseOpcode == PARSEOP_METHOD) ||
    467             (NextOp->Asl.ParseOpcode == PARSEOP_NAME))
    468         {
    469             if (ACPI_COMPARE_NAME (Target, NextOp->Asl.NameSeg))
    470             {
    471                 /* Found both _Exy and _Lxy in the same scope, error */
    472 
    473                 AslError (ASL_ERROR, ASL_MSG_GPE_NAME_CONFLICT, NextOp,
    474                     Name);
    475                 return;
    476             }
    477         }
    478 
    479         NextOp = NextOp->Asl.Next;
    480     }
    481 
    482     /* OK, no conflict found */
    483 
    484     return;
    485 }
    486 
    487 
    488 /*******************************************************************************
    489  *
    490  * FUNCTION:    ApCheckRegMethod
    491  *
    492  * PARAMETERS:  Op                  - Current parse op
    493  *
    494  * RETURN:      None
    495  *
    496  * DESCRIPTION: Ensure that a _REG method has a corresponding Operation
    497  *              Region declaration within the same scope. Note: _REG is defined
    498  *              to have two arguments and must therefore be defined as a
    499  *              control method.
    500  *
    501  ******************************************************************************/
    502 
    503 void
    504 ApCheckRegMethod (
    505     ACPI_PARSE_OBJECT       *Op)
    506 {
    507     ACPI_PARSE_OBJECT       *Next;
    508     ACPI_PARSE_OBJECT       *Parent;
    509 
    510 
    511     /* We are only interested in _REG methods */
    512 
    513     if (!ACPI_COMPARE_NAME (METHOD_NAME__REG, &Op->Asl.NameSeg))
    514     {
    515         return;
    516     }
    517 
    518     /* Get the start of the current scope */
    519 
    520     Parent = Op->Asl.Parent;
    521     Next = Parent->Asl.Child;
    522 
    523     /* Search entire scope for an operation region declaration */
    524 
    525     while (Next)
    526     {
    527         if (Next->Asl.ParseOpcode == PARSEOP_OPERATIONREGION)
    528         {
    529             return; /* Found region, OK */
    530         }
    531 
    532         Next = Next->Asl.Next;
    533     }
    534 
    535     /* No region found, issue warning */
    536 
    537     AslError (ASL_WARNING, ASL_MSG_NO_REGION, Op, NULL);
    538 }
    539