Example #1
0
acpi_status
acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
               union acpi_parse_object ** out_op)
{
    union acpi_parse_object *op;
    struct acpi_namespace_node *node;
    acpi_status status;
    acpi_object_type object_type;
    char *path;
    u32 flags;

    ACPI_FUNCTION_TRACE(ds_load1_begin_op);

    op = walk_state->op;
    ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op,
              walk_state));

    /* We are only interested in opcodes that have an associated name */

    if (op) {
        if (!(walk_state->op_info->flags & AML_NAMED)) {
            *out_op = op;
            return_ACPI_STATUS(AE_OK);
        }

        /* Check if this object has already been installed in the namespace */

        if (op->common.node) {
            *out_op = op;
            return_ACPI_STATUS(AE_OK);
        }
    }

    path = acpi_ps_get_next_namestring(&walk_state->parser_state);

    /* Map the raw opcode into an internal object type */

    object_type = walk_state->op_info->object_type;

    ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
              "State=%p Op=%p [%s]\n", walk_state, op,
              acpi_ut_get_type_name(object_type)));

    switch (walk_state->opcode) {
    case AML_SCOPE_OP:

        /*
         * The target name of the Scope() operator must exist at this point so
         * that we can actually open the scope to enter new names underneath it.
         * Allow search-to-root for single namesegs.
         */
        status =
            acpi_ns_lookup(walk_state->scope_info, path, object_type,
                   ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT,
                   walk_state, &(node));
#ifdef ACPI_ASL_COMPILER
        if (status == AE_NOT_FOUND) {
            /*
             * Table disassembly:
             * Target of Scope() not found. Generate an External for it, and
             * insert the name into the namespace.
             */
            acpi_dm_add_to_external_list(path, ACPI_TYPE_DEVICE, 0);
            status =
                acpi_ns_lookup(walk_state->scope_info, path,
                       object_type, ACPI_IMODE_LOAD_PASS1,
                       ACPI_NS_SEARCH_PARENT, walk_state,
                       &node);
        }
#endif
        if (ACPI_FAILURE(status)) {
            ACPI_ERROR_NAMESPACE(path, status);
            return_ACPI_STATUS(status);
        }

        /*
         * Check to make sure that the target is
         * one of the opcodes that actually opens a scope
         */
        switch (node->type) {
        case ACPI_TYPE_ANY:
        case ACPI_TYPE_LOCAL_SCOPE:    /* Scope  */
        case ACPI_TYPE_DEVICE:
        case ACPI_TYPE_POWER:
        case ACPI_TYPE_PROCESSOR:
        case ACPI_TYPE_THERMAL:

            /* These are acceptable types */
            break;

        case ACPI_TYPE_INTEGER:
        case ACPI_TYPE_STRING:
        case ACPI_TYPE_BUFFER:

            /*
             * These types we will allow, but we will change the type. This
             * enables some existing code of the form:
             *
             *  Name (DEB, 0)
             *  Scope (DEB) { ... }
             *
             * Note: silently change the type here. On the second pass, we will report
             * a warning
             */
            ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                      "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n",
                      path,
                      acpi_ut_get_type_name(node->type)));

            node->type = ACPI_TYPE_ANY;
            walk_state->scope_info->common.value = ACPI_TYPE_ANY;
            break;

        default:

            /* All other types are an error */

            ACPI_ERROR((AE_INFO,
                    "Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)",
                    acpi_ut_get_type_name(node->type), path));

            return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
        }
        break;

    default:
        /*
         * For all other named opcodes, we will enter the name into
         * the namespace.
         *
         * Setup the search flags.
         * Since we are entering a name into the namespace, we do not want to
         * enable the search-to-root upsearch.
         *
         * There are only two conditions where it is acceptable that the name
         * already exists:
         *    1) the Scope() operator can reopen a scoping object that was
         *       previously defined (Scope, Method, Device, etc.)
         *    2) Whenever we are parsing a deferred opcode (op_region, Buffer,
         *       buffer_field, or Package), the name of the object is already
         *       in the namespace.
         */
        if (walk_state->deferred_node) {

            /* This name is already in the namespace, get the node */

            node = walk_state->deferred_node;
            status = AE_OK;
            break;
        }

        /*
         * If we are executing a method, do not create any namespace objects
         * during the load phase, only during execution.
         */
        if (walk_state->method_node) {
            node = NULL;
            status = AE_OK;
            break;
        }

        flags = ACPI_NS_NO_UPSEARCH;
        if ((walk_state->opcode != AML_SCOPE_OP) &&
            (!(walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP))) {
            flags |= ACPI_NS_ERROR_IF_FOUND;
            ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
                      "[%s] Cannot already exist\n",
                      acpi_ut_get_type_name(object_type)));
        } else {
            ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
                      "[%s] Both Find or Create allowed\n",
                      acpi_ut_get_type_name(object_type)));
        }

        /*
         * Enter the named type into the internal namespace. We enter the name
         * as we go downward in the parse tree. Any necessary subobjects that
         * involve arguments to the opcode must be created as we go back up the
         * parse tree later.
         */
        status =
            acpi_ns_lookup(walk_state->scope_info, path, object_type,
                   ACPI_IMODE_LOAD_PASS1, flags, walk_state,
                   &node);
        if (ACPI_FAILURE(status)) {
            if (status == AE_ALREADY_EXISTS) {

                /* The name already exists in this scope */

                if (node->flags & ANOBJ_IS_EXTERNAL) {
                    /*
                     * Allow one create on an object or segment that was
                     * previously declared External
                     */
                    node->flags &= ~ANOBJ_IS_EXTERNAL;
                    node->type = (u8) object_type;

                    /* Just retyped a node, probably will need to open a scope */

                    if (acpi_ns_opens_scope(object_type)) {
                        status =
                            acpi_ds_scope_stack_push
                            (node, object_type,
                             walk_state);
                        if (ACPI_FAILURE(status)) {
                            return_ACPI_STATUS
                                (status);
                        }
                    }

                    status = AE_OK;
                }
            }

            if (ACPI_FAILURE(status)) {
                ACPI_ERROR_NAMESPACE(path, status);
                return_ACPI_STATUS(status);
            }
        }
        break;
    }

    /* Common exit */

    if (!op) {

        /* Create a new op */

        op = acpi_ps_alloc_op(walk_state->opcode);
        if (!op) {
            return_ACPI_STATUS(AE_NO_MEMORY);
        }
    }

    /* Initialize the op */

#if (defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY))
    op->named.path = ACPI_CAST_PTR(u8, path);
#endif

    if (node) {
        /*
         * Put the Node in the "op" object that the parser uses, so we
         * can get it again quickly when this scope is closed
         */
        op->common.node = node;
        op->named.name = node->name.integer;
    }

    acpi_ps_append_arg(acpi_ps_get_parent_scope(&walk_state->parser_state),
               op);
    *out_op = op;
    return_ACPI_STATUS(status);
}
Example #2
0
acpi_status
acpi_ps_create_op(struct acpi_walk_state *walk_state,
		  u8 *aml_op_start, union acpi_parse_object **new_op)
{
	acpi_status status = AE_OK;
	union acpi_parse_object *op;
	union acpi_parse_object *named_op = NULL;
	union acpi_parse_object *parent_scope;
	u8 argument_count;
	const struct acpi_opcode_info *op_info;

	ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state);

	status = acpi_ps_get_aml_opcode(walk_state);
	if (status == AE_CTRL_PARSE_CONTINUE) {
		return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
	}
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

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

	walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
	op = acpi_ps_alloc_op(walk_state->opcode, aml_op_start);
	if (!op) {
		return_ACPI_STATUS(AE_NO_MEMORY);
	}

	if (walk_state->op_info->flags & AML_NAMED) {
		status =
		    acpi_ps_build_named_op(walk_state, aml_op_start, op,
					   &named_op);
		acpi_ps_free_op(op);
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}

		*new_op = named_op;
		return_ACPI_STATUS(AE_OK);
	}

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

	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;
	}

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

	parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state));
	acpi_ps_append_arg(parent_scope, op);

	if (parent_scope) {
		op_info =
		    acpi_ps_get_opcode_info(parent_scope->common.aml_opcode);
		if (op_info->flags & AML_HAS_TARGET) {
			argument_count =
			    acpi_ps_get_argument_count(op_info->type);
			if (parent_scope->common.arg_list_length >
			    argument_count) {
				op->common.flags |= ACPI_PARSEOP_TARGET;
			}
		}

		/*
		 * Special case for both Increment() and Decrement(), where
		 * the lone argument is both a source and a target.
		 */
		else if ((parent_scope->common.aml_opcode == AML_INCREMENT_OP)
			 || (parent_scope->common.aml_opcode ==
			     AML_DECREMENT_OP)) {
			op->common.flags |= ACPI_PARSEOP_TARGET;
		}
	}

	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 = *new_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_CTRL_PARSE_PENDING;
		}
	}

	return_ACPI_STATUS(status);
}
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 */
Example #4
0
acpi_status
acpi_ds_load1_begin_op (
	acpi_walk_state         *walk_state,
	acpi_parse_object       **out_op)
{
	acpi_parse_object       *op;
	acpi_namespace_node     *node;
	acpi_status             status;
	acpi_object_type8       data_type;
	NATIVE_CHAR             *path;


	PROC_NAME ("Ds_load1_begin_op");

	op = walk_state->op;
	ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state));


	/* We are only interested in opcodes that have an associated name */

	if (walk_state->op) {
	   if (!(walk_state->op_info->flags & AML_NAMED)) {
			*out_op = op;
			return (AE_OK);
		}

		/* Check if this object has already been installed in the namespace */

		if (op->node) {
			*out_op = op;
			return (AE_OK);
		}
	}

	path = acpi_ps_get_next_namestring (&walk_state->parser_state);

	/* Map the raw opcode into an internal object type */

	data_type = acpi_ds_map_named_opcode_to_data_type (walk_state->opcode);


	ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
		"State=%p Op=%p Type=%x\n", walk_state, op, data_type));


	if (walk_state->opcode == AML_SCOPE_OP) {
		ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
			"State=%p Op=%p Type=%x\n", walk_state, op, data_type));
	}

	/*
	 * Enter the named type into the internal namespace.  We enter the name
	 * as we go downward in the parse tree.  Any necessary subobjects that involve
	 * arguments to the opcode must be created as we go back up the parse tree later.
	 */
	status = acpi_ns_lookup (walk_state->scope_info, path, data_type,
			  IMODE_LOAD_PASS1, NS_NO_UPSEARCH, walk_state, &(node));

	if (ACPI_FAILURE (status)) {
		return (status);
	}

	if (!op) {
		/* Create a new op */

		op = acpi_ps_alloc_op (walk_state->opcode);
		if (!op) {
			return (AE_NO_MEMORY);
		}
	}

	/* Initialize */

	((acpi_parse2_object *)op)->name = node->name;

	/*
	 * Put the Node in the "op" object that the parser uses, so we
	 * can get it again quickly when this scope is closed
	 */
	op->node = node;
	acpi_ps_append_arg (acpi_ps_get_parent_scope (&walk_state->parser_state), op);

	*out_op = op;
	return (status);
}
Example #5
0
void
acpi_ps_get_next_namepath (
	ACPI_PARSE_STATE        *parser_state,
	ACPI_PARSE_OBJECT       *arg,
	u32                     *arg_count,
	u8                      method_call)
{
	NATIVE_CHAR             *path;
	ACPI_PARSE_OBJECT       *name_op;
	ACPI_PARSE_OBJECT       *op;
	ACPI_PARSE_OBJECT       *count;


	path = acpi_ps_get_next_namestring (parser_state);
	if (!path || !method_call) {
		/* Null name case, create a null namepath object */

		acpi_ps_init_op (arg, AML_NAMEPATH_OP);
		arg->value.name = path;
		return;
	}


	if (acpi_gbl_parsed_namespace_root) {
		/*
		 * Lookup the name in the parsed namespace
		 */

		op = NULL;
		if (method_call) {
			op = acpi_ps_find (acpi_ps_get_parent_scope (parser_state),
					   path, AML_METHOD_OP, 0);
		}

		if (op) {
			if (op->opcode == AML_METHOD_OP) {
				/*
				 * The name refers to a control method, so this namepath is a
				 * method invocation.  We need to 1) Get the number of arguments
				 * associated with this method, and 2) Change the NAMEPATH
				 * object into a METHODCALL object.
				 */

				count = acpi_ps_get_arg (op, 0);
				if (count && count->opcode == AML_BYTE_OP) {
					name_op = acpi_ps_alloc_op (AML_NAMEPATH_OP);
					if (name_op) {
						/* Change arg into a METHOD CALL and attach the name */

						acpi_ps_init_op (arg, AML_METHODCALL_OP);

						name_op->value.name = path;

						/* Point METHODCALL/NAME to the METHOD Node */

						name_op->node = (ACPI_NAMESPACE_NODE *) op;
						acpi_ps_append_arg (arg, name_op);

						*arg_count = count->value.integer &
								 METHOD_FLAGS_ARG_COUNT;
					}
				}

				return;
			}

			/*
			 * Else this is normal named object reference.
			 * Just init the NAMEPATH object with the pathname.
			 * (See code below)
			 */
		}
	}


	/*
	 * Either we didn't find the object in the namespace, or the object is
	 * something other than a control method.  Just initialize the Op with the
	 * pathname
	 */

	acpi_ps_init_op (arg, AML_NAMEPATH_OP);
	arg->value.name = path;


	return;
}
Example #6
0
acpi_status
acpi_ps_create_op(struct acpi_walk_state *walk_state,
		  u8 *aml_op_start, union acpi_parse_object **new_op)
{
	acpi_status status = AE_OK;
	union acpi_parse_object *op;
	union acpi_parse_object *named_op = NULL;
	union acpi_parse_object *parent_scope;
	u8 argument_count;
	const struct acpi_opcode_info *op_info;

	ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state);

	status = acpi_ps_get_aml_opcode(walk_state);
	if (status == AE_CTRL_PARSE_CONTINUE) {
		return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
	}
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

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

	walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
	op = acpi_ps_alloc_op(walk_state->opcode, aml_op_start);
	if (!op) {
		return_ACPI_STATUS(AE_NO_MEMORY);
	}

	if (walk_state->op_info->flags & AML_NAMED) {
		status =
		    acpi_ps_build_named_op(walk_state, aml_op_start, op,
					   &named_op);
		acpi_ps_free_op(op);

#ifdef ACPI_ASL_COMPILER
		if (acpi_gbl_disasm_flag
		    && walk_state->opcode == AML_EXTERNAL_OP
		    && status == AE_NOT_FOUND) {
			/*
			 * If parsing of AML_EXTERNAL_OP's name path fails, then skip
			 * past this opcode and keep parsing. This is a much better
			 * alternative than to abort the entire disassembler. At this
			 * point, the parser_state is at the end of the namepath of the
			 * external declaration opcode. Setting walk_state->Aml to
			 * walk_state->parser_state.Aml + 2 moves increments the
			 * walk_state->Aml past the object type and the paramcount of the
			 * external opcode.
			 */
			walk_state->aml = walk_state->parser_state.aml + 2;
			walk_state->parser_state.aml = walk_state->aml;
			return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
		}
#endif
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}

		*new_op = named_op;
		return_ACPI_STATUS(AE_OK);
	}

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

	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;
	}

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

	parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state));
	acpi_ps_append_arg(parent_scope, op);

	if (parent_scope) {
		op_info =
		    acpi_ps_get_opcode_info(parent_scope->common.aml_opcode);
		if (op_info->flags & AML_HAS_TARGET) {
			argument_count =
			    acpi_ps_get_argument_count(op_info->type);
			if (parent_scope->common.arg_list_length >
			    argument_count) {
				op->common.flags |= ACPI_PARSEOP_TARGET;
			}
		}

		/*
		 * Special case for both Increment() and Decrement(), where
		 * the lone argument is both a source and a target.
		 */
		else if ((parent_scope->common.aml_opcode == AML_INCREMENT_OP)
			 || (parent_scope->common.aml_opcode ==
			     AML_DECREMENT_OP)) {
			op->common.flags |= ACPI_PARSEOP_TARGET;
		}
	}

	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 = *new_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_CTRL_PARSE_PENDING;
		}
	}

	return_ACPI_STATUS(status);
}