acpi_status acpi_tb_allocate_owner_id(u32 table_index)
{
    acpi_status status = AE_BAD_PARAMETER;

    ACPI_FUNCTION_TRACE(tb_allocate_owner_id);

    (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
    if (table_index < acpi_gbl_root_table_list.current_table_count) {
        status = acpi_ut_allocate_owner_id
                 (&(acpi_gbl_root_table_list.tables[table_index].owner_id));
    }

    (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
    return_ACPI_STATUS(status);
}
Ejemplo n.º 2
0
acpi_status
acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
			       union acpi_operand_object *obj_desc,
			       struct acpi_walk_state *walk_state)
{
	acpi_status status = AE_OK;

	ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node);

	if (!method_node) {
		return_ACPI_STATUS(AE_NULL_ENTRY);
	}

	/* Prevent wraparound of thread count */

	if (obj_desc->method.thread_count == ACPI_UINT8_MAX) {
		ACPI_ERROR((AE_INFO,
			    "Method reached maximum reentrancy limit (255)"));
		return_ACPI_STATUS(AE_AML_METHOD_LIMIT);
	}

	/*
	 * If this method is serialized, we need to acquire the method mutex.
	 */
	if (obj_desc->method.method_flags & AML_METHOD_SERIALIZED) {
		/*
		 * Create a mutex for the method if it is defined to be Serialized
		 * and a mutex has not already been created. We defer the mutex creation
		 * until a method is actually executed, to minimize the object count
		 */
		if (!obj_desc->method.mutex) {
			status = acpi_ds_create_method_mutex(obj_desc);
			if (ACPI_FAILURE(status)) {
				return_ACPI_STATUS(status);
			}
		}

		/*
		 * The current_sync_level (per-thread) must be less than or equal to
		 * the sync level of the method. This mechanism provides some
		 * deadlock prevention
		 *
		 * Top-level method invocation has no walk state at this point
		 */
		if (walk_state &&
		    (walk_state->thread->current_sync_level >
		     obj_desc->method.mutex->mutex.sync_level)) {
			ACPI_ERROR((AE_INFO,
				    "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%d)",
				    acpi_ut_get_node_name(method_node),
				    walk_state->thread->current_sync_level));

			return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
		}

		/*
		 * Obtain the method mutex if necessary. Do not acquire mutex for a
		 * recursive call.
		 */
		if (acpi_os_get_thread_id() !=
		    obj_desc->method.mutex->mutex.owner_thread_id) {
			/*
			 * Acquire the method mutex. This releases the interpreter if we
			 * block (and reacquires it before it returns)
			 */
			status =
			    acpi_ex_system_wait_mutex(obj_desc->method.mutex->
						      mutex.os_mutex,
						      ACPI_WAIT_FOREVER);
			if (ACPI_FAILURE(status)) {
				return_ACPI_STATUS(status);
			}

			/* Update the mutex and walk info and save the original sync_level */
			obj_desc->method.mutex->mutex.owner_thread_id =
				acpi_os_get_thread_id();

			if (walk_state) {
				obj_desc->method.mutex->mutex.
				    original_sync_level =
				    walk_state->thread->current_sync_level;

				walk_state->thread->current_sync_level =
				    obj_desc->method.sync_level;
			} else {
				obj_desc->method.mutex->mutex.
				    original_sync_level =
				    obj_desc->method.mutex->mutex.sync_level;
			}
		}

		/* Always increase acquisition depth */

		obj_desc->method.mutex->mutex.acquisition_depth++;
	}

	/*
	 * Allocate an Owner ID for this method, only if this is the first thread
	 * to begin concurrent execution. We only need one owner_id, even if the
	 * method is invoked recursively.
	 */
	if (!obj_desc->method.owner_id) {
		status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
		if (ACPI_FAILURE(status)) {
			goto cleanup;
		}
	}

	/*
	 * Increment the method parse tree thread count since it has been
	 * reentered one more time (even if it is the same thread)
	 */
	obj_desc->method.thread_count++;
	return_ACPI_STATUS(status);

      cleanup:
	/* On error, must release the method mutex (if present) */

	if (obj_desc->method.mutex) {
		acpi_os_release_mutex(obj_desc->method.mutex->mutex.os_mutex);
	}
	return_ACPI_STATUS(status);
}
Ejemplo n.º 3
0
acpi_status
acpi_tb_init_table_descriptor (
    acpi_table_type         table_type,
    acpi_table_desc         *table_info)
{
    acpi_table_desc         *list_head;
    acpi_table_desc         *table_desc;


    FUNCTION_TRACE_U32 ("Tb_init_table_descriptor", table_type);

    /*
     * Install the table into the global data structure
     */
    list_head   = &acpi_gbl_acpi_tables[table_type];
    table_desc  = list_head;


    /*
     * Two major types of tables:  1) Only one instance is allowed.  This
     * includes most ACPI tables such as the DSDT.  2) Multiple instances of
     * the table are allowed.  This includes SSDT and PSDTs.
     */
    if (IS_SINGLE_TABLE (acpi_gbl_acpi_table_data[table_type].flags)) {
        /*
         * Only one table allowed, and a table has alread been installed
         *  at this location, so return an error.
         */
        if (list_head->pointer) {
            return_ACPI_STATUS (AE_EXIST);
        }

        table_desc->count = 1;
    }


    else {
        /*
         * Multiple tables allowed for this table type, we must link
         * the new table in to the list of tables of this type.
         */
        if (list_head->pointer) {
            table_desc = ACPI_MEM_CALLOCATE (sizeof (acpi_table_desc));
            if (!table_desc) {
                return_ACPI_STATUS (AE_NO_MEMORY);
            }

            list_head->count++;

            /* Update the original previous */

            list_head->prev->next = table_desc;

            /* Update new entry */

            table_desc->prev = list_head->prev;
            table_desc->next = list_head;

            /* Update list head */

            list_head->prev = table_desc;
        }

        else {
            table_desc->count = 1;
        }
    }


    /* Common initialization of the table descriptor */

    table_desc->pointer             = table_info->pointer;
    table_desc->base_pointer        = table_info->base_pointer;
    table_desc->length              = table_info->length;
    table_desc->allocation          = table_info->allocation;
    table_desc->aml_start           = (u8 *) (table_desc->pointer + 1),
                table_desc->aml_length          = (u32) (table_desc->length -
                        (u32) sizeof (acpi_table_header));
    table_desc->table_id            = acpi_ut_allocate_owner_id (OWNER_TYPE_TABLE);
    table_desc->loaded_into_namespace = FALSE;

    /*
     * Set the appropriate global pointer (if there is one) to point to the
     * newly installed table
     */
    if (acpi_gbl_acpi_table_data[table_type].global_ptr) {
        *(acpi_gbl_acpi_table_data[table_type].global_ptr) = table_info->pointer;
    }


    /* Return Data */

    table_info->table_id        = table_desc->table_id;
    table_info->installed_desc  = table_desc;

    return_ACPI_STATUS (AE_OK);
}
Ejemplo n.º 4
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_ds_parse_method
 *
 * PARAMETERS:  Node        - Method node
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Parse the AML that is associated with the method.
 *
 * MUTEX:       Assumes parser is locked
 *
 ******************************************************************************/
acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node)
{
	acpi_status status;
	union acpi_operand_object *obj_desc;
	union acpi_parse_object *op;
	struct acpi_walk_state *walk_state;

	ACPI_FUNCTION_TRACE_PTR("ds_parse_method", node);

	/* Parameter Validation */

	if (!node) {
		return_ACPI_STATUS(AE_NULL_ENTRY);
	}

	ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
			  "**** Parsing [%4.4s] **** named_obj=%p\n",
			  acpi_ut_get_node_name(node), node));

	/* Extract the method object from the method Node */

	obj_desc = acpi_ns_get_attached_object(node);
	if (!obj_desc) {
		return_ACPI_STATUS(AE_NULL_OBJECT);
	}

	/* Create a mutex for the method if there is a concurrency limit */

	if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) &&
	    (!obj_desc->method.semaphore)) {
		status = acpi_os_create_semaphore(obj_desc->method.concurrency,
						  obj_desc->method.concurrency,
						  &obj_desc->method.semaphore);
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}
	}

	/*
	 * Allocate a new parser op to be the root of the parsed
	 * method tree
	 */
	op = acpi_ps_alloc_op(AML_METHOD_OP);
	if (!op) {
		return_ACPI_STATUS(AE_NO_MEMORY);
	}

	/* Init new op with the method name and pointer back to the Node */

	acpi_ps_set_name(op, node->name.integer);
	op->common.node = node;

	/*
	 * Get a new owner_id for objects created by this method. Namespace
	 * objects (such as Operation Regions) can be created during the
	 * first pass parse.
	 */
	status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
	if (ACPI_FAILURE(status)) {
		goto cleanup;
	}

	/* Create and initialize a new walk state */

	walk_state =
	    acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, NULL,
				      NULL);
	if (!walk_state) {
		status = AE_NO_MEMORY;
		goto cleanup2;
	}

	status = acpi_ds_init_aml_walk(walk_state, op, node,
				       obj_desc->method.aml_start,
				       obj_desc->method.aml_length, NULL, 1);
	if (ACPI_FAILURE(status)) {
		acpi_ds_delete_walk_state(walk_state);
		goto cleanup2;
	}

	/*
	 * Parse the method, first pass
	 *
	 * The first pass load is where newly declared named objects are added into
	 * the namespace.  Actual evaluation of the named objects (what would be
	 * called a "second pass") happens during the actual execution of the
	 * method so that operands to the named objects can take on dynamic
	 * run-time values.
	 */
	status = acpi_ps_parse_aml(walk_state);
	if (ACPI_FAILURE(status)) {
		goto cleanup2;
	}

	ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
			  "**** [%4.4s] Parsed **** named_obj=%p Op=%p\n",
			  acpi_ut_get_node_name(node), node, op));

	/*
	 * Delete the parse tree. We simply re-parse the method for every
	 * execution since there isn't much overhead (compared to keeping lots
	 * of parse trees around)
	 */
	acpi_ns_delete_namespace_subtree(node);
	acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id);

      cleanup2:
	acpi_ut_release_owner_id(&obj_desc->method.owner_id);

      cleanup:
	acpi_ps_delete_parse_tree(op);
	return_ACPI_STATUS(status);
}
Ejemplo n.º 5
0
acpi_status
acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
			       union acpi_operand_object *obj_desc,
			       struct acpi_namespace_node *calling_method_node)
{
	acpi_status status = AE_OK;

	ACPI_FUNCTION_TRACE_PTR("ds_begin_method_execution", method_node);

	if (!method_node) {
		return_ACPI_STATUS(AE_NULL_ENTRY);
	}

	/* Prevent wraparound of thread count */

	if (obj_desc->method.thread_count == ACPI_UINT8_MAX) {
		ACPI_REPORT_ERROR(("Method reached maximum reentrancy limit (255)\n"));
		return_ACPI_STATUS(AE_AML_METHOD_LIMIT);
	}

	/*
	 * If there is a concurrency limit on this method, we need to
	 * obtain a unit from the method semaphore.
	 */
	if (obj_desc->method.semaphore) {
		/*
		 * Allow recursive method calls, up to the reentrancy/concurrency
		 * limit imposed by the SERIALIZED rule and the sync_level method
		 * parameter.
		 *
		 * The point of this code is to avoid permanently blocking a
		 * thread that is making recursive method calls.
		 */
		if (method_node == calling_method_node) {
			if (obj_desc->method.thread_count >=
			    obj_desc->method.concurrency) {
				return_ACPI_STATUS(AE_AML_METHOD_LIMIT);
			}
		}

		/*
		 * Get a unit from the method semaphore. This releases the
		 * interpreter if we block
		 */
		status =
		    acpi_ex_system_wait_semaphore(obj_desc->method.semaphore,
						  ACPI_WAIT_FOREVER);
	}

	/*
	 * Allocate an Owner ID for this method, only if this is the first thread
	 * to begin concurrent execution. We only need one owner_id, even if the
	 * method is invoked recursively.
	 */
	if (!obj_desc->method.owner_id) {
		status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}
	}

	/*
	 * Increment the method parse tree thread count since it has been
	 * reentered one more time (even if it is the same thread)
	 */
	obj_desc->method.thread_count++;
	return_ACPI_STATUS(status);
}
Ejemplo n.º 6
0
acpi_status
acpi_ds_call_control_method (
	struct acpi_thread_state        *thread,
	struct acpi_walk_state          *this_walk_state,
	union acpi_parse_object         *op)
{
	acpi_status                     status;
	struct acpi_namespace_node      *method_node;
	union acpi_operand_object       *obj_desc;
	struct acpi_walk_state          *next_walk_state;
	u32                             i;


	ACPI_FUNCTION_TRACE_PTR ("ds_call_control_method", this_walk_state);

	ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Execute method %p, currentstate=%p\n",
		this_walk_state->prev_op, this_walk_state));

	/*
	 * Get the namespace entry for the control method we are about to call
	 */
	method_node = this_walk_state->method_call_node;
	if (!method_node) {
		return_ACPI_STATUS (AE_NULL_ENTRY);
	}

	obj_desc = acpi_ns_get_attached_object (method_node);
	if (!obj_desc) {
		return_ACPI_STATUS (AE_NULL_OBJECT);
	}

	obj_desc->method.owning_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_METHOD);

	/* Init for new method, wait on concurrency semaphore */

	status = acpi_ds_begin_method_execution (method_node, obj_desc,
			  this_walk_state->method_node);
	if (ACPI_FAILURE (status)) {
		return_ACPI_STATUS (status);
	}

	if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) {
		/* 1) Parse: Create a new walk state for the preempting walk */

		next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id,
				  op, obj_desc, NULL);
		if (!next_walk_state) {
			return_ACPI_STATUS (AE_NO_MEMORY);
		}


		/* Create and init a Root Node */

		op = acpi_ps_create_scope_op ();
		if (!op) {
			status = AE_NO_MEMORY;
			goto cleanup;
		}

		status = acpi_ds_init_aml_walk (next_walk_state, op, method_node,
				  obj_desc->method.aml_start, obj_desc->method.aml_length,
				  NULL, NULL, 1);
		if (ACPI_FAILURE (status)) {
			acpi_ds_delete_walk_state (next_walk_state);
			goto cleanup;
		}

		/* Begin AML parse */

		status = acpi_ps_parse_aml (next_walk_state);
		acpi_ps_delete_parse_tree (op);
	}

	/* 2) Execute: Create a new state for the preempting walk */

	next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id,
			  NULL, obj_desc, thread);
	if (!next_walk_state) {
		status = AE_NO_MEMORY;
		goto cleanup;
	}
	/*
	 * The resolved arguments were put on the previous walk state's operand
	 * stack.  Operands on the previous walk state stack always
	 * start at index 0.
	 * Null terminate the list of arguments
	 */
	this_walk_state->operands [this_walk_state->num_operands] = NULL;

	status = acpi_ds_init_aml_walk (next_walk_state, NULL, method_node,
			  obj_desc->method.aml_start, obj_desc->method.aml_length,
			  &this_walk_state->operands[0], NULL, 3);
	if (ACPI_FAILURE (status)) {
		goto cleanup;
	}

	/*
	 * Delete the operands on the previous walkstate operand stack
	 * (they were copied to new objects)
	 */
	for (i = 0; i < obj_desc->method.param_count; i++) {
		acpi_ut_remove_reference (this_walk_state->operands [i]);
		this_walk_state->operands [i] = NULL;
	}

	/* Clear the operand stack */

	this_walk_state->num_operands = 0;

	ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
		"Starting nested execution, newstate=%p\n", next_walk_state));

	if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
		status = obj_desc->method.implementation (next_walk_state);
		return_ACPI_STATUS (status);
	}

	return_ACPI_STATUS (AE_OK);


	/* On error, we must delete the new walk state */

cleanup:
	if (next_walk_state->method_desc) {
		/* Decrement the thread count on the method parse tree */

	   next_walk_state->method_desc->method.thread_count--;
	}
	(void) acpi_ds_terminate_control_method (next_walk_state);
	acpi_ds_delete_walk_state (next_walk_state);
	return_ACPI_STATUS (status);
}
/**ltl
 * 功能:将ACPI表的描述符信息插入到全局列表中
 * 参数:
 * 返回值:
 * 说明:表类型table_type分别为:0(RSDP)、6 (XSDT)、2 (FADT)、5 (SSDT)、5 (SSDT)、3 (FACS)、1 (DSDT)
 */
acpi_status
acpi_tb_init_table_descriptor(acpi_table_type table_type,
			      struct acpi_table_desc *table_info)
{
	struct acpi_table_list *list_head;
	struct acpi_table_desc *table_desc;
	acpi_status status;

	ACPI_FUNCTION_TRACE_U32(tb_init_table_descriptor, table_type);

	/* Allocate a descriptor for this table */
	/* 分配ACPI表描述符信息 */
	table_desc = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc));
	if (!table_desc) {
		return_ACPI_STATUS(AE_NO_MEMORY);
	}

	/* Get a new owner ID for the table */
	/* 为ACPI表描述符分配ID */
	status = acpi_ut_allocate_owner_id(&table_desc->owner_id);
	if (ACPI_FAILURE(status)) {
		goto error_exit1;
	}

	/* Install the table into the global data structure */
	/* 全局列表 */
	list_head = &acpi_gbl_table_lists[table_type];

	/*
	 * Two major types of tables:  1) Only one instance is allowed.  This
	 * includes most ACPI tables such as the DSDT.  2) Multiple instances of
	 * the table are allowed.  This includes SSDT and PSDTs.
	 */
	/* 如果此ACPI表在系统中只能是唯一一个 */
	if (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags)) {
		/*
		 * Only one table allowed, and a table has alread been installed
		 * at this location, so return an error.
		 */
		if (list_head->next) { /* 表示此表已经存在,退出 */
			status = AE_ALREADY_EXISTS;
			goto error_exit2;
		}
		/*  将ACPI表描述符对象插入到全局列表中 */
		table_desc->next = list_head->next;	
		list_head->next = table_desc;

		if (table_desc->next) {
			table_desc->next->prev = table_desc;
		}

		list_head->count++;
	} else {
		/*
		 * Link the new table in to the list of tables of this type.
		 * Insert at the end of the list, order IS IMPORTANT.
		 *
		 * table_desc->Prev & Next are already NULL from calloc()
		 */
		/* 在系统中引出现多张相同的ACPI表,把它们以链表的形式链接 */
		list_head->count++;

		if (!list_head->next) {
			list_head->next = table_desc;
		} else {
			table_desc->next = list_head->next;

			while (table_desc->next->next) {
				table_desc->next = table_desc->next->next;
			}

			table_desc->next->next = table_desc;
			table_desc->prev = table_desc->next;
			table_desc->next = NULL;
		}
	}

	/* Finish initialization of the table descriptor */

	table_desc->loaded_into_namespace = FALSE;
	table_desc->type = (u8) table_type;
	table_desc->pointer = table_info->pointer;
	table_desc->length = table_info->length;
	table_desc->allocation = table_info->allocation;
	table_desc->aml_start = (u8 *) (table_desc->pointer + 1),
	    table_desc->aml_length = (u32)
	    (table_desc->length - (u32) sizeof(struct acpi_table_header));

	/*
	 * Set the appropriate global pointer (if there is one) to point to the
	 * newly installed table
	 */
	/* 将ACPI表的起始地址保存到global_ptr中。在这语句是对全局变量:acpi_gbl_FADT、acpi_gbl_FACS、acpi_gbl_DSDT
      * 进行赋值
	 */
	if (acpi_gbl_table_data[table_type].global_ptr) { 
		*(acpi_gbl_table_data[table_type].global_ptr) =
		    table_info->pointer;
	}

	/* Return Data */

	table_info->owner_id = table_desc->owner_id;
	table_info->installed_desc = table_desc;
	return_ACPI_STATUS(AE_OK);

	/* Error exit with cleanup */

      error_exit2:

	acpi_ut_release_owner_id(&table_desc->owner_id);

      error_exit1:

	ACPI_FREE(table_desc);
	return_ACPI_STATUS(status);
}
Ejemplo n.º 8
0
acpi_status
acpi_psx_execute (
	struct acpi_parameter_info      *info)
{
	acpi_status                     status;
	union acpi_operand_object       *obj_desc;
	u32                             i;
	union acpi_parse_object         *op;
	struct acpi_walk_state          *walk_state;


	ACPI_FUNCTION_TRACE ("psx_execute");


	/* Validate the Node and get the attached object */

	if (!info || !info->node) {
		return_ACPI_STATUS (AE_NULL_ENTRY);
	}

	obj_desc = acpi_ns_get_attached_object (info->node);
	if (!obj_desc) {
		return_ACPI_STATUS (AE_NULL_OBJECT);
	}

	/* Init for new method, wait on concurrency semaphore */

	status = acpi_ds_begin_method_execution (info->node, obj_desc, NULL);
	if (ACPI_FAILURE (status)) {
		return_ACPI_STATUS (status);
	}

	if ((info->parameter_type == ACPI_PARAM_ARGS) &&
		(info->parameters)) {
		/*
		 * The caller "owns" the parameters, so give each one an extra
		 * reference
		 */
		for (i = 0; info->parameters[i]; i++) {
			acpi_ut_add_reference (info->parameters[i]);
		}
	}

	/*
	 * 1) Perform the first pass parse of the method to enter any
	 * named objects that it creates into the namespace
	 */
	ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
		"**** Begin Method Parse **** Entry=%p obj=%p\n",
		info->node, obj_desc));

	/* Create and init a Root Node */

	op = acpi_ps_create_scope_op ();
	if (!op) {
		status = AE_NO_MEMORY;
		goto cleanup1;
	}

	/*
	 * Get a new owner_id for objects created by this method. Namespace
	 * objects (such as Operation Regions) can be created during the
	 * first pass parse.
	 */
	obj_desc->method.owning_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_METHOD);

	/* Create and initialize a new walk state */

	walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id,
			   NULL, NULL, NULL);
	if (!walk_state) {
		status = AE_NO_MEMORY;
		goto cleanup2;
	}

	status = acpi_ds_init_aml_walk (walk_state, op, info->node,
			  obj_desc->method.aml_start,
			  obj_desc->method.aml_length, NULL, 1);
	if (ACPI_FAILURE (status)) {
		goto cleanup3;
	}

	/* Parse the AML */

	status = acpi_ps_parse_aml (walk_state);
	acpi_ps_delete_parse_tree (op);
	if (ACPI_FAILURE (status)) {
		goto cleanup1; /* Walk state is already deleted */
	}

	/*
	 * 2) Execute the method.  Performs second pass parse simultaneously
	 */
	ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
		"**** Begin Method Execution **** Entry=%p obj=%p\n",
		info->node, obj_desc));

	/* Create and init a Root Node */

	op = acpi_ps_create_scope_op ();
	if (!op) {
		status = AE_NO_MEMORY;
		goto cleanup1;
	}

	/* Init new op with the method name and pointer back to the NS node */

	acpi_ps_set_name (op, info->node->name.integer);
	op->common.node = info->node;

	/* Create and initialize a new walk state */

	walk_state = acpi_ds_create_walk_state (0, NULL, NULL, NULL);
	if (!walk_state) {
		status = AE_NO_MEMORY;
		goto cleanup2;
	}

	status = acpi_ds_init_aml_walk (walk_state, op, info->node,
			  obj_desc->method.aml_start,
			  obj_desc->method.aml_length, info, 3);
	if (ACPI_FAILURE (status)) {
		goto cleanup3;
	}

	/* The walk of the parse tree is where we actually execute the method */

	status = acpi_ps_parse_aml (walk_state);
	goto cleanup2; /* Walk state already deleted */


cleanup3:
	acpi_ds_delete_walk_state (walk_state);

cleanup2:
	acpi_ps_delete_parse_tree (op);

cleanup1:
	if ((info->parameter_type == ACPI_PARAM_ARGS) &&
		(info->parameters)) {
		/* Take away the extra reference that we gave the parameters above */

		for (i = 0; info->parameters[i]; i++) {
			/* Ignore errors, just do them all */

			(void) acpi_ut_update_object_reference (
					 info->parameters[i], REF_DECREMENT);
		}
	}

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

	/*
	 * If the method has returned an object, signal this to the caller with
	 * a control exception code
	 */
	if (info->return_object) {
		ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Method returned obj_desc=%p\n",
			info->return_object));
		ACPI_DUMP_STACK_ENTRY (info->return_object);

		status = AE_CTRL_RETURN_VALUE;
	}

	return_ACPI_STATUS (status);
}
Ejemplo n.º 9
0
acpi_status
acpi_tb_init_table_descriptor (
    acpi_table_type                 table_type,
    struct acpi_table_desc          *table_info)
{
    struct acpi_table_list          *list_head;
    struct acpi_table_desc          *table_desc;


    ACPI_FUNCTION_TRACE_U32 ("tb_init_table_descriptor", table_type);


    /* Allocate a descriptor for this table */

    table_desc = ACPI_MEM_CALLOCATE (sizeof (struct acpi_table_desc));
    if (!table_desc) {
        return_ACPI_STATUS (AE_NO_MEMORY);
    }

    /*
     * Install the table into the global data structure
     */
    list_head = &acpi_gbl_table_lists[table_type];

    /*
     * Two major types of tables:  1) Only one instance is allowed.  This
     * includes most ACPI tables such as the DSDT.  2) Multiple instances of
     * the table are allowed.  This includes SSDT and PSDTs.
     */
    if (ACPI_IS_SINGLE_TABLE (acpi_gbl_table_data[table_type].flags)) {
        /*
         * Only one table allowed, and a table has alread been installed
         * at this location, so return an error.
         */
        if (list_head->next) {
            ACPI_MEM_FREE (table_desc);
            return_ACPI_STATUS (AE_ALREADY_EXISTS);
        }

        table_desc->next = list_head->next;
        list_head->next = table_desc;

        if (table_desc->next) {
            table_desc->next->prev = table_desc;
        }

        list_head->count++;
    }
    else {
        /*
         * Link the new table in to the list of tables of this type.
         * Insert at the end of the list, order IS IMPORTANT.
         *
         * table_desc->Prev & Next are already NULL from calloc()
         */
        list_head->count++;

        if (!list_head->next) {
            list_head->next = table_desc;
        }
        else {
            table_desc->next = list_head->next;

            while (table_desc->next->next) {
                table_desc->next = table_desc->next->next;
            }

            table_desc->next->next = table_desc;
            table_desc->prev = table_desc->next;
            table_desc->next = NULL;
        }
    }

    /* Finish initialization of the table descriptor */

    table_desc->type                = (u8) table_type;
    table_desc->pointer             = table_info->pointer;
    table_desc->length              = table_info->length;
    table_desc->allocation          = table_info->allocation;
    table_desc->aml_start           = (u8 *) (table_desc->pointer + 1),
                table_desc->aml_length          = (u32) (table_desc->length -
                        (u32) sizeof (struct acpi_table_header));
    table_desc->table_id            = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_TABLE);
    table_desc->loaded_into_namespace = FALSE;

    /*
     * Set the appropriate global pointer (if there is one) to point to the
     * newly installed table
     */
    if (acpi_gbl_table_data[table_type].global_ptr) {
        *(acpi_gbl_table_data[table_type].global_ptr) = table_info->pointer;
    }

    /* Return Data */

    table_info->table_id        = table_desc->table_id;
    table_info->installed_desc  = table_desc;

    return_ACPI_STATUS (AE_OK);
}