diff options
| author | Jung-uk Kim <jkim@FreeBSD.org> | 2013-01-02 19:01:21 +0000 | 
|---|---|---|
| committer | Jung-uk Kim <jkim@FreeBSD.org> | 2013-01-02 19:01:21 +0000 | 
| commit | b28e481ae9b051dab150e9b5a89730cdc1103a9c (patch) | |
| tree | 434e706ece73a93073f350c91cd35ed7d7e98811 /source/compiler/aslmethod.c | |
| parent | c2463a8709e5b3a5ce54c09d35b4820a756b0fc5 (diff) | |
Notes
Diffstat (limited to 'source/compiler/aslmethod.c')
| -rw-r--r-- | source/compiler/aslmethod.c | 619 | 
1 files changed, 619 insertions, 0 deletions
diff --git a/source/compiler/aslmethod.c b/source/compiler/aslmethod.c new file mode 100644 index 0000000000000..b9e6d6feefe1a --- /dev/null +++ b/source/compiler/aslmethod.c @@ -0,0 +1,619 @@ +/****************************************************************************** + * + * Module Name: aslmethod.c - Control method analysis walk + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + *    substantially similar to the "NO WARRANTY" disclaimer below + *    ("Disclaimer") and any redistribution must be conditioned upon + *    including a substantially similar Disclaimer requirement for further + *    binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + *    of any contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include "aslcompiler.h" +#include "aslcompiler.y.h" + + +#define _COMPONENT          ACPI_COMPILER +        ACPI_MODULE_NAME    ("aslmethod") + + +/******************************************************************************* + * + * FUNCTION:    MtMethodAnalysisWalkBegin + * + * PARAMETERS:  ASL_WALK_CALLBACK + * + * RETURN:      Status + * + * DESCRIPTION: Descending callback for the analysis walk. Check methods for: + *              1) Initialized local variables + *              2) Valid arguments + *              3) Return types + * + ******************************************************************************/ + +ACPI_STATUS +MtMethodAnalysisWalkBegin ( +    ACPI_PARSE_OBJECT       *Op, +    UINT32                  Level, +    void                    *Context) +{ +    ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context; +    ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack; +    ACPI_PARSE_OBJECT       *Next; +    UINT32                  RegisterNumber; +    UINT32                  i; +    char                    LocalName[] = "Local0"; +    char                    ArgName[] = "Arg0"; +    ACPI_PARSE_OBJECT       *ArgNode; +    ACPI_PARSE_OBJECT       *NextType; +    ACPI_PARSE_OBJECT       *NextParamType; +    UINT8                   ActualArgs = 0; + + +    switch (Op->Asl.ParseOpcode) +    { +    case PARSEOP_METHOD: + +        TotalMethods++; + +        /* Create and init method info */ + +        MethodInfo       = UtLocalCalloc (sizeof (ASL_METHOD_INFO)); +        MethodInfo->Next = WalkInfo->MethodStack; +        MethodInfo->Op = Op; + +        WalkInfo->MethodStack = MethodInfo; + +        /* Get the name node, ignored here */ + +        Next = Op->Asl.Child; + +        /* Get the NumArguments node */ + +        Next = Next->Asl.Next; +        MethodInfo->NumArguments = (UINT8) +            (((UINT8) Next->Asl.Value.Integer) & 0x07); + +        /* Get the SerializeRule and SyncLevel nodes, ignored here */ + +        Next = Next->Asl.Next; +        Next = Next->Asl.Next; +        ArgNode = Next; + +        /* Get the ReturnType node */ + +        Next = Next->Asl.Next; + +        NextType = Next->Asl.Child; +        while (NextType) +        { +            /* Get and map each of the ReturnTypes */ + +            MethodInfo->ValidReturnTypes |= AnMapObjTypeToBtype (NextType); +            NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; +            NextType = NextType->Asl.Next; +        } + +        /* Get the ParameterType node */ + +        Next = Next->Asl.Next; + +        NextType = Next->Asl.Child; +        while (NextType) +        { +            if (NextType->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) +            { +                NextParamType = NextType->Asl.Child; +                while (NextParamType) +                { +                    MethodInfo->ValidArgTypes[ActualArgs] |= AnMapObjTypeToBtype (NextParamType); +                    NextParamType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; +                    NextParamType = NextParamType->Asl.Next; +                } +            } +            else +            { +                MethodInfo->ValidArgTypes[ActualArgs] = +                    AnMapObjTypeToBtype (NextType); +                NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; +                ActualArgs++; +            } + +            NextType = NextType->Asl.Next; +        } + +        if ((MethodInfo->NumArguments) && +            (MethodInfo->NumArguments != ActualArgs)) +        { +            /* error: Param list did not match number of args */ +        } + +        /* Allow numarguments == 0 for Function() */ + +        if ((!MethodInfo->NumArguments) && (ActualArgs)) +        { +            MethodInfo->NumArguments = ActualArgs; +            ArgNode->Asl.Value.Integer |= ActualArgs; +        } + +        /* +         * Actual arguments are initialized at method entry. +         * All other ArgX "registers" can be used as locals, so we +         * track their initialization. +         */ +        for (i = 0; i < MethodInfo->NumArguments; i++) +        { +            MethodInfo->ArgInitialized[i] = TRUE; +        } +        break; + + +    case PARSEOP_METHODCALL: + +        if (MethodInfo && +           (Op->Asl.Node == MethodInfo->Op->Asl.Node)) +        { +            AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName); +        } +        break; + + +    case PARSEOP_LOCAL0: +    case PARSEOP_LOCAL1: +    case PARSEOP_LOCAL2: +    case PARSEOP_LOCAL3: +    case PARSEOP_LOCAL4: +    case PARSEOP_LOCAL5: +    case PARSEOP_LOCAL6: +    case PARSEOP_LOCAL7: + +        if (!MethodInfo) +        { +            /* +             * Local was used outside a control method, or there was an error +             * in the method declaration. +             */ +            AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName); +            return (AE_ERROR); +        } + +        RegisterNumber = (Op->Asl.AmlOpcode & 0x000F); + +        /* +         * If the local is being used as a target, mark the local +         * initialized +         */ +        if (Op->Asl.CompileFlags & NODE_IS_TARGET) +        { +            MethodInfo->LocalInitialized[RegisterNumber] = TRUE; +        } + +        /* +         * Otherwise, this is a reference, check if the local +         * has been previously initialized. +         * +         * The only operator that accepts an uninitialized value is ObjectType() +         */ +        else if ((!MethodInfo->LocalInitialized[RegisterNumber]) && +                 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE)) +        { +            LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30); +            AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName); +        } +        break; + + +    case PARSEOP_ARG0: +    case PARSEOP_ARG1: +    case PARSEOP_ARG2: +    case PARSEOP_ARG3: +    case PARSEOP_ARG4: +    case PARSEOP_ARG5: +    case PARSEOP_ARG6: + +        if (!MethodInfo) +        { +            /* +             * Arg was used outside a control method, or there was an error +             * in the method declaration. +             */ +            AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName); +            return (AE_ERROR); +        } + +        RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8; +        ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30); + +        /* +         * If the Arg is being used as a target, mark the local +         * initialized +         */ +        if (Op->Asl.CompileFlags & NODE_IS_TARGET) +        { +            MethodInfo->ArgInitialized[RegisterNumber] = TRUE; +        } + +        /* +         * Otherwise, this is a reference, check if the Arg +         * has been previously initialized. +         * +         * The only operator that accepts an uninitialized value is ObjectType() +         */ +        else if ((!MethodInfo->ArgInitialized[RegisterNumber]) && +                 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE)) +        { +            AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName); +        } + +        /* Flag this arg if it is not a "real" argument to the method */ + +        if (RegisterNumber >= MethodInfo->NumArguments) +        { +            AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName); +        } +        break; + + +    case PARSEOP_RETURN: + +        if (!MethodInfo) +        { +            /* +             * Probably was an error in the method declaration, +             * no additional error here +             */ +            ACPI_WARNING ((AE_INFO, "%p, No parent method", Op)); +            return (AE_ERROR); +        } + +        /* +         * A child indicates a possible return value. A simple Return or +         * Return() is marked with NODE_IS_NULL_RETURN by the parser so +         * that it is not counted as a "real" return-with-value, although +         * the AML code that is actually emitted is Return(0). The AML +         * definition of Return has a required parameter, so we are +         * forced to convert a null return to Return(0). +         */ +        if ((Op->Asl.Child) && +            (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) && +            (!(Op->Asl.Child->Asl.CompileFlags & NODE_IS_NULL_RETURN))) +        { +            MethodInfo->NumReturnWithValue++; +        } +        else +        { +            MethodInfo->NumReturnNoValue++; +        } +        break; + + +    case PARSEOP_BREAK: +    case PARSEOP_CONTINUE: + +        Next = Op->Asl.Parent; +        while (Next) +        { +            if (Next->Asl.ParseOpcode == PARSEOP_WHILE) +            { +                break; +            } +            Next = Next->Asl.Parent; +        } + +        if (!Next) +        { +            AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL); +        } +        break; + + +    case PARSEOP_STALL: + +        /* We can range check if the argument is an integer */ + +        if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) && +            (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX)) +        { +            AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL); +        } +        break; + + +    case PARSEOP_DEVICE: +    case PARSEOP_EVENT: +    case PARSEOP_MUTEX: +    case PARSEOP_OPERATIONREGION: +    case PARSEOP_POWERRESOURCE: +    case PARSEOP_PROCESSOR: +    case PARSEOP_THERMALZONE: + +        /* +         * The first operand is a name to be created in the namespace. +         * Check against the reserved list. +         */ +        i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg); +        if (i < ACPI_VALID_RESERVED_NAME_MAX) +        { +            AslError (ASL_ERROR, ASL_MSG_RESERVED_USE, Op, Op->Asl.ExternalName); +        } +        break; + + +    case PARSEOP_NAME: + +        /* Typecheck any predefined names statically defined with Name() */ + +        ApCheckForPredefinedObject (Op, Op->Asl.NameSeg); + +        /* Special typechecking for _HID */ + +        if (!ACPI_STRCMP (METHOD_NAME__HID, Op->Asl.NameSeg)) +        { +            Next = Op->Asl.Child->Asl.Next; +            AnCheckId (Next, ASL_TYPE_HID); +        } + +        /* Special typechecking for _CID */ + +        else if (!ACPI_STRCMP (METHOD_NAME__CID, Op->Asl.NameSeg)) +        { +            Next = Op->Asl.Child->Asl.Next; + +            if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) || +                (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)) +            { +                Next = Next->Asl.Child; +                while (Next) +                { +                    AnCheckId (Next, ASL_TYPE_CID); +                    Next = Next->Asl.Next; +                } +            } +            else +            { +                AnCheckId (Next, ASL_TYPE_CID); +            } +        } +        break; + + +    default: +        break; +    } + +    return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION:    MtMethodAnalysisWalkEnd + * + * PARAMETERS:  ASL_WALK_CALLBACK + * + * RETURN:      Status + * + * DESCRIPTION: Ascending callback for analysis walk. Complete method + *              return analysis. + * + ******************************************************************************/ + +ACPI_STATUS +MtMethodAnalysisWalkEnd ( +    ACPI_PARSE_OBJECT       *Op, +    UINT32                  Level, +    void                    *Context) +{ +    ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context; +    ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack; + + +    switch (Op->Asl.ParseOpcode) +    { +    case PARSEOP_METHOD: +    case PARSEOP_RETURN: +        if (!MethodInfo) +        { +            printf ("No method info for method! [%s]\n", Op->Asl.Namepath); +            AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op, +                "No method info for this method"); + +            CmCleanupAndExit (); +            return (AE_AML_INTERNAL); +        } +        break; + +    default: +        break; +    } + +    switch (Op->Asl.ParseOpcode) +    { +    case PARSEOP_METHOD: + +        WalkInfo->MethodStack = MethodInfo->Next; + +        /* +         * Check if there is no return statement at the end of the +         * method AND we can actually get there -- i.e., the execution +         * of the method can possibly terminate without a return statement. +         */ +        if ((!AnLastStatementIsReturn (Op)) && +            (!(Op->Asl.CompileFlags & NODE_HAS_NO_EXIT))) +        { +            /* +             * No return statement, and execution can possibly exit +             * via this path. This is equivalent to Return () +             */ +            MethodInfo->NumReturnNoValue++; +        } + +        /* +         * Check for case where some return statements have a return value +         * and some do not. Exit without a return statement is a return with +         * no value +         */ +        if (MethodInfo->NumReturnNoValue && +            MethodInfo->NumReturnWithValue) +        { +            AslError (ASL_WARNING, ASL_MSG_RETURN_TYPES, Op, +                Op->Asl.ExternalName); +        } + +        /* +         * If there are any RETURN() statements with no value, or there is a +         * control path that allows the method to exit without a return value, +         * we mark the method as a method that does not return a value. This +         * knowledge can be used to check method invocations that expect a +         * returned value. +         */ +        if (MethodInfo->NumReturnNoValue) +        { +            if (MethodInfo->NumReturnWithValue) +            { +                Op->Asl.CompileFlags |= NODE_METHOD_SOME_NO_RETVAL; +            } +            else +            { +                Op->Asl.CompileFlags |= NODE_METHOD_NO_RETVAL; +            } +        } + +        /* +         * Check predefined method names for correct return behavior +         * and correct number of arguments. Also, some special checks +         * For GPE and _REG methods. +         */ +        if (ApCheckForPredefinedMethod (Op, MethodInfo)) +        { +            /* Special check for two names like _L01 and _E01 in same scope */ + +            ApCheckForGpeNameConflict (Op); + +            /* +             * Special check for _REG: Must have an operation region definition +             * within the same scope! +             */ +            ApCheckRegMethod (Op); +        } + +        ACPI_FREE (MethodInfo); +        break; + + +    case PARSEOP_NAME: + +         /* Special check for two names like _L01 and _E01 in same scope */ + +        ApCheckForGpeNameConflict (Op); +        break; + + +    case PARSEOP_RETURN: + +        /* +         * If the parent is a predefined method name, attempt to typecheck +         * the return value. Only static types can be validated. +         */ +        ApCheckPredefinedReturnValue (Op, MethodInfo); + +        /* +         * The parent block does not "exit" and continue execution -- the +         * method is terminated here with the Return() statement. +         */ +        Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT; + +        /* Used in the "typing" pass later */ + +        Op->Asl.ParentMethod = MethodInfo->Op; + +        /* +         * If there is a peer node after the return statement, then this +         * node is unreachable code -- i.e., it won't be executed because of +         * the preceding Return() statement. +         */ +        if (Op->Asl.Next) +        { +            AslError (ASL_WARNING, ASL_MSG_UNREACHABLE_CODE, Op->Asl.Next, NULL); +        } +        break; + + +    case PARSEOP_IF: + +        if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) && +            (Op->Asl.Next) && +            (Op->Asl.Next->Asl.ParseOpcode == PARSEOP_ELSE)) +        { +            /* +             * This IF has a corresponding ELSE. The IF block has no exit, +             * (it contains an unconditional Return) +             * mark the ELSE block to remember this fact. +             */ +            Op->Asl.Next->Asl.CompileFlags |= NODE_IF_HAS_NO_EXIT; +        } +        break; + + +    case PARSEOP_ELSE: + +        if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) && +            (Op->Asl.CompileFlags & NODE_IF_HAS_NO_EXIT)) +        { +            /* +             * This ELSE block has no exit and the corresponding IF block +             * has no exit either. Therefore, the parent node has no exit. +             */ +            Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT; +        } +        break; + + +    default: + +        if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) && +            (Op->Asl.Parent)) +        { +            /* If this node has no exit, then the parent has no exit either */ + +            Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT; +        } +        break; +    } + +    return (AE_OK); +}  | 
