Ejemplo n.º 1
0
static ACPI_STATUS
AcpiPsBuildNamedOp (
    ACPI_WALK_STATE         *WalkState,
    UINT8                   *AmlOpStart,
    ACPI_PARSE_OBJECT       *UnnamedOp,
    ACPI_PARSE_OBJECT       **Op)
{
    ACPI_STATUS             Status = AE_OK;
    ACPI_PARSE_OBJECT       *Arg = NULL;


    ACPI_FUNCTION_TRACE_PTR (PsBuildNamedOp, WalkState);


    UnnamedOp->Common.Value.Arg = NULL;
    UnnamedOp->Common.ArgListLength = 0;
    UnnamedOp->Common.AmlOpcode = WalkState->Opcode;

    /*
     * Get and append arguments until we find the node that contains
     * the name (the type ARGP_NAME).
     */
    while (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) &&
          (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) != ARGP_NAME))
    {
        Status = AcpiPsGetNextArg (WalkState, &(WalkState->ParserState),
                    GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), &Arg);
        if (ACPI_FAILURE (Status))
        {
            return_ACPI_STATUS (Status);
        }

        AcpiPsAppendArg (UnnamedOp, Arg);
        INCREMENT_ARG_LIST (WalkState->ArgTypes);
    }

    /*
     * Make sure that we found a NAME and didn't run out of arguments
     */
    if (!GET_CURRENT_ARG_TYPE (WalkState->ArgTypes))
    {
        return_ACPI_STATUS (AE_AML_NO_OPERAND);
    }

    /* We know that this arg is a name, move to next arg */

    INCREMENT_ARG_LIST (WalkState->ArgTypes);

    /*
     * Find the object. This will either insert the object into
     * the namespace or simply look it up
     */
    WalkState->Op = NULL;

    Status = WalkState->DescendingCallback (WalkState, Op);
    if (ACPI_FAILURE (Status))
    {
        ACPI_EXCEPTION ((AE_INFO, Status, "During name lookup/catalog"));
        return_ACPI_STATUS (Status);
    }

    if (!*Op)
    {
        return_ACPI_STATUS (AE_CTRL_PARSE_CONTINUE);
    }

    Status = AcpiPsNextParseState (WalkState, *Op, Status);
    if (ACPI_FAILURE (Status))
    {
        if (Status == AE_CTRL_PENDING)
        {
            return_ACPI_STATUS (AE_CTRL_PARSE_PENDING);
        }
        return_ACPI_STATUS (Status);
    }

    AcpiPsAppendArg (*Op, UnnamedOp->Common.Value.Arg);
    AcpiGbl_Depth++;

    if ((*Op)->Common.AmlOpcode == AML_REGION_OP ||
        (*Op)->Common.AmlOpcode == AML_DATA_REGION_OP)
    {
        /*
         * Defer final parsing of an OperationRegion body, because we don't
         * have enough info in the first pass to parse it correctly (i.e.,
         * there may be method calls within the TermArg elements of the body.)
         *
         * However, we must continue parsing because the opregion is not a
         * standalone package -- we don't know where the end is at this point.
         *
         * (Length is unknown until parse of the body complete)
         */
        (*Op)->Named.Data = AmlOpStart;
        (*Op)->Named.Length = 0;
    }

    return_ACPI_STATUS (AE_OK);
}
Ejemplo n.º 2
0
static ACPI_STATUS
AcpiPsGetArguments (
    ACPI_WALK_STATE         *WalkState,
    UINT8                   *AmlOpStart,
    ACPI_PARSE_OBJECT       *Op)
{
    ACPI_STATUS             Status = AE_OK;
    ACPI_PARSE_OBJECT       *Arg = NULL;
    const ACPI_OPCODE_INFO  *OpInfo;


    ACPI_FUNCTION_TRACE_PTR (PsGetArguments, WalkState);


    switch (Op->Common.AmlOpcode)
    {
    case AML_BYTE_OP:       /* AML_BYTEDATA_ARG */
    case AML_WORD_OP:       /* AML_WORDDATA_ARG */
    case AML_DWORD_OP:      /* AML_DWORDATA_ARG */
    case AML_QWORD_OP:      /* AML_QWORDATA_ARG */
    case AML_STRING_OP:     /* AML_ASCIICHARLIST_ARG */

        /* Fill in constant or string argument directly */

        AcpiPsGetNextSimpleArg (&(WalkState->ParserState),
            GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), Op);
        break;

    case AML_INT_NAMEPATH_OP:   /* AML_NAMESTRING_ARG */

        Status = AcpiPsGetNextNamepath (WalkState, &(WalkState->ParserState), Op, 1);
        if (ACPI_FAILURE (Status))
        {
            return_ACPI_STATUS (Status);
        }

        WalkState->ArgTypes = 0;
        break;

    default:
        /*
         * Op is not a constant or string, append each argument to the Op
         */
        while (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) && !WalkState->ArgCount)
        {
            WalkState->AmlOffset = (UINT32) ACPI_PTR_DIFF (WalkState->ParserState.Aml,
                WalkState->ParserState.AmlStart);

            Status = AcpiPsGetNextArg (WalkState, &(WalkState->ParserState),
                        GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), &Arg);
            if (ACPI_FAILURE (Status))
            {
                return_ACPI_STATUS (Status);
            }

            if (Arg)
            {
                Arg->Common.AmlOffset = WalkState->AmlOffset;
                AcpiPsAppendArg (Op, Arg);
            }

            INCREMENT_ARG_LIST (WalkState->ArgTypes);
        }


        /*
         * Handle executable code at "module-level". This refers to
         * executable opcodes that appear outside of any control method.
         */
        if ((WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2) &&
            ((WalkState->ParseFlags & ACPI_PARSE_DISASSEMBLE) == 0))
        {
            /*
             * We want to skip If/Else/While constructs during Pass1 because we
             * want to actually conditionally execute the code during Pass2.
             *
             * Except for disassembly, where we always want to walk the
             * If/Else/While packages
             */
            switch (Op->Common.AmlOpcode)
            {
            case AML_IF_OP:
            case AML_ELSE_OP:
            case AML_WHILE_OP:

                /*
                 * Currently supported module-level opcodes are:
                 * IF/ELSE/WHILE. These appear to be the most common,
                 * and easiest to support since they open an AML
                 * package.
                 */
                if (WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1)
                {
                    AcpiPsLinkModuleCode (Op->Common.Parent, AmlOpStart,
                        (UINT32) (WalkState->ParserState.PkgEnd - AmlOpStart),
                        WalkState->OwnerId);
                }

                ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
                    "Pass1: Skipping an If/Else/While body\n"));

                /* Skip body of if/else/while in pass 1 */

                WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
                WalkState->ArgCount = 0;
                break;

            default:
                /*
                 * Check for an unsupported executable opcode at module
                 * level. We must be in PASS1, the parent must be a SCOPE,
                 * The opcode class must be EXECUTE, and the opcode must
                 * not be an argument to another opcode.
                 */
                if ((WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) &&
                    (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP))
                {
                    OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
                    if ((OpInfo->Class == AML_CLASS_EXECUTE) &&
                        (!Arg))
                    {
                        ACPI_WARNING ((AE_INFO,
                            "Unsupported module-level executable opcode "
                            "0x%.2X at table offset 0x%.4X",
                            Op->Common.AmlOpcode,
                            (UINT32) (ACPI_PTR_DIFF (AmlOpStart,
                                WalkState->ParserState.AmlStart) +
                                sizeof (ACPI_TABLE_HEADER))));
                    }
                }
                break;
            }
        }

        /* Special processing for certain opcodes */

        switch (Op->Common.AmlOpcode)
        {
        case AML_METHOD_OP:
            /*
             * Skip parsing of control method because we don't have enough
             * info in the first pass to parse it correctly.
             *
             * Save the length and address of the body
             */
            Op->Named.Data = WalkState->ParserState.Aml;
            Op->Named.Length = (UINT32)
                (WalkState->ParserState.PkgEnd - WalkState->ParserState.Aml);

            /* Skip body of method */

            WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
            WalkState->ArgCount = 0;
            break;

        case AML_BUFFER_OP:
        case AML_PACKAGE_OP:
        case AML_VAR_PACKAGE_OP:

            if ((Op->Common.Parent) &&
                (Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) &&
                (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2))
            {
                /*
                 * Skip parsing of Buffers and Packages because we don't have
                 * enough info in the first pass to parse them correctly.
                 */
                Op->Named.Data = AmlOpStart;
                Op->Named.Length = (UINT32)
                    (WalkState->ParserState.PkgEnd - AmlOpStart);

                /* Skip body */

                WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
                WalkState->ArgCount = 0;
            }
            break;

        case AML_WHILE_OP:

            if (WalkState->ControlState)
            {
                WalkState->ControlState->Control.PackageEnd =
                    WalkState->ParserState.PkgEnd;
            }
            break;

        default:

            /* No action for all other opcodes */
            break;
        }

        break;
    }

    return_ACPI_STATUS (AE_OK);
}
Ejemplo n.º 3
0
ACPI_STATUS
AnOperandTypecheckWalkEnd (
    ACPI_PARSE_OBJECT       *Op,
    UINT32                  Level,
    void                    *Context)
{
    const ACPI_OPCODE_INFO  *OpInfo;
    UINT32                  RuntimeArgTypes;
    UINT32                  RuntimeArgTypes2;
    UINT32                  RequiredBtypes;
    UINT32                  ThisNodeBtype;
    UINT32                  CommonBtypes;
    UINT32                  OpcodeClass;
    ACPI_PARSE_OBJECT       *ArgOp;
    UINT32                  ArgType;


    switch (Op->Asl.AmlOpcode)
    {
    case AML_RAW_DATA_BYTE:
    case AML_RAW_DATA_WORD:
    case AML_RAW_DATA_DWORD:
    case AML_RAW_DATA_QWORD:
    case AML_RAW_DATA_BUFFER:
    case AML_RAW_DATA_CHAIN:
    case AML_PACKAGE_LENGTH:
    case AML_UNASSIGNED_OPCODE:
    case AML_DEFAULT_ARG_OP:

        /* Ignore the internal (compiler-only) AML opcodes */

        return (AE_OK);

    default:

        break;
    }

    OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
    if (!OpInfo)
    {
        return (AE_OK);
    }

    ArgOp = Op->Asl.Child;
    OpcodeClass = OpInfo->Class;
    RuntimeArgTypes = OpInfo->RuntimeArgs;

#ifdef ASL_ERROR_NAMED_OBJECT_IN_WHILE
    /*
     * Update 11/2008: In practice, we can't perform this check. A simple
     * analysis is not sufficient. Also, it can cause errors when compiling
     * disassembled code because of the way Switch operators are implemented
     * (a While(One) loop with a named temp variable created within.)
     */

    /*
     * If we are creating a named object, check if we are within a while loop
     * by checking if the parent is a WHILE op. This is a simple analysis, but
     * probably sufficient for many cases.
     *
     * Allow Scope(), Buffer(), and Package().
     */
    if (((OpcodeClass == AML_CLASS_NAMED_OBJECT) && (Op->Asl.AmlOpcode != AML_SCOPE_OP)) ||
        ((OpcodeClass == AML_CLASS_CREATE) && (OpInfo->Flags & AML_NSNODE)))
    {
        if (Op->Asl.Parent->Asl.AmlOpcode == AML_WHILE_OP)
        {
            AslError (ASL_ERROR, ASL_MSG_NAMED_OBJECT_IN_WHILE, Op, NULL);
        }
    }
#endif

    /*
     * Special case for control opcodes IF/RETURN/WHILE since they
     * have no runtime arg list (at this time)
     */
    switch (Op->Asl.AmlOpcode)
    {
    case AML_IF_OP:
    case AML_WHILE_OP:
    case AML_RETURN_OP:

        if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL)
        {
            /* Check for an internal method */

            if (AnIsInternalMethod (ArgOp))
            {
                return (AE_OK);
            }

            /* The lone arg is a method call, check it */

            RequiredBtypes = AnMapArgTypeToBtype (ARGI_INTEGER);
            if (Op->Asl.AmlOpcode == AML_RETURN_OP)
            {
                RequiredBtypes = 0xFFFFFFFF;
            }

            ThisNodeBtype = AnGetBtype (ArgOp);
            if (ThisNodeBtype == ACPI_UINT32_MAX)
            {
                return (AE_OK);
            }

            AnCheckMethodReturnValue (Op, OpInfo, ArgOp,
                RequiredBtypes, ThisNodeBtype);
        }
        return (AE_OK);

    case AML_EXTERNAL_OP:
        /*
         * Not really a "runtime" opcode since it used by disassembler only.
         * The parser will find any issues with the operands.
         */
        return (AE_OK);

    default:

        break;
    }

    /* Ignore the non-executable opcodes */

    if (RuntimeArgTypes == ARGI_INVALID_OPCODE)
    {
        return (AE_OK);
    }

    /*
     * Special handling for certain opcodes.
     */
    switch (Op->Asl.AmlOpcode)
    {
        /* BankField has one TermArg */

    case AML_BANK_FIELD_OP:

        OpcodeClass = AML_CLASS_EXECUTE;
        ArgOp = ArgOp->Asl.Next;
        ArgOp = ArgOp->Asl.Next;
        break;

        /* Operation Region has 2 TermArgs */

    case AML_REGION_OP:

        OpcodeClass = AML_CLASS_EXECUTE;
        ArgOp = ArgOp->Asl.Next;
        ArgOp = ArgOp->Asl.Next;
        break;

        /* DataTableRegion has 3 TermArgs */

    case AML_DATA_REGION_OP:

        OpcodeClass = AML_CLASS_EXECUTE;
        ArgOp = ArgOp->Asl.Next;
        break;

        /* Buffers/Packages have a length that is a TermArg */

    case AML_BUFFER_OP:
    case AML_PACKAGE_OP:
    case AML_VARIABLE_PACKAGE_OP:

            /* If length is a constant, we are done */

        if ((ArgOp->Asl.ParseOpcode == PARSEOP_INTEGER) ||
            (ArgOp->Asl.ParseOpcode == PARSEOP_RAW_DATA))
        {
            return (AE_OK);
        }
        break;

        /* Store can write any object to the Debug object */

    case AML_STORE_OP:
        /*
         * If this is a Store() to the Debug object, we don't need
         * to perform any further validation -- because a Store of
         * any object to Debug is permitted and supported.
         */
        if (ArgOp->Asl.Next->Asl.AmlOpcode == AML_DEBUG_OP)
        {
            return (AE_OK);
        }
        break;

    default:
        break;
    }

    switch (OpcodeClass)
    {
    case AML_CLASS_EXECUTE:
    case AML_CLASS_CREATE:
    case AML_CLASS_CONTROL:
    case AML_CLASS_RETURN_VALUE:

        /* Reverse the runtime argument list */

        RuntimeArgTypes2 = 0;
        while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes)))
        {
            RuntimeArgTypes2 <<= ARG_TYPE_WIDTH;
            RuntimeArgTypes2 |= ArgType;
            INCREMENT_ARG_LIST (RuntimeArgTypes);
        }

        /* Typecheck each argument */

        while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes2)))
        {
            /* Get the required type(s) for the argument */

            RequiredBtypes = AnMapArgTypeToBtype (ArgType);

            if (!ArgOp)
            {
                AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op,
                    "Null ArgOp in argument loop");
                AslAbort ();
            }

            /* Get the actual type of the argument */

            ThisNodeBtype = AnGetBtype (ArgOp);
            if (ThisNodeBtype == ACPI_UINT32_MAX)
            {
                goto NextArgument;
            }

            /* Examine the arg based on the required type of the arg */

            switch (ArgType)
            {
            case ARGI_TARGETREF:

                if (ArgOp->Asl.ParseOpcode == PARSEOP_ZERO)
                {
                    /* ZERO is the placeholder for "don't store result" */

                    ThisNodeBtype = RequiredBtypes;
                    break;
                }

            /* Fallthrough */

            case ARGI_STORE_TARGET:

                if (ArgOp->Asl.ParseOpcode == PARSEOP_INTEGER)
                {
                    /*
                     * This is the case where an original reference to a resource
                     * descriptor field has been replaced by an (Integer) offset.
                     * These named fields are supported at compile-time only;
                     * the names are not passed to the interpreter (via the AML).
                     */
                    if ((ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE_FIELD) ||
                        (ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE))
                    {
                        AslError (ASL_ERROR, ASL_MSG_RESOURCE_FIELD,
                            ArgOp, NULL);
                    }
                    else
                    {
                        AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE,
                            ArgOp, NULL);
                    }
                }
                break;


#ifdef __FUTURE_IMPLEMENTATION
/*
 * Possible future typechecking support
 */
            case ARGI_REFERENCE:            /* References */
            case ARGI_INTEGER_REF:
            case ARGI_OBJECT_REF:
            case ARGI_DEVICE_REF:

                switch (ArgOp->Asl.ParseOpcode)
                {
                case PARSEOP_LOCAL0:
                case PARSEOP_LOCAL1:
                case PARSEOP_LOCAL2:
                case PARSEOP_LOCAL3:
                case PARSEOP_LOCAL4:
                case PARSEOP_LOCAL5:
                case PARSEOP_LOCAL6:
                case PARSEOP_LOCAL7:

                    /* TBD: implement analysis of current value (type) of the local */
                    /* For now, just treat any local as a typematch */

                    /*ThisNodeBtype = RequiredBtypes;*/
                    break;

                case PARSEOP_ARG0:
                case PARSEOP_ARG1:
                case PARSEOP_ARG2:
                case PARSEOP_ARG3:
                case PARSEOP_ARG4:
                case PARSEOP_ARG5:
                case PARSEOP_ARG6:

                    /* Hard to analyze argument types, so we won't */
                    /* for now. Just treat any arg as a typematch */

                    /* ThisNodeBtype = RequiredBtypes; */
                    break;

                case PARSEOP_DEBUG:
                case PARSEOP_REFOF:
                case PARSEOP_INDEX:
                default:

                    break;
                }
                break;
#endif
            case ARGI_INTEGER:
            default:

                break;
            }


            /* Check for a type mismatch (required versus actual) */

            CommonBtypes = ThisNodeBtype & RequiredBtypes;

            if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL)
            {
                if (AnIsInternalMethod (ArgOp))
                {
                    return (AE_OK);
                }

                /* Check a method call for a valid return value */

                AnCheckMethodReturnValue (Op, OpInfo, ArgOp,
                    RequiredBtypes, ThisNodeBtype);
            }

            /*
             * Now check if the actual type(s) match at least one
             * bit to the required type
             */
            else if (!CommonBtypes)
            {
                /* No match -- this is a type mismatch error */

                AnFormatBtype (StringBuffer, ThisNodeBtype);
                AnFormatBtype (StringBuffer2, RequiredBtypes);

                sprintf (MsgBuffer, "[%s] found, %s operator requires [%s]",
                    StringBuffer, OpInfo->Name, StringBuffer2);

                AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE,
                    ArgOp, MsgBuffer);
            }

        NextArgument:
            ArgOp = ArgOp->Asl.Next;
            INCREMENT_ARG_LIST (RuntimeArgTypes2);
        }
        break;

    default:

        break;
    }

    return (AE_OK);
}
Ejemplo n.º 4
0
acpi_status
acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
		       u8 *aml_op_start,
		       union acpi_parse_object *unnamed_op,
		       union acpi_parse_object **op)
{
	acpi_status status = AE_OK;
	union acpi_parse_object *arg = NULL;

	ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state);

	unnamed_op->common.value.arg = NULL;
	unnamed_op->common.arg_list_length = 0;
	unnamed_op->common.aml_opcode = walk_state->opcode;

	/*
	 * Get and append arguments until we find the node that contains
	 * the name (the type ARGP_NAME).
	 */
	while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) &&
	       (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) {
		ASL_CV_CAPTURE_COMMENTS(walk_state);
		status =
		    acpi_ps_get_next_arg(walk_state,
					 &(walk_state->parser_state),
					 GET_CURRENT_ARG_TYPE(walk_state->
							      arg_types), &arg);
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}

		acpi_ps_append_arg(unnamed_op, arg);
		INCREMENT_ARG_LIST(walk_state->arg_types);
	}

	/* are there any inline comments associated with the name_seg?? If so, save this. */

	ASL_CV_CAPTURE_COMMENTS(walk_state);

#ifdef ACPI_ASL_COMPILER
	if (acpi_gbl_current_inline_comment != NULL) {
		unnamed_op->common.name_comment =
		    acpi_gbl_current_inline_comment;
		acpi_gbl_current_inline_comment = NULL;
	}
#endif

	/*
	 * Make sure that we found a NAME and didn't run out of arguments
	 */
	if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) {
		return_ACPI_STATUS(AE_AML_NO_OPERAND);
	}

	/* We know that this arg is a name, move to next arg */

	INCREMENT_ARG_LIST(walk_state->arg_types);

	/*
	 * Find the object. This will either insert the object into
	 * the namespace or simply look it up
	 */
	walk_state->op = NULL;

	status = walk_state->descending_callback(walk_state, op);
	if (ACPI_FAILURE(status)) {
		if (status != AE_CTRL_TERMINATE) {
			ACPI_EXCEPTION((AE_INFO, status,
					"During name lookup/catalog"));
		}
		return_ACPI_STATUS(status);
	}

	if (!*op) {
		return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
	}

	status = acpi_ps_next_parse_state(walk_state, *op, status);
	if (ACPI_FAILURE(status)) {
		if (status == AE_CTRL_PENDING) {
			status = AE_CTRL_PARSE_PENDING;
		}
		return_ACPI_STATUS(status);
	}

	acpi_ps_append_arg(*op, unnamed_op->common.value.arg);

#ifdef ACPI_ASL_COMPILER

	/* save any comments that might be associated with unnamed_op. */

	(*op)->common.inline_comment = unnamed_op->common.inline_comment;
	(*op)->common.end_node_comment = unnamed_op->common.end_node_comment;
	(*op)->common.close_brace_comment =
	    unnamed_op->common.close_brace_comment;
	(*op)->common.name_comment = unnamed_op->common.name_comment;
	(*op)->common.comment_list = unnamed_op->common.comment_list;
	(*op)->common.end_blk_comment = unnamed_op->common.end_blk_comment;
	(*op)->common.cv_filename = unnamed_op->common.cv_filename;
	(*op)->common.cv_parent_filename =
	    unnamed_op->common.cv_parent_filename;
	(*op)->named.aml = unnamed_op->common.aml;

	unnamed_op->common.inline_comment = NULL;
	unnamed_op->common.end_node_comment = NULL;
	unnamed_op->common.close_brace_comment = NULL;
	unnamed_op->common.name_comment = NULL;
	unnamed_op->common.comment_list = NULL;
	unnamed_op->common.end_blk_comment = NULL;
#endif

	if ((*op)->common.aml_opcode == AML_REGION_OP ||
	    (*op)->common.aml_opcode == AML_DATA_REGION_OP) {
		/*
		 * Defer final parsing of an operation_region body, because we don't
		 * have enough info in the first pass to parse it correctly (i.e.,
		 * there may be method calls within the term_arg elements of the body.)
		 *
		 * However, we must continue parsing because the opregion is not a
		 * standalone package -- we don't know where the end is at this point.
		 *
		 * (Length is unknown until parse of the body complete)
		 */
		(*op)->named.data = aml_op_start;
		(*op)->named.length = 0;
	}

	return_ACPI_STATUS(AE_OK);
}
Ejemplo n.º 5
0
ACPI_STATUS
AcpiExResolveOperands (
    UINT16                  Opcode,
    ACPI_OPERAND_OBJECT     **StackPtr,
    ACPI_WALK_STATE         *WalkState)
{
    ACPI_OPERAND_OBJECT     *ObjDesc;
    ACPI_STATUS             Status = AE_OK;
    UINT8                   ObjectType;
    UINT32                  ArgTypes;
    const ACPI_OPCODE_INFO  *OpInfo;
    UINT32                  ThisArgType;
    ACPI_OBJECT_TYPE        TypeNeeded;
    UINT16                  TargetOp = 0;


    ACPI_FUNCTION_TRACE_U32 (ExResolveOperands, Opcode);


    OpInfo = AcpiPsGetOpcodeInfo (Opcode);
    if (OpInfo->Class == AML_CLASS_UNKNOWN)
    {
        return_ACPI_STATUS (AE_AML_BAD_OPCODE);
    }

    ArgTypes = OpInfo->RuntimeArgs;
    if (ArgTypes == ARGI_INVALID_OPCODE)
    {
        ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X",
            Opcode));

        return_ACPI_STATUS (AE_AML_INTERNAL);
    }

    ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
        "Opcode %X [%s] RequiredOperandTypes=%8.8X\n",
        Opcode, OpInfo->Name, ArgTypes));

    /*
     * Normal exit is with (ArgTypes == 0) at end of argument list.
     * Function will return an exception from within the loop upon
     * finding an entry which is not (or cannot be converted
     * to) the required type; if stack underflows; or upon
     * finding a NULL stack entry (which should not happen).
     */
    while (GET_CURRENT_ARG_TYPE (ArgTypes))
    {
        if (!StackPtr || !*StackPtr)
        {
            ACPI_ERROR ((AE_INFO, "Null stack entry at %p",
                StackPtr));

            return_ACPI_STATUS (AE_AML_INTERNAL);
        }

        /* Extract useful items */

        ObjDesc = *StackPtr;

        /* Decode the descriptor type */

        switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc))
        {
        case ACPI_DESC_TYPE_NAMED:

            /* Namespace Node */

            ObjectType = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type;

            /*
             * Resolve an alias object. The construction of these objects
             * guarantees that there is only one level of alias indirection;
             * thus, the attached object is always the aliased namespace node
             */
            if (ObjectType == ACPI_TYPE_LOCAL_ALIAS)
            {
                ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) ObjDesc);
                *StackPtr = ObjDesc;
                ObjectType = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type;
            }
            break;


        case ACPI_DESC_TYPE_OPERAND:

            /* ACPI internal object */

            ObjectType = ObjDesc->Common.Type;

            /* Check for bad ACPI_OBJECT_TYPE */

            if (!AcpiUtValidObjectType (ObjectType))
            {
                ACPI_ERROR ((AE_INFO,
                    "Bad operand object type [0x%X]", ObjectType));

                return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
            }

            if (ObjectType == (UINT8) ACPI_TYPE_LOCAL_REFERENCE)
            {
                /* Validate the Reference */

                switch (ObjDesc->Reference.Class)
                {
                case ACPI_REFCLASS_DEBUG:

                    TargetOp = AML_DEBUG_OP;

                    /*lint -fallthrough */

                case ACPI_REFCLASS_ARG:
                case ACPI_REFCLASS_LOCAL:
                case ACPI_REFCLASS_INDEX:
                case ACPI_REFCLASS_REFOF:
                case ACPI_REFCLASS_TABLE:    /* DdbHandle from LOAD_OP or LOAD_TABLE_OP */
                case ACPI_REFCLASS_NAME:     /* Reference to a named object */

                    ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
                        "Operand is a Reference, Class [%s] %2.2X\n",
                        AcpiUtGetReferenceName (ObjDesc),
                        ObjDesc->Reference.Class));
                    break;

                default:

                    ACPI_ERROR ((AE_INFO,
                        "Unknown Reference Class 0x%2.2X in %p",
                        ObjDesc->Reference.Class, ObjDesc));

                    return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
                }
            }
            break;


        default:

            /* Invalid descriptor */

            ACPI_ERROR ((AE_INFO, "Invalid descriptor %p [%s]",
                ObjDesc, AcpiUtGetDescriptorName (ObjDesc)));

            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
        }

        /* Get one argument type, point to the next */

        ThisArgType = GET_CURRENT_ARG_TYPE (ArgTypes);
        INCREMENT_ARG_LIST (ArgTypes);

        /*
         * Handle cases where the object does not need to be
         * resolved to a value
         */
        switch (ThisArgType)
        {
        case ARGI_REF_OR_STRING:        /* Can be a String or Reference */

            if ((ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) == ACPI_DESC_TYPE_OPERAND) &&
                (ObjDesc->Common.Type == ACPI_TYPE_STRING))
            {
                /*
                 * String found - the string references a named object and
                 * must be resolved to a node
                 */
                goto NextOperand;
            }

            /*
             * Else not a string - fall through to the normal Reference
             * case below
             */
            /*lint -fallthrough */

        case ARGI_REFERENCE:            /* References: */
        case ARGI_INTEGER_REF:
        case ARGI_OBJECT_REF:
        case ARGI_DEVICE_REF:
        case ARGI_TARGETREF:     /* Allows implicit conversion rules before store */
        case ARGI_FIXED_TARGET:  /* No implicit conversion before store to target */
        case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion  */

            /*
             * Need an operand of type ACPI_TYPE_LOCAL_REFERENCE
             * A Namespace Node is OK as-is
             */
            if (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) == ACPI_DESC_TYPE_NAMED)
            {
                goto NextOperand;
            }

            Status = AcpiExCheckObjectType (ACPI_TYPE_LOCAL_REFERENCE,
                            ObjectType, ObjDesc);
            if (ACPI_FAILURE (Status))
            {
                return_ACPI_STATUS (Status);
            }
            goto NextOperand;


        case ARGI_DATAREFOBJ:  /* Store operator only */

            /*
             * We don't want to resolve IndexOp reference objects during
             * a store because this would be an implicit DeRefOf operation.
             * Instead, we just want to store the reference object.
             * -- All others must be resolved below.
             */
            if ((Opcode == AML_STORE_OP) &&
                ((*StackPtr)->Common.Type == ACPI_TYPE_LOCAL_REFERENCE) &&
                ((*StackPtr)->Reference.Class == ACPI_REFCLASS_INDEX))
            {
                goto NextOperand;
            }
            break;

        default:
            /* All cases covered above */
            break;
        }

        /*
         * Resolve this object to a value
         */
        Status = AcpiExResolveToValue (StackPtr, WalkState);
        if (ACPI_FAILURE (Status))
        {
            return_ACPI_STATUS (Status);
        }

        /* Get the resolved object */

        ObjDesc = *StackPtr;

        /*
         * Check the resulting object (value) type
         */
        switch (ThisArgType)
        {
        /*
         * For the simple cases, only one type of resolved object
         * is allowed
         */
        case ARGI_MUTEX:

            /* Need an operand of type ACPI_TYPE_MUTEX */

            TypeNeeded = ACPI_TYPE_MUTEX;
            break;

        case ARGI_EVENT:

            /* Need an operand of type ACPI_TYPE_EVENT */

            TypeNeeded = ACPI_TYPE_EVENT;
            break;

        case ARGI_PACKAGE:   /* Package */

            /* Need an operand of type ACPI_TYPE_PACKAGE */

            TypeNeeded = ACPI_TYPE_PACKAGE;
            break;

        case ARGI_ANYTYPE:

            /* Any operand type will do */

            TypeNeeded = ACPI_TYPE_ANY;
            break;

        case ARGI_DDBHANDLE:

            /* Need an operand of type ACPI_TYPE_DDB_HANDLE */

            TypeNeeded = ACPI_TYPE_LOCAL_REFERENCE;
            break;


        /*
         * The more complex cases allow multiple resolved object types
         */
        case ARGI_INTEGER:

            /*
             * Need an operand of type ACPI_TYPE_INTEGER,
             * But we can implicitly convert from a STRING or BUFFER
             * Aka - "Implicit Source Operand Conversion"
             */
            Status = AcpiExConvertToInteger (ObjDesc, StackPtr, 16);
            if (ACPI_FAILURE (Status))
            {
                if (Status == AE_TYPE)
                {
                    ACPI_ERROR ((AE_INFO,
                        "Needed [Integer/String/Buffer], found [%s] %p",
                        AcpiUtGetObjectTypeName (ObjDesc), ObjDesc));

                    return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
                }

                return_ACPI_STATUS (Status);
            }

            if (ObjDesc != *StackPtr)
            {
                AcpiUtRemoveReference (ObjDesc);
            }
            goto NextOperand;


        case ARGI_BUFFER:

            /*
             * Need an operand of type ACPI_TYPE_BUFFER,
             * But we can implicitly convert from a STRING or INTEGER
             * Aka - "Implicit Source Operand Conversion"
             */
            Status = AcpiExConvertToBuffer (ObjDesc, StackPtr);
            if (ACPI_FAILURE (Status))
            {
                if (Status == AE_TYPE)
                {
                    ACPI_ERROR ((AE_INFO,
                        "Needed [Integer/String/Buffer], found [%s] %p",
                        AcpiUtGetObjectTypeName (ObjDesc), ObjDesc));

                    return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
                }

                return_ACPI_STATUS (Status);
            }

            if (ObjDesc != *StackPtr)
            {
                AcpiUtRemoveReference (ObjDesc);
            }
            goto NextOperand;


        case ARGI_STRING:

            /*
             * Need an operand of type ACPI_TYPE_STRING,
             * But we can implicitly convert from a BUFFER or INTEGER
             * Aka - "Implicit Source Operand Conversion"
             */
            Status = AcpiExConvertToString (ObjDesc, StackPtr,
                        ACPI_IMPLICIT_CONVERT_HEX);
            if (ACPI_FAILURE (Status))
            {
                if (Status == AE_TYPE)
                {
                    ACPI_ERROR ((AE_INFO,
                        "Needed [Integer/String/Buffer], found [%s] %p",
                        AcpiUtGetObjectTypeName (ObjDesc), ObjDesc));

                    return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
                }

                return_ACPI_STATUS (Status);
            }

            if (ObjDesc != *StackPtr)
            {
                AcpiUtRemoveReference (ObjDesc);
            }
            goto NextOperand;


        case ARGI_COMPUTEDATA:

            /* Need an operand of type INTEGER, STRING or BUFFER */

            switch (ObjDesc->Common.Type)
            {
            case ACPI_TYPE_INTEGER:
            case ACPI_TYPE_STRING:
            case ACPI_TYPE_BUFFER:

                /* Valid operand */
               break;

            default:
                ACPI_ERROR ((AE_INFO,
                    "Needed [Integer/String/Buffer], found [%s] %p",
                    AcpiUtGetObjectTypeName (ObjDesc), ObjDesc));

                return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
            }
            goto NextOperand;


        case ARGI_BUFFER_OR_STRING:

            /* Need an operand of type STRING or BUFFER */

            switch (ObjDesc->Common.Type)
            {
            case ACPI_TYPE_STRING:
            case ACPI_TYPE_BUFFER:

                /* Valid operand */
               break;

            case ACPI_TYPE_INTEGER:

                /* Highest priority conversion is to type Buffer */

                Status = AcpiExConvertToBuffer (ObjDesc, StackPtr);
                if (ACPI_FAILURE (Status))
                {
                    return_ACPI_STATUS (Status);
                }

                if (ObjDesc != *StackPtr)
                {
                    AcpiUtRemoveReference (ObjDesc);
                }
                break;

            default:
                ACPI_ERROR ((AE_INFO,
                    "Needed [Integer/String/Buffer], found [%s] %p",
                    AcpiUtGetObjectTypeName (ObjDesc), ObjDesc));

                return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
            }
            goto NextOperand;


        case ARGI_DATAOBJECT:
            /*
             * ARGI_DATAOBJECT is only used by the SizeOf operator.
             * Need a buffer, string, package, or RefOf reference.
             *
             * The only reference allowed here is a direct reference to
             * a namespace node.
             */
            switch (ObjDesc->Common.Type)
            {
            case ACPI_TYPE_PACKAGE:
            case ACPI_TYPE_STRING:
            case ACPI_TYPE_BUFFER:
            case ACPI_TYPE_LOCAL_REFERENCE:

                /* Valid operand */
                break;

            default:
                ACPI_ERROR ((AE_INFO,
                    "Needed [Buffer/String/Package/Reference], found [%s] %p",
                    AcpiUtGetObjectTypeName (ObjDesc), ObjDesc));

                return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
            }
            goto NextOperand;


        case ARGI_COMPLEXOBJ:

            /* Need a buffer or package or (ACPI 2.0) String */

            switch (ObjDesc->Common.Type)
            {
            case ACPI_TYPE_PACKAGE:
            case ACPI_TYPE_STRING:
            case ACPI_TYPE_BUFFER:

                /* Valid operand */
                break;

            default:
                ACPI_ERROR ((AE_INFO,
                    "Needed [Buffer/String/Package], found [%s] %p",
                    AcpiUtGetObjectTypeName (ObjDesc), ObjDesc));

                return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
            }
            goto NextOperand;


        case ARGI_REGION_OR_BUFFER: /* Used by Load() only */

            /* Need an operand of type REGION or a BUFFER (which could be a resolved region field) */

            switch (ObjDesc->Common.Type)
            {
            case ACPI_TYPE_BUFFER:
            case ACPI_TYPE_REGION:

                /* Valid operand */
                break;

            default:
                ACPI_ERROR ((AE_INFO,
                    "Needed [Region/Buffer], found [%s] %p",
                    AcpiUtGetObjectTypeName (ObjDesc), ObjDesc));

                return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
            }
            goto NextOperand;


        case ARGI_DATAREFOBJ:

            /* Used by the Store() operator only */

            switch (ObjDesc->Common.Type)
            {
            case ACPI_TYPE_INTEGER:
            case ACPI_TYPE_PACKAGE:
            case ACPI_TYPE_STRING:
            case ACPI_TYPE_BUFFER:
            case ACPI_TYPE_BUFFER_FIELD:
            case ACPI_TYPE_LOCAL_REFERENCE:
            case ACPI_TYPE_LOCAL_REGION_FIELD:
            case ACPI_TYPE_LOCAL_BANK_FIELD:
            case ACPI_TYPE_LOCAL_INDEX_FIELD:
            case ACPI_TYPE_DDB_HANDLE:

                /* Valid operand */
                break;

            default:

                if (AcpiGbl_EnableInterpreterSlack)
                {
                    /*
                     * Enable original behavior of Store(), allowing any and all
                     * objects as the source operand.  The ACPI spec does not
                     * allow this, however.
                     */
                    break;
                }

                if (TargetOp == AML_DEBUG_OP)
                {
                    /* Allow store of any object to the Debug object */

                    break;
                }

                ACPI_ERROR ((AE_INFO,
                    "Needed Integer/Buffer/String/Package/Ref/Ddb], found [%s] %p",
                    AcpiUtGetObjectTypeName (ObjDesc), ObjDesc));

                return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
            }
            goto NextOperand;


        default:

            /* Unknown type */

            ACPI_ERROR ((AE_INFO,
                "Internal - Unknown ARGI (required operand) type 0x%X",
                ThisArgType));

            return_ACPI_STATUS (AE_BAD_PARAMETER);
        }

        /*
         * Make sure that the original object was resolved to the
         * required object type (Simple cases only).
         */
        Status = AcpiExCheckObjectType (TypeNeeded,
                        (*StackPtr)->Common.Type, *StackPtr);
        if (ACPI_FAILURE (Status))
        {
            return_ACPI_STATUS (Status);
        }

NextOperand:
        /*
         * If more operands needed, decrement StackPtr to point
         * to next operand on stack
         */
        if (GET_CURRENT_ARG_TYPE (ArgTypes))
        {
            StackPtr--;
        }
    }

    ACPI_DUMP_OPERANDS (WalkState->Operands,
        AcpiPsGetOpcodeName (Opcode), WalkState->NumOperands);

    return_ACPI_STATUS (Status);
}
Ejemplo n.º 6
0
acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
{
	acpi_status status = AE_OK;
	acpi_status status2;
	union acpi_parse_object *op = NULL;	/* current op */
	union acpi_parse_object *arg = NULL;
	union acpi_parse_object *pre_op = NULL;
	struct acpi_parse_state *parser_state;
	u8 *aml_op_start = NULL;

	ACPI_FUNCTION_TRACE_PTR("ps_parse_loop", walk_state);

	if (walk_state->descending_callback == NULL) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	parser_state = &walk_state->parser_state;
	walk_state->arg_types = 0;

#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))

	if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) {
		/* We are restarting a preempted control method */

		if (acpi_ps_has_completed_scope(parser_state)) {
			/*
			 * We must check if a predicate to an IF or WHILE statement
			 * was just completed
			 */
			if ((parser_state->scope->parse_scope.op) &&
			    ((parser_state->scope->parse_scope.op->common.
			      aml_opcode == AML_IF_OP)
			     || (parser_state->scope->parse_scope.op->common.
				 aml_opcode == AML_WHILE_OP))
			    && (walk_state->control_state)
			    && (walk_state->control_state->common.state ==
				ACPI_CONTROL_PREDICATE_EXECUTING)) {
				/*
				 * A predicate was just completed, get the value of the
				 * predicate and branch based on that value
				 */
				walk_state->op = NULL;
				status =
				    acpi_ds_get_predicate_value(walk_state,
								ACPI_TO_POINTER
								(TRUE));
				if (ACPI_FAILURE(status)
				    && ((status & AE_CODE_MASK) !=
					AE_CODE_CONTROL)) {
					if (status == AE_AML_NO_RETURN_VALUE) {
						ACPI_EXCEPTION((AE_INFO, status,
								"Invoked method did not return a value"));

					}
					ACPI_EXCEPTION((AE_INFO, status,
							"get_predicate Failed"));
					return_ACPI_STATUS(status);
				}

				status =
				    acpi_ps_next_parse_state(walk_state, op,
							     status);
			}

			acpi_ps_pop_scope(parser_state, &op,
					  &walk_state->arg_types,
					  &walk_state->arg_count);
			ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
					  "Popped scope, Op=%p\n", op));
		} else if (walk_state->prev_op) {
			/* We were in the middle of an op */

			op = walk_state->prev_op;
			walk_state->arg_types = walk_state->prev_arg_types;
		}
	}
#endif

	/* Iterative parsing loop, while there is more AML to process: */

	while ((parser_state->aml < parser_state->aml_end) || (op)) {
		aml_op_start = parser_state->aml;
		if (!op) {
			/* Get the next opcode from the AML stream */

			walk_state->aml_offset =
			    (u32) ACPI_PTR_DIFF(parser_state->aml,
						parser_state->aml_start);
			walk_state->opcode = acpi_ps_peek_opcode(parser_state);

			/*
			 * First cut to determine what we have found:
			 * 1) A valid AML opcode
			 * 2) A name string
			 * 3) An unknown/invalid opcode
			 */
			walk_state->op_info =
			    acpi_ps_get_opcode_info(walk_state->opcode);
			switch (walk_state->op_info->class) {
			case AML_CLASS_ASCII:
			case AML_CLASS_PREFIX:
				/*
				 * Starts with a valid prefix or ASCII char, this is a name
				 * string.  Convert the bare name string to a namepath.
				 */
				walk_state->opcode = AML_INT_NAMEPATH_OP;
				walk_state->arg_types = ARGP_NAMESTRING;
				break;

			case AML_CLASS_UNKNOWN:

				/* The opcode is unrecognized.  Just skip unknown opcodes */

				ACPI_ERROR((AE_INFO,
					    "Found unknown opcode %X at AML address %p offset %X, ignoring",
					    walk_state->opcode,
					    parser_state->aml,
					    walk_state->aml_offset));

				ACPI_DUMP_BUFFER(parser_state->aml, 128);

				/* Assume one-byte bad opcode */

				parser_state->aml++;
				continue;

			default:

				/* Found opcode info, this is a normal opcode */

				parser_state->aml +=
				    acpi_ps_get_opcode_size(walk_state->opcode);
				walk_state->arg_types =
				    walk_state->op_info->parse_args;
				break;
			}

			/* Create Op structure and append to parent's argument list */

			if (walk_state->op_info->flags & AML_NAMED) {
				/* Allocate a new pre_op if necessary */

				if (!pre_op) {
					pre_op =
					    acpi_ps_alloc_op(walk_state->
							     opcode);
					if (!pre_op) {
						status = AE_NO_MEMORY;
						goto close_this_op;
					}
				}

				pre_op->common.value.arg = NULL;
				pre_op->common.aml_opcode = walk_state->opcode;

				/*
				 * Get and append arguments until we find the node that contains
				 * the name (the type ARGP_NAME).
				 */
				while (GET_CURRENT_ARG_TYPE
				       (walk_state->arg_types)
				       &&
				       (GET_CURRENT_ARG_TYPE
					(walk_state->arg_types) != ARGP_NAME)) {
					status =
					    acpi_ps_get_next_arg(walk_state,
								 parser_state,
								 GET_CURRENT_ARG_TYPE
								 (walk_state->
								  arg_types),
								 &arg);
					if (ACPI_FAILURE(status)) {
						goto close_this_op;
					}

					acpi_ps_append_arg(pre_op, arg);
					INCREMENT_ARG_LIST(walk_state->
							   arg_types);
				}

				/*
				 * Make sure that we found a NAME and didn't run out of
				 * arguments
				 */
				if (!GET_CURRENT_ARG_TYPE
				    (walk_state->arg_types)) {
					status = AE_AML_NO_OPERAND;
					goto close_this_op;
				}

				/* We know that this arg is a name, move to next arg */

				INCREMENT_ARG_LIST(walk_state->arg_types);

				/*
				 * Find the object.  This will either insert the object into
				 * the namespace or simply look it up
				 */
				walk_state->op = NULL;

				status =
				    walk_state->descending_callback(walk_state,
								    &op);
				if (ACPI_FAILURE(status)) {
					ACPI_EXCEPTION((AE_INFO, status,
							"During name lookup/catalog"));
					goto close_this_op;
				}

				if (!op) {
					continue;
				}

				status =
				    acpi_ps_next_parse_state(walk_state, op,
							     status);
				if (status == AE_CTRL_PENDING) {
					status = AE_OK;
					goto close_this_op;
				}

				if (ACPI_FAILURE(status)) {
					goto close_this_op;
				}

				acpi_ps_append_arg(op,
						   pre_op->common.value.arg);
				acpi_gbl_depth++;

				if (op->common.aml_opcode == AML_REGION_OP) {
					/*
					 * Defer final parsing of an operation_region body,
					 * because we don't have enough info in the first pass
					 * to parse it correctly (i.e., there may be method
					 * calls within the term_arg elements of the body.)
					 *
					 * However, we must continue parsing because
					 * the opregion is not a standalone package --
					 * we don't know where the end is at this point.
					 *
					 * (Length is unknown until parse of the body complete)
					 */
					op->named.data = aml_op_start;
					op->named.length = 0;
				}
			} else {
				/* Not a named opcode, just allocate Op and append to parent */

				walk_state->op_info =
				    acpi_ps_get_opcode_info(walk_state->opcode);
				op = acpi_ps_alloc_op(walk_state->opcode);
				if (!op) {
					status = AE_NO_MEMORY;
					goto close_this_op;
				}

				if (walk_state->op_info->flags & AML_CREATE) {
					/*
					 * Backup to beginning of create_xXXfield declaration
					 * body_length is unknown until we parse the body
					 */
					op->named.data = aml_op_start;
					op->named.length = 0;
				}

				acpi_ps_append_arg(acpi_ps_get_parent_scope
						   (parser_state), op);

				if ((walk_state->descending_callback != NULL)) {
					/*
					 * Find the object. This will either insert the object into
					 * the namespace or simply look it up
					 */
					walk_state->op = op;

					status =
					    walk_state->
					    descending_callback(walk_state,
								&op);
					status =
					    acpi_ps_next_parse_state(walk_state,
								     op,
								     status);
					if (status == AE_CTRL_PENDING) {
						status = AE_OK;
						goto close_this_op;
					}

					if (ACPI_FAILURE(status)) {
						goto close_this_op;
					}
				}
			}

			op->common.aml_offset = walk_state->aml_offset;

			if (walk_state->op_info) {
				ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
						  "Opcode %4.4X [%s] Op %p Aml %p aml_offset %5.5X\n",
						  (u32) op->common.aml_opcode,
						  walk_state->op_info->name, op,
						  parser_state->aml,
						  op->common.aml_offset));
			}
		}

		/*
		 * Start arg_count at zero because we don't know if there are
		 * any args yet
		 */
		walk_state->arg_count = 0;

		/* Are there any arguments that must be processed? */

		if (walk_state->arg_types) {
			/* Get arguments */

			switch (op->common.aml_opcode) {
			case AML_BYTE_OP:	/* AML_BYTEDATA_ARG */
			case AML_WORD_OP:	/* AML_WORDDATA_ARG */
			case AML_DWORD_OP:	/* AML_DWORDATA_ARG */
			case AML_QWORD_OP:	/* AML_QWORDATA_ARG */
			case AML_STRING_OP:	/* AML_ASCIICHARLIST_ARG */

				/* Fill in constant or string argument directly */

				acpi_ps_get_next_simple_arg(parser_state,
							    GET_CURRENT_ARG_TYPE
							    (walk_state->
							     arg_types), op);
				break;

			case AML_INT_NAMEPATH_OP:	/* AML_NAMESTRING_ARG */

				status =
				    acpi_ps_get_next_namepath(walk_state,
							      parser_state, op,
							      1);
				if (ACPI_FAILURE(status)) {
					goto close_this_op;
				}

				walk_state->arg_types = 0;
				break;

			default:
				/*
				 * Op is not a constant or string, append each argument
				 * to the Op
				 */
				while (GET_CURRENT_ARG_TYPE
				       (walk_state->arg_types)
				       && !walk_state->arg_count) {
					walk_state->aml_offset = (u32)
					    ACPI_PTR_DIFF(parser_state->aml,
							  parser_state->
							  aml_start);

					status =
					    acpi_ps_get_next_arg(walk_state,
								 parser_state,
								 GET_CURRENT_ARG_TYPE
								 (walk_state->
								  arg_types),
								 &arg);
					if (ACPI_FAILURE(status)) {
						goto close_this_op;
					}

					if (arg) {
						arg->common.aml_offset =
						    walk_state->aml_offset;
						acpi_ps_append_arg(op, arg);
					}
					INCREMENT_ARG_LIST(walk_state->
							   arg_types);
				}

				/* Special processing for certain opcodes */

				/* TBD (remove): Temporary mechanism to disable this code if needed */

#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE

				if ((walk_state->pass_number <=
				     ACPI_IMODE_LOAD_PASS1)
				    &&
				    ((walk_state->
				      parse_flags & ACPI_PARSE_DISASSEMBLE) ==
				     0)) {
					/*
					 * We want to skip If/Else/While constructs during Pass1
					 * because we want to actually conditionally execute the
					 * code during Pass2.
					 *
					 * Except for disassembly, where we always want to
					 * walk the If/Else/While packages
					 */
					switch (op->common.aml_opcode) {
					case AML_IF_OP:
					case AML_ELSE_OP:
					case AML_WHILE_OP:

						ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
								  "Pass1: Skipping an If/Else/While body\n"));

						/* Skip body of if/else/while in pass 1 */

						parser_state->aml =
						    parser_state->pkg_end;
						walk_state->arg_count = 0;
						break;

					default:
						break;
					}
				}
#endif
				switch (op->common.aml_opcode) {
				case AML_METHOD_OP:

					/*
					 * Skip parsing of control method
					 * because we don't have enough info in the first pass
					 * to parse it correctly.
					 *
					 * Save the length and address of the body
					 */
					op->named.data = parser_state->aml;
					op->named.length =
					    (u32) (parser_state->pkg_end -
						   parser_state->aml);

					/* Skip body of method */

					parser_state->aml =
					    parser_state->pkg_end;
					walk_state->arg_count = 0;
					break;

				case AML_BUFFER_OP:
				case AML_PACKAGE_OP:
				case AML_VAR_PACKAGE_OP:

					if ((op->common.parent) &&
					    (op->common.parent->common.
					     aml_opcode == AML_NAME_OP)
					    && (walk_state->pass_number <=
						ACPI_IMODE_LOAD_PASS2)) {
						/*
						 * Skip parsing of Buffers and Packages
						 * because we don't have enough info in the first pass
						 * to parse them correctly.
						 */
						op->named.data = aml_op_start;
						op->named.length =
						    (u32) (parser_state->
							   pkg_end -
							   aml_op_start);

						/* Skip body */

						parser_state->aml =
						    parser_state->pkg_end;
						walk_state->arg_count = 0;
					}
					break;

				case AML_WHILE_OP:

					if (walk_state->control_state) {
						walk_state->control_state->
						    control.package_end =
						    parser_state->pkg_end;
					}
					break;

				default:

					/* No action for all other opcodes */
					break;
				}
				break;
			}
		}

		/* Check for arguments that need to be processed */

		if (walk_state->arg_count) {
			/*
			 * There are arguments (complex ones), push Op and
			 * prepare for argument
			 */
			status = acpi_ps_push_scope(parser_state, op,
						    walk_state->arg_types,
						    walk_state->arg_count);
			if (ACPI_FAILURE(status)) {
				goto close_this_op;
			}
			op = NULL;
			continue;
		}

		/*
		 * All arguments have been processed -- Op is complete,
		 * prepare for next
		 */
		walk_state->op_info =
		    acpi_ps_get_opcode_info(op->common.aml_opcode);
		if (walk_state->op_info->flags & AML_NAMED) {
			if (acpi_gbl_depth) {
				acpi_gbl_depth--;
			}

			if (op->common.aml_opcode == AML_REGION_OP) {
				/*
				 * Skip parsing of control method or opregion body,
				 * because we don't have enough info in the first pass
				 * to parse them correctly.
				 *
				 * Completed parsing an op_region declaration, we now
				 * know the length.
				 */
				op->named.length =
				    (u32) (parser_state->aml - op->named.data);
			}
		}

		if (walk_state->op_info->flags & AML_CREATE) {
			/*
			 * Backup to beginning of create_xXXfield declaration (1 for
			 * Opcode)
			 *
			 * body_length is unknown until we parse the body
			 */
			op->named.length =
			    (u32) (parser_state->aml - op->named.data);
		}

		/* This op complete, notify the dispatcher */

		if (walk_state->ascending_callback != NULL) {
			walk_state->op = op;
			walk_state->opcode = op->common.aml_opcode;

			status = walk_state->ascending_callback(walk_state);
			status =
			    acpi_ps_next_parse_state(walk_state, op, status);
			if (status == AE_CTRL_PENDING) {
				status = AE_OK;
				goto close_this_op;
			}
		}

	      close_this_op:
		/*
		 * Finished one argument of the containing scope
		 */
		parser_state->scope->parse_scope.arg_count--;

		/* Finished with pre_op */

		if (pre_op) {
			acpi_ps_free_op(pre_op);
			pre_op = NULL;
		}

		/* Close this Op (will result in parse subtree deletion) */

		status2 = acpi_ps_complete_this_op(walk_state, op);
		if (ACPI_FAILURE(status2)) {
			return_ACPI_STATUS(status2);
		}
		op = NULL;

		switch (status) {
		case AE_OK:
			break;

		case AE_CTRL_TRANSFER:

			/* We are about to transfer to a called method. */

			walk_state->prev_op = op;
			walk_state->prev_arg_types = walk_state->arg_types;
			return_ACPI_STATUS(status);

		case AE_CTRL_END:

			acpi_ps_pop_scope(parser_state, &op,
					  &walk_state->arg_types,
					  &walk_state->arg_count);

			if (op) {
				walk_state->op = op;
				walk_state->op_info =
				    acpi_ps_get_opcode_info(op->common.
							    aml_opcode);
				walk_state->opcode = op->common.aml_opcode;

				status =
				    walk_state->ascending_callback(walk_state);
				status =
				    acpi_ps_next_parse_state(walk_state, op,
							     status);

				status2 =
				    acpi_ps_complete_this_op(walk_state, op);
				if (ACPI_FAILURE(status2)) {
					return_ACPI_STATUS(status2);
				}
				op = NULL;
			}
			status = AE_OK;
			break;

		case AE_CTRL_BREAK:
		case AE_CTRL_CONTINUE:

			/* Pop off scopes until we find the While */

			while (!op || (op->common.aml_opcode != AML_WHILE_OP)) {
				acpi_ps_pop_scope(parser_state, &op,
						  &walk_state->arg_types,
						  &walk_state->arg_count);

				if (op->common.aml_opcode != AML_WHILE_OP) {
					status2 =
					    acpi_ds_result_stack_pop
					    (walk_state);
					if (ACPI_FAILURE(status2)) {
						return_ACPI_STATUS(status2);
					}
				}
			}

			/* Close this iteration of the While loop */

			walk_state->op = op;
			walk_state->op_info =
			    acpi_ps_get_opcode_info(op->common.aml_opcode);
			walk_state->opcode = op->common.aml_opcode;

			status = walk_state->ascending_callback(walk_state);
			status =
			    acpi_ps_next_parse_state(walk_state, op, status);

			status2 = acpi_ps_complete_this_op(walk_state, op);
			if (ACPI_FAILURE(status2)) {
				return_ACPI_STATUS(status2);
			}
			op = NULL;

			status = AE_OK;
			break;

		case AE_CTRL_TERMINATE:

			status = AE_OK;

			/* Clean up */
			do {
				if (op) {
					status2 =
					    acpi_ps_complete_this_op(walk_state,
								     op);
					if (ACPI_FAILURE(status2)) {
						return_ACPI_STATUS(status2);
					}
				}
				acpi_ps_pop_scope(parser_state, &op,
						  &walk_state->arg_types,
						  &walk_state->arg_count);

			} while (op);

			return_ACPI_STATUS(status);

		default:	/* All other non-AE_OK status */

			do {
				if (op) {
					status2 =
					    acpi_ps_complete_this_op(walk_state,
								     op);
					if (ACPI_FAILURE(status2)) {
						return_ACPI_STATUS(status2);
					}
				}
				acpi_ps_pop_scope(parser_state, &op,
						  &walk_state->arg_types,
						  &walk_state->arg_count);

			} while (op);

			/*
			 * TBD: Cleanup parse ops on error
			 */
#if 0
			if (op == NULL) {
				acpi_ps_pop_scope(parser_state, &op,
						  &walk_state->arg_types,
						  &walk_state->arg_count);
			}
#endif
			walk_state->prev_op = op;
			walk_state->prev_arg_types = walk_state->arg_types;
			return_ACPI_STATUS(status);
		}

		/* This scope complete? */

		if (acpi_ps_has_completed_scope(parser_state)) {
			acpi_ps_pop_scope(parser_state, &op,
					  &walk_state->arg_types,
					  &walk_state->arg_count);
			ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
					  "Popped scope, Op=%p\n", op));
		} else {
			op = NULL;
		}

	}			/* while parser_state->Aml */
Ejemplo n.º 7
0
ACPI_STATUS
AcpiPsParseLoop (
    ACPI_WALK_STATE         *WalkState)
{
    ACPI_STATUS             Status = AE_OK;
    ACPI_PARSE_OBJECT       *Op = NULL;     /* current op */
    const ACPI_OPCODE_INFO  *OpInfo;
    ACPI_PARSE_OBJECT       *Arg = NULL;
    ACPI_PARSE2_OBJECT      *DeferredOp;
    UINT32                  ArgCount;       /* push for fixed or var args */
    UINT32                  ArgTypes = 0;
    UINT32                  AmlOffset;
    UINT16                  Opcode;
    ACPI_PARSE_OBJECT       PreOp;
    ACPI_PARSE_STATE        *ParserState;
    UINT8                   *AmlOpStart;


    FUNCTION_TRACE_PTR ("PsParseLoop", WalkState);


    ParserState = WalkState->ParserState;

#ifndef PARSER_ONLY
    if (WalkState->WalkType & WALK_METHOD_RESTART)
    {
        /* We are restarting a preempted control method */

        if (AcpiPsHasCompletedScope (ParserState))
        {
            /*
             * We must check if a predicate to an IF or WHILE statement
             * was just completed
             */
            if ((ParserState->Scope->ParseScope.Op) &&
                ((ParserState->Scope->ParseScope.Op->Opcode == AML_IF_OP) ||
                (ParserState->Scope->ParseScope.Op->Opcode == AML_WHILE_OP)) &&
                (WalkState->ControlState) &&
                (WalkState->ControlState->Common.State ==
                    CONTROL_PREDICATE_EXECUTING))
            {

                /*
                 * A predicate was just completed, get the value of the
                 * predicate and branch based on that value
                 */
                Status = AcpiDsGetPredicateValue (WalkState, NULL, TRUE);
                if (ACPI_FAILURE (Status) &&
                    ((Status & AE_CODE_MASK) != AE_CODE_CONTROL))
                {
                    if (Status == AE_AML_NO_RETURN_VALUE)
                    {
                        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
                            "Invoked method did not return a value, %s\n",
                            AcpiFormatException (Status)));

                    }
                    ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "GetPredicate Failed, %s\n",
                        AcpiFormatException (Status)));
                    return_ACPI_STATUS (Status);
                }

                Status = AcpiPsNextParseState (WalkState, Op, Status);
            }

            AcpiPsPopScope (ParserState, &Op, &ArgTypes, &ArgCount);
            ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", Op));
        }

        else if (WalkState->PrevOp)
        {
            /* We were in the middle of an op */

            Op = WalkState->PrevOp;
            ArgTypes = WalkState->PrevArgTypes;
        }
    }
#endif

    /*
     * Iterative parsing loop, while there is more aml to process:
     */
    while ((ParserState->Aml < ParserState->AmlEnd) || (Op))
    {
        if (!Op)
        {
            /* Get the next opcode from the AML stream */

            AmlOpStart = ParserState->Aml;
            AmlOffset  = ParserState->Aml - ParserState->AmlStart;
            Opcode     = AcpiPsPeekOpcode (ParserState);

            /*
             * First cut to determine what we have found:
             * 1) A valid AML opcode
             * 2) A name string
             * 3) An unknown/invalid opcode
             */
            OpInfo = AcpiPsGetOpcodeInfo (Opcode);
            switch (ACPI_GET_OP_TYPE (OpInfo))
            {
            case ACPI_OP_TYPE_OPCODE:

                /* Found opcode info, this is a normal opcode */

                ParserState->Aml += AcpiPsGetOpcodeSize (Opcode);
                ArgTypes = OpInfo->ParseArgs;
                break;

            case ACPI_OP_TYPE_ASCII:
            case ACPI_OP_TYPE_PREFIX:
                /*
                 * Starts with a valid prefix or ASCII char, this is a name
                 * string.  Convert the bare name string to a namepath.
                 */
                Opcode = AML_INT_NAMEPATH_OP;
                ArgTypes = ARGP_NAMESTRING;
                break;

            case ACPI_OP_TYPE_UNKNOWN:

                /* The opcode is unrecognized.  Just skip unknown opcodes */

                ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
                    "Found unknown opcode %lX at AML offset %X, ignoring\n",
                    Opcode, AmlOffset));

                DUMP_BUFFER (ParserState->Aml, 128);

                /* Assume one-byte bad opcode */

                ParserState->Aml++;
                continue;
            }


            /* Create Op structure and append to parent's argument list */

            if (OpInfo->Flags & AML_NAMED)
            {
                PreOp.Value.Arg = NULL;
                PreOp.Opcode = Opcode;

                while (GET_CURRENT_ARG_TYPE (ArgTypes) != ARGP_NAME)
                {
                    Arg = AcpiPsGetNextArg (ParserState,
                                            GET_CURRENT_ARG_TYPE (ArgTypes),
                                            &ArgCount);
                    AcpiPsAppendArg (&PreOp, Arg);
                    INCREMENT_ARG_LIST (ArgTypes);
                }


                /* We know that this arg is a name, move to next arg */

                INCREMENT_ARG_LIST (ArgTypes);

                if (WalkState->DescendingCallback != NULL)
                {
                    /*
                     * Find the object.  This will either insert the object into
                     * the namespace or simply look it up
                     */
                    Status = WalkState->DescendingCallback (Opcode, NULL, WalkState, &Op);
                    if (Op == NULL)
                    {
                        continue;
                    }
                    Status = AcpiPsNextParseState (WalkState, Op, Status);
                    if (Status == AE_CTRL_PENDING)
                    {
                        Status = AE_OK;
                        goto CloseThisOp;
                    }

                    if (ACPI_FAILURE (Status))
                    {
                        goto CloseThisOp;
                    }
                }

                AcpiPsAppendArg (Op, PreOp.Value.Arg);
                AcpiGbl_Depth++;


                if (Op->Opcode == AML_REGION_OP)
                {
                    DeferredOp = (ACPI_PARSE2_OBJECT *) Op;

                    /*
                     * Defer final parsing of an OperationRegion body,
                     * because we don't have enough info in the first pass
                     * to parse it correctly (i.e., there may be method
                     * calls within the TermArg elements of the body.
                     *
                     * However, we must continue parsing because
                     * the opregion is not a standalone package --
                     * we don't know where the end is at this point.
                     *
                     * (Length is unknown until parse of the body complete)
                     */
                    DeferredOp->Data    = AmlOpStart;
                    DeferredOp->Length  = 0;
                }
            }


            else
            {
                /* Not a named opcode, just allocate Op and append to parent */

                OpInfo = AcpiPsGetOpcodeInfo (Opcode);
                Op = AcpiPsAllocOp (Opcode);
                if (!Op)
                {
                    return_ACPI_STATUS (AE_NO_MEMORY);
                }


                if (OpInfo->Flags & AML_CREATE)
                {
                    /*
                     * Backup to beginning of CreateXXXfield declaration
                     * BodyLength is unknown until we parse the body
                     */
                    DeferredOp = (ACPI_PARSE2_OBJECT *) Op;

                    DeferredOp->Data    = AmlOpStart;
                    DeferredOp->Length  = 0;
                }

                AcpiPsAppendArg (AcpiPsGetParentScope (ParserState), Op);

                if ((WalkState->DescendingCallback != NULL))
                {
                    /*
                     * Find the object.  This will either insert the object into
                     * the namespace or simply look it up
                     */
                    Status = WalkState->DescendingCallback (Opcode, Op, WalkState, &Op);
                    Status = AcpiPsNextParseState (WalkState, Op, Status);
                    if (Status == AE_CTRL_PENDING)
                    {
                        Status = AE_OK;
                        goto CloseThisOp;
                    }

                    if (ACPI_FAILURE (Status))
                    {
                        goto CloseThisOp;
                    }
                }
            }

            Op->AmlOffset = AmlOffset;

            if (OpInfo)
            {
                ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
                    "Op=%p Opcode=%4.4lX Aml %p Oft=%5.5lX\n",
                     Op, Op->Opcode, ParserState->Aml, Op->AmlOffset));
            }
        }


        /* Start ArgCount at zero because we don't know if there are any args yet */

        ArgCount  = 0;


        if (ArgTypes)   /* Are there any arguments that must be processed? */
        {
            /* get arguments */

            switch (Op->Opcode)
            {
            case AML_BYTE_OP:       /* AML_BYTEDATA_ARG */
            case AML_WORD_OP:       /* AML_WORDDATA_ARG */
            case AML_DWORD_OP:      /* AML_DWORDATA_ARG */
            case AML_QWORD_OP:      /* AML_QWORDATA_ARG */
            case AML_STRING_OP:     /* AML_ASCIICHARLIST_ARG */

                /* fill in constant or string argument directly */

                AcpiPsGetNextSimpleArg (ParserState,
                                        GET_CURRENT_ARG_TYPE (ArgTypes), Op);
                break;

            case AML_INT_NAMEPATH_OP:   /* AML_NAMESTRING_ARG */

                AcpiPsGetNextNamepath (ParserState, Op, &ArgCount, 1);
                ArgTypes = 0;
                break;


            default:

                /* Op is not a constant or string, append each argument */

                while (GET_CURRENT_ARG_TYPE (ArgTypes) && !ArgCount)
                {
                    AmlOffset = ParserState->Aml - ParserState->AmlStart;
                    Arg = AcpiPsGetNextArg (ParserState,
                                            GET_CURRENT_ARG_TYPE (ArgTypes),
                                            &ArgCount);
                    if (Arg)
                    {
                        Arg->AmlOffset = AmlOffset;
                        AcpiPsAppendArg (Op, Arg);
                    }

                    INCREMENT_ARG_LIST (ArgTypes);
                }


                /* For a method, save the length and address of the body */

                if (Op->Opcode == AML_METHOD_OP)
                {
                    DeferredOp = (ACPI_PARSE2_OBJECT *) Op;

                    /*
                     * Skip parsing of control method or opregion body,
                     * because we don't have enough info in the first pass
                     * to parse them correctly.
                     */
                    DeferredOp->Data    = ParserState->Aml;
                    DeferredOp->Length  = (UINT32) (ParserState->PkgEnd -
                                                    ParserState->Aml);

                    /*
                     * Skip body of method.  For OpRegions, we must continue
                     * parsing because the opregion is not a standalone
                     * package (We don't know where the end is).
                     */
                    ParserState->Aml    = ParserState->PkgEnd;
                    ArgCount            = 0;
                }

                break;
            }
        }


        /*
         * Zero ArgCount means that all arguments for this op have been processed
         */
        if (!ArgCount)
        {
            /* completed Op, prepare for next */

            OpInfo = AcpiPsGetOpcodeInfo (Op->Opcode);
            if (OpInfo->Flags & AML_NAMED)
            {
                if (AcpiGbl_Depth)
                {
                    AcpiGbl_Depth--;
                }

                if (Op->Opcode == AML_REGION_OP)
                {
                    DeferredOp = (ACPI_PARSE2_OBJECT *) Op;

                    /*
                     * Skip parsing of control method or opregion body,
                     * because we don't have enough info in the first pass
                     * to parse them correctly.
                     *
                     * Completed parsing an OpRegion declaration, we now
                     * know the length.
                     */
                    DeferredOp->Length = (UINT32) (ParserState->Aml -
                                                    DeferredOp->Data);
                }
            }

            if (OpInfo->Flags & AML_CREATE)
            {
                /*
                 * Backup to beginning of CreateXXXfield declaration (1 for
                 * Opcode)
                 *
                 * BodyLength is unknown until we parse the body
                 */
                DeferredOp = (ACPI_PARSE2_OBJECT *) Op;
                DeferredOp->Length = (UINT32) (ParserState->Aml -
                                               DeferredOp->Data);
            }

            /* This op complete, notify the dispatcher */

            if (WalkState->AscendingCallback != NULL)
            {
                Status = WalkState->AscendingCallback (WalkState, Op);
                Status = AcpiPsNextParseState (WalkState, Op, Status);
                if (Status == AE_CTRL_PENDING)
                {
                    Status = AE_OK;
                    goto CloseThisOp;
                }
            }


CloseThisOp:

            /*
             * Finished one argument of the containing scope
             */
            ParserState->Scope->ParseScope.ArgCount--;

            /* Close this Op (may result in parse subtree deletion) */

            if (AcpiPsCompleteThisOp (WalkState, Op))
            {
                Op = NULL;
            }


            switch (Status)
            {
            case AE_OK:
                break;


            case AE_CTRL_TRANSFER:

                /*
                 * We are about to transfer to a called method.
                 */
                WalkState->PrevOp = Op;
                WalkState->PrevArgTypes = ArgTypes;
                return_ACPI_STATUS (Status);
                break;


            case AE_CTRL_END:

                AcpiPsPopScope (ParserState, &Op, &ArgTypes, &ArgCount);

                Status = WalkState->AscendingCallback (WalkState, Op);
                Status = AcpiPsNextParseState (WalkState, Op, Status);

                AcpiPsCompleteThisOp (WalkState, Op);
                Op = NULL;
                Status = AE_OK;
                break;


            case AE_CTRL_TERMINATE:

                Status = AE_OK;

                /* Clean up */
                do
                {
                    if (Op)
                    {
                        AcpiPsCompleteThisOp (WalkState, Op);
                    }

                    AcpiPsPopScope (ParserState, &Op, &ArgTypes, &ArgCount);
                } while (Op);

                return_ACPI_STATUS (Status);
                break;


            default:  /* All other non-AE_OK status */

                if (Op == NULL)
                {
                    AcpiPsPopScope (ParserState, &Op, &ArgTypes, &ArgCount);
                }
                WalkState->PrevOp = Op;
                WalkState->PrevArgTypes = ArgTypes;

                /*
                 * TEMP:
                 */

                return_ACPI_STATUS (Status);
                break;
            }

            /* This scope complete? */

            if (AcpiPsHasCompletedScope (ParserState))
            {
                AcpiPsPopScope (ParserState, &Op, &ArgTypes, &ArgCount);
                ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", Op));
            }

            else
            {
                Op = NULL;
            }

        }


        /* ArgCount is non-zero */

        else
        {
            /* complex argument, push Op and prepare for argument */

            AcpiPsPushScope (ParserState, Op, ArgTypes, ArgCount);
            Op = NULL;
        }

    } /* while ParserState->Aml */


    /*
     * Complete the last Op (if not completed), and clear the scope stack.
     * It is easily possible to end an AML "package" with an unbounded number
     * of open scopes (such as when several AML blocks are closed with
     * sequential closing braces).  We want to terminate each one cleanly.
     */
    ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Package complete at Op %p\n", Op));
    do
    {
        if (Op)
        {
            if (WalkState->AscendingCallback != NULL)
            {
                Status = WalkState->AscendingCallback (WalkState, Op);
                Status = AcpiPsNextParseState (WalkState, Op, Status);
                if (Status == AE_CTRL_PENDING)
                {
                    Status = AE_OK;
                    goto CloseThisOp;
                }

                if (Status == AE_CTRL_TERMINATE)
                {
                    Status = AE_OK;

                    /* Clean up */
                    do
                    {
                        if (Op)
                        {
                            AcpiPsCompleteThisOp (WalkState, Op);
                        }

                        AcpiPsPopScope (ParserState, &Op, &ArgTypes, &ArgCount);

                    } while (Op);

                    return_ACPI_STATUS (Status);
                }

                else if (ACPI_FAILURE (Status))
                {
                    AcpiPsCompleteThisOp (WalkState, Op);
                    return_ACPI_STATUS (Status);
                }
            }

            AcpiPsCompleteThisOp (WalkState, Op);
        }

        AcpiPsPopScope (ParserState, &Op, &ArgTypes, &ArgCount);

    } while (Op);

    return_ACPI_STATUS (Status);
}
Ejemplo n.º 8
0
ACPI_STATUS
acpi_aml_resolve_operands (
	u16                     opcode,
	ACPI_OPERAND_OBJECT     **stack_ptr,
	ACPI_WALK_STATE         *walk_state)
{
	ACPI_OPERAND_OBJECT     *obj_desc;
	ACPI_STATUS             status = AE_OK;
	u8                      object_type;
	ACPI_HANDLE             temp_handle;
	u32                     arg_types;
	ACPI_OPCODE_INFO        *op_info;
	u32                     this_arg_type;
	ACPI_OBJECT_TYPE        type_needed;


	op_info = acpi_ps_get_opcode_info (opcode);
	if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) {
		return (AE_AML_BAD_OPCODE);
	}


	arg_types = op_info->runtime_args;
	if (arg_types == ARGI_INVALID_OPCODE) {
		return (AE_AML_INTERNAL);
	}


   /*
	 * Normal exit is with *Types == '\0' at end of string.
	 * Function will return an exception from within the loop upon
	 * finding an entry which is not, and cannot be converted
	 * to, the required type; if stack underflows; or upon
	 * finding a NULL stack entry (which "should never happen").
	 */

	while (GET_CURRENT_ARG_TYPE (arg_types)) {
		if (!stack_ptr || !*stack_ptr) {
			return (AE_AML_INTERNAL);
		}

		/* Extract useful items */

		obj_desc = *stack_ptr;

		/* Decode the descriptor type */

		if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) {
			/* Node */

			object_type = ((ACPI_NAMESPACE_NODE *) obj_desc)->type;
		}

		else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_INTERNAL)) {
			/* ACPI internal object */

			object_type = obj_desc->common.type;

			/* Check for bad ACPI_OBJECT_TYPE */

			if (!acpi_aml_validate_object_type (object_type)) {
				return (AE_AML_OPERAND_TYPE);
			}

			if (object_type == (u8) INTERNAL_TYPE_REFERENCE) {
				/*
				 * Decode the Reference
				 */

				op_info = acpi_ps_get_opcode_info (opcode);
				if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) {
					return (AE_AML_BAD_OPCODE);
				}


				switch (obj_desc->reference.op_code)
				{
				case AML_ZERO_OP:
				case AML_ONE_OP:
				case AML_ONES_OP:
				case AML_DEBUG_OP:
				case AML_NAME_OP:
				case AML_INDEX_OP:
				case AML_ARG_OP:
				case AML_LOCAL_OP:

					break;

				default:
					return (AE_AML_OPERAND_TYPE);
					break;
				}
			}
		}

		else {
			/* Invalid descriptor */

			return (AE_AML_OPERAND_TYPE);
		}


		/*
		 * Get one argument type, point to the next
		 */

		this_arg_type = GET_CURRENT_ARG_TYPE (arg_types);
		INCREMENT_ARG_LIST (arg_types);


		/*
		 * Handle cases where the object does not need to be
		 * resolved to a value
		 */

		switch (this_arg_type)
		{

		case ARGI_REFERENCE:   /* Reference */
		case ARGI_TARGETREF:

			/* Need an operand of type INTERNAL_TYPE_REFERENCE */

			if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED))            /* direct name ptr OK as-is */ {
				goto next_operand;
			}

			status = acpi_aml_check_object_type (INTERNAL_TYPE_REFERENCE,
					  object_type, obj_desc);
			if (ACPI_FAILURE (status)) {
				return (status);
			}


			if (AML_NAME_OP == obj_desc->reference.op_code) {
				/*
				 * Convert an indirect name ptr to direct name ptr and put
				 * it on the stack
				 */

				temp_handle = obj_desc->reference.object;
				acpi_cm_remove_reference (obj_desc);
				(*stack_ptr) = temp_handle;
			}

			goto next_operand;
			break;


		case ARGI_ANYTYPE:

			/*
			 * We don't want to resolve Index_op reference objects during
			 * a store because this would be an implicit De_ref_of operation.
			 * Instead, we just want to store the reference object.
			 * -- All others must be resolved below.
			 */

			if ((opcode == AML_STORE_OP) &&
				((*stack_ptr)->common.type == INTERNAL_TYPE_REFERENCE) &&
				((*stack_ptr)->reference.op_code == AML_INDEX_OP))
			{
				goto next_operand;
			}
			break;
		}


		/*
		 * Resolve this object to a value
		 */

		status = acpi_aml_resolve_to_value (stack_ptr, walk_state);
		if (ACPI_FAILURE (status)) {
			return (status);
		}


		/*
		 * Check the resulting object (value) type
		 */
		switch (this_arg_type)
		{
		/*
		 * For the simple cases, only one type of resolved object
		 * is allowed
		 */
		case ARGI_NUMBER:   /* Number */

			/* Need an operand of type ACPI_TYPE_NUMBER */

			type_needed = ACPI_TYPE_NUMBER;
			break;

		case ARGI_BUFFER:

			/* Need an operand of type ACPI_TYPE_BUFFER */

			type_needed = ACPI_TYPE_BUFFER;
			break;

		case ARGI_MUTEX:

			/* Need an operand of type ACPI_TYPE_MUTEX */

			type_needed = ACPI_TYPE_MUTEX;
			break;

		case ARGI_EVENT:

			/* Need an operand of type ACPI_TYPE_EVENT */

			type_needed = ACPI_TYPE_EVENT;
			break;

		case ARGI_REGION:

			/* Need an operand of type ACPI_TYPE_REGION */

			type_needed = ACPI_TYPE_REGION;
			break;

		case ARGI_IF:   /* If */

			/* Need an operand of type INTERNAL_TYPE_IF */

			type_needed = INTERNAL_TYPE_IF;
			break;

		case ARGI_PACKAGE:   /* Package */

			/* Need an operand of type ACPI_TYPE_PACKAGE */

			type_needed = ACPI_TYPE_PACKAGE;
			break;

		case ARGI_ANYTYPE:

			/* Any operand type will do */

			type_needed = ACPI_TYPE_ANY;
			break;


		/*
		 * The more complex cases allow multiple resolved object types
		 */

		case ARGI_STRING:

			/* Need an operand of type ACPI_TYPE_STRING or ACPI_TYPE_BUFFER */

			if ((ACPI_TYPE_STRING != (*stack_ptr)->common.type) &&
				(ACPI_TYPE_BUFFER != (*stack_ptr)->common.type))
			{
				return (AE_AML_OPERAND_TYPE);
			}
			goto next_operand;
			break;


		case ARGI_DATAOBJECT:
			/*
			 * ARGI_DATAOBJECT is only used by the Size_of operator.
			 *
			 * The ACPI specification allows Size_of to return the size of
			 *  a Buffer, String or Package.  However, the MS ACPI.SYS AML
			 *  Interpreter also allows an Node reference to return without
			 *  error with a size of 4.
			 */

			/* Need a buffer, string, package or Node reference */

			if (((*stack_ptr)->common.type != ACPI_TYPE_BUFFER) &&
				((*stack_ptr)->common.type != ACPI_TYPE_STRING) &&
				((*stack_ptr)->common.type != ACPI_TYPE_PACKAGE) &&
				((*stack_ptr)->common.type != INTERNAL_TYPE_REFERENCE))
			{
				return (AE_AML_OPERAND_TYPE);
			}

			/*
			 * If this is a reference, only allow a reference to an Node.
			 */
			if ((*stack_ptr)->common.type == INTERNAL_TYPE_REFERENCE) {
				if (!(*stack_ptr)->reference.node) {
					return (AE_AML_OPERAND_TYPE);
				}
			}
			goto next_operand;
			break;


		case ARGI_COMPLEXOBJ:

			/* Need a buffer or package */

			if (((*stack_ptr)->common.type != ACPI_TYPE_BUFFER) &&
				((*stack_ptr)->common.type != ACPI_TYPE_PACKAGE))
			{
				return (AE_AML_OPERAND_TYPE);
			}
			goto next_operand;
			break;


		default:

			/* Unknown type */

			return (AE_BAD_PARAMETER);
		}


		/*
		 * Make sure that the original object was resolved to the
		 * required object type (Simple cases only).
		 */
		status = acpi_aml_check_object_type (type_needed,
				  (*stack_ptr)->common.type, *stack_ptr);
		if (ACPI_FAILURE (status)) {
			return (status);
		}


next_operand:
		/*
		 * If more operands needed, decrement Stack_ptr to point
		 * to next operand on stack
		 */
		if (GET_CURRENT_ARG_TYPE (arg_types)) {
			stack_ptr--;
		}

	}   /* while (*Types) */


	return (status);
}
Ejemplo n.º 9
0
static ACPI_STATUS
AcpiPsGetArguments (
    ACPI_WALK_STATE         *WalkState,
    UINT8                   *AmlOpStart,
    ACPI_PARSE_OBJECT       *Op)
{
    ACPI_STATUS             Status = AE_OK;
    ACPI_PARSE_OBJECT       *Arg = NULL;
    const ACPI_OPCODE_INFO  *OpInfo;


    ACPI_FUNCTION_TRACE_PTR (PsGetArguments, WalkState);


    ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
        "Get arguments for opcode [%s]\n", Op->Common.AmlOpName));

    switch (Op->Common.AmlOpcode)
    {
    case AML_BYTE_OP:       /* AML_BYTEDATA_ARG */
    case AML_WORD_OP:       /* AML_WORDDATA_ARG */
    case AML_DWORD_OP:      /* AML_DWORDATA_ARG */
    case AML_QWORD_OP:      /* AML_QWORDATA_ARG */
    case AML_STRING_OP:     /* AML_ASCIICHARLIST_ARG */

        /* Fill in constant or string argument directly */

        AcpiPsGetNextSimpleArg (&(WalkState->ParserState),
            GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), Op);
        break;

    case AML_INT_NAMEPATH_OP:   /* AML_NAMESTRING_ARG */

        Status = AcpiPsGetNextNamepath (WalkState,
            &(WalkState->ParserState), Op, ACPI_POSSIBLE_METHOD_CALL);
        if (ACPI_FAILURE (Status))
        {
            return_ACPI_STATUS (Status);
        }

        WalkState->ArgTypes = 0;
        break;

    default:
        /*
         * Op is not a constant or string, append each argument to the Op
         */
        while (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) &&
            !WalkState->ArgCount)
        {
            WalkState->Aml = WalkState->ParserState.Aml;

            switch (Op->Common.AmlOpcode)
            {
            case AML_METHOD_OP:
            case AML_BUFFER_OP:
            case AML_PACKAGE_OP:
            case AML_VARIABLE_PACKAGE_OP:
            case AML_WHILE_OP:

                break;

            default:

                ASL_CV_CAPTURE_COMMENTS (WalkState);
                break;
            }

            Status = AcpiPsGetNextArg (WalkState, &(WalkState->ParserState),
                GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), &Arg);
            if (ACPI_FAILURE (Status))
            {
                return_ACPI_STATUS (Status);
            }

            if (Arg)
            {
                AcpiPsAppendArg (Op, Arg);
            }

            INCREMENT_ARG_LIST (WalkState->ArgTypes);
        }

        ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
            "Final argument count: %8.8X pass %u\n",
            WalkState->ArgCount, WalkState->PassNumber));

        /*
         * This case handles the legacy option that groups all module-level
         * code blocks together and defers execution until all of the tables
         * are loaded. Execute all of these blocks at this time.
         * Execute any module-level code that was detected during the table
         * load phase.
         *
         * Note: this option is deprecated and will be eliminated in the
         * future. Use of this option can cause problems with AML code that
         * depends upon in-order immediate execution of module-level code.
         */
        if (AcpiGbl_GroupModuleLevelCode &&
            (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2) &&
            ((WalkState->ParseFlags & ACPI_PARSE_DISASSEMBLE) == 0))
        {
            /*
             * We want to skip If/Else/While constructs during Pass1 because we
             * want to actually conditionally execute the code during Pass2.
             *
             * Except for disassembly, where we always want to walk the
             * If/Else/While packages
             */
            switch (Op->Common.AmlOpcode)
            {
            case AML_IF_OP:
            case AML_ELSE_OP:
            case AML_WHILE_OP:
                /*
                 * Currently supported module-level opcodes are:
                 * IF/ELSE/WHILE. These appear to be the most common,
                 * and easiest to support since they open an AML
                 * package.
                 */
                if (WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1)
                {
                    AcpiPsLinkModuleCode (Op->Common.Parent, AmlOpStart,
                        (UINT32) (WalkState->ParserState.PkgEnd - AmlOpStart),
                        WalkState->OwnerId);
                }

                ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
                    "Pass1: Skipping an If/Else/While body\n"));

                /* Skip body of if/else/while in pass 1 */

                WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
                WalkState->ArgCount = 0;
                break;

            default:
                /*
                 * Check for an unsupported executable opcode at module
                 * level. We must be in PASS1, the parent must be a SCOPE,
                 * The opcode class must be EXECUTE, and the opcode must
                 * not be an argument to another opcode.
                 */
                if ((WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) &&
                    (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP))
                {
                    OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
                    if ((OpInfo->Class == AML_CLASS_EXECUTE) &&
                        (!Arg))
                    {
                        ACPI_WARNING ((AE_INFO,
                            "Unsupported module-level executable opcode "
                            "0x%.2X at table offset 0x%.4X",
                            Op->Common.AmlOpcode,
                            (UINT32) (ACPI_PTR_DIFF (AmlOpStart,
                                WalkState->ParserState.AmlStart) +
                                sizeof (ACPI_TABLE_HEADER))));
                    }
                }
                break;
            }
        }

        /* Special processing for certain opcodes */

        switch (Op->Common.AmlOpcode)
        {
        case AML_METHOD_OP:
            /*
             * Skip parsing of control method because we don't have enough
             * info in the first pass to parse it correctly.
             *
             * Save the length and address of the body
             */
            Op->Named.Data = WalkState->ParserState.Aml;
            Op->Named.Length = (UINT32)
                (WalkState->ParserState.PkgEnd - WalkState->ParserState.Aml);

            /* Skip body of method */

            WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
            WalkState->ArgCount = 0;
            break;

        case AML_BUFFER_OP:
        case AML_PACKAGE_OP:
        case AML_VARIABLE_PACKAGE_OP:

            if ((Op->Common.Parent) &&
                (Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) &&
                (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2))
            {
                ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
                    "Setup Package/Buffer: Pass %u, AML Ptr: %p\n",
                    WalkState->PassNumber, AmlOpStart));

                /*
                 * Skip parsing of Buffers and Packages because we don't have
                 * enough info in the first pass to parse them correctly.
                 */
                Op->Named.Data = AmlOpStart;
                Op->Named.Length = (UINT32)
                    (WalkState->ParserState.PkgEnd - AmlOpStart);

                /* Skip body */

                WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
                WalkState->ArgCount = 0;
            }
            break;

        case AML_WHILE_OP:

            if (WalkState->ControlState)
            {
                WalkState->ControlState->Control.PackageEnd =
                    WalkState->ParserState.PkgEnd;
            }
            break;

        default:

            /* No action for all other opcodes */

            break;
        }

        break;
    }

    return_ACPI_STATUS (AE_OK);
}