Skip to content

Commit

Permalink
ACPICA: Add support for module-level executable AML code
Browse files Browse the repository at this point in the history
Add limited support for executable AML code that exists outside
of any control method. This type of code has been illegal since
ACPI 2.0.  The code must exist in an If/Else/While block. All AML
tables are supported, including tables that are dynamically loaded.
ACPICA BZ 762.

http://acpica.org/bugzilla/show_bug.cgi?id=762

Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
  • Loading branch information
Lin Ming authored and Len Brown committed Aug 28, 2009
1 parent 999e08f commit 7f0c826
Show file tree
Hide file tree
Showing 13 changed files with 306 additions and 52 deletions.
1 change: 1 addition & 0 deletions drivers/acpi/acpica/acglobal.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ extern char const *acpi_gbl_exception_names_ctrl[];
ACPI_EXTERN struct acpi_namespace_node acpi_gbl_root_node_struct;
ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_root_node;
ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_fadt_gpe_device;
ACPI_EXTERN union acpi_operand_object *acpi_gbl_module_code_list;

extern const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES];
extern const struct acpi_predefined_names
Expand Down
2 changes: 2 additions & 0 deletions drivers/acpi/acpica/acnamesp.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ acpi_ns_dump_objects(acpi_object_type type,
*/
acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info);

void acpi_ns_exec_module_code_list(void);

/*
* nspredef - Support for predefined/reserved names
*/
Expand Down
1 change: 1 addition & 0 deletions drivers/acpi/acpica/acobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
#define AOPOBJ_SETUP_COMPLETE 0x10
#define AOPOBJ_SINGLE_DATUM 0x20
#define AOPOBJ_INVALID 0x40 /* Used if host OS won't allow an op_region address */
#define AOPOBJ_MODULE_LEVEL 0x80

/******************************************************************************
*
Expand Down
2 changes: 2 additions & 0 deletions drivers/acpi/acpica/acparser.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
#define ACPI_PARSE_DEFERRED_OP 0x0100
#define ACPI_PARSE_DISASSEMBLE 0x0200

#define ACPI_PARSE_MODULE_LEVEL 0x0400

/******************************************************************************
*
* Parser interfaces
Expand Down
18 changes: 12 additions & 6 deletions drivers/acpi/acpica/dsfield.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,12 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
ACPI_NS_ERROR_IF_FOUND;

/* Mark node temporary if we are executing a method */

if (walk_state->method_node) {
/*
* Mark node temporary if we are executing a normal control
* method. (Don't mark if this is a module-level code method)
*/
if (walk_state->method_node &&
!(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) {
flags |= ACPI_NS_TEMPORARY;
}

Expand Down Expand Up @@ -456,9 +459,12 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
ACPI_NS_ERROR_IF_FOUND;

/* Mark node(s) temporary if we are executing a method */

if (walk_state->method_node) {
/*
* Mark node(s) temporary if we are executing a normal control
* method. (Don't mark if this is a module-level code method)
*/
if (walk_state->method_node &&
!(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) {
flags |= ACPI_NS_TEMPORARY;
}

Expand Down
15 changes: 11 additions & 4 deletions drivers/acpi/acpica/dsmethod.c
Original file line number Diff line number Diff line change
Expand Up @@ -578,10 +578,15 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
}

/*
* Delete any namespace objects created anywhere within
* the namespace by the execution of this method
* Delete any namespace objects created anywhere within the
* namespace by the execution of this method. Unless this method
* is a module-level executable code method, in which case we
* want make the objects permanent.
*/
acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id);
if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) {
acpi_ns_delete_namespace_by_owner(method_desc->method.
owner_id);
}
}

/* Decrement the thread count on the method */
Expand Down Expand Up @@ -622,7 +627,9 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,

/* No more threads, we can free the owner_id */

acpi_ut_release_owner_id(&method_desc->method.owner_id);
if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) {
acpi_ut_release_owner_id(&method_desc->method.owner_id);
}
}

return_VOID;
Expand Down
41 changes: 7 additions & 34 deletions drivers/acpi/acpica/dswload.c
Original file line number Diff line number Diff line change
Expand Up @@ -581,21 +581,6 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
if ((!(walk_state->op_info->flags & AML_NSOPCODE) &&
(walk_state->opcode != AML_INT_NAMEPATH_OP)) ||
(!(walk_state->op_info->flags & AML_NAMED))) {
#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
if ((walk_state->op_info->class == AML_CLASS_EXECUTE) ||
(walk_state->op_info->class == AML_CLASS_CONTROL)) {
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"Begin/EXEC: %s (fl %8.8X)\n",
walk_state->op_info->name,
walk_state->op_info->flags));

/* Executing a type1 or type2 opcode outside of a method */

status =
acpi_ds_exec_begin_op(walk_state, out_op);
return_ACPI_STATUS(status);
}
#endif
return_ACPI_STATUS(AE_OK);
}

Expand Down Expand Up @@ -768,7 +753,13 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,

/* Execution mode, node cannot already exist, node is temporary */

flags |= (ACPI_NS_ERROR_IF_FOUND | ACPI_NS_TEMPORARY);
flags |= ACPI_NS_ERROR_IF_FOUND;

if (!
(walk_state->
parse_flags & ACPI_PARSE_MODULE_LEVEL)) {
flags |= ACPI_NS_TEMPORARY;
}
}

/* Add new entry or lookup existing entry */
Expand Down Expand Up @@ -851,24 +842,6 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
/* Check if opcode had an associated namespace object */

if (!(walk_state->op_info->flags & AML_NSOBJECT)) {
#ifndef ACPI_NO_METHOD_EXECUTION
#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
/* No namespace object. Executable opcode? */

if ((walk_state->op_info->class == AML_CLASS_EXECUTE) ||
(walk_state->op_info->class == AML_CLASS_CONTROL)) {
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"End/EXEC: %s (fl %8.8X)\n",
walk_state->op_info->name,
walk_state->op_info->flags));

/* Executing a type1 or type2 opcode outside of a method */

status = acpi_ds_exec_end_op(walk_state);
return_ACPI_STATUS(status);
}
#endif
#endif
return_ACPI_STATUS(AE_OK);
}

Expand Down
7 changes: 7 additions & 0 deletions drivers/acpi/acpica/exconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,15 @@ acpi_ex_add_table(u32 table_index,
if (ACPI_FAILURE(status)) {
acpi_ut_remove_reference(obj_desc);
*ddb_handle = NULL;
return_ACPI_STATUS(status);
}

/* Execute any module-level code that was found in the table */

acpi_ex_exit_interpreter();
acpi_ns_exec_module_code_list();
acpi_ex_enter_interpreter();

return_ACPI_STATUS(status);
}

Expand Down
137 changes: 137 additions & 0 deletions drivers/acpi/acpica/nseval.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nseval")

/* Local prototypes */
static void
acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
struct acpi_evaluate_info *info);

/*******************************************************************************
*
* FUNCTION: acpi_ns_evaluate
Expand All @@ -76,6 +81,7 @@ ACPI_MODULE_NAME("nseval")
* MUTEX: Locks interpreter
*
******************************************************************************/

acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
{
acpi_status status;
Expand Down Expand Up @@ -276,3 +282,134 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
*/
return_ACPI_STATUS(status);
}

/*******************************************************************************
*
* FUNCTION: acpi_ns_exec_module_code_list
*
* PARAMETERS: None
*
* RETURN: None. Exceptions during method execution are ignored, since
* we cannot abort a table load.
*
* DESCRIPTION: Execute all elements of the global module-level code list.
* Each element is executed as a single control method.
*
******************************************************************************/

void acpi_ns_exec_module_code_list(void)
{
union acpi_operand_object *prev;
union acpi_operand_object *next;
struct acpi_evaluate_info *info;
u32 method_count = 0;

ACPI_FUNCTION_TRACE(ns_exec_module_code_list);

/* Exit now if the list is empty */

next = acpi_gbl_module_code_list;
if (!next) {
return_VOID;
}

/* Allocate the evaluation information block */

info = ACPI_ALLOCATE(sizeof(struct acpi_evaluate_info));
if (!info) {
return_VOID;
}

/* Walk the list, executing each "method" */

while (next) {
prev = next;
next = next->method.mutex;

/* Clear the link field and execute the method */

prev->method.mutex = NULL;
acpi_ns_exec_module_code(prev, info);
method_count++;

/* Delete the (temporary) method object */

acpi_ut_remove_reference(prev);
}

ACPI_INFO((AE_INFO,
"Executed %u blocks of module-level executable AML code",
method_count));

ACPI_FREE(info);
acpi_gbl_module_code_list = NULL;
return_VOID;
}

/*******************************************************************************
*
* FUNCTION: acpi_ns_exec_module_code
*
* PARAMETERS: method_obj - Object container for the module-level code
* Info - Info block for method evaluation
*
* RETURN: None. Exceptions during method execution are ignored, since
* we cannot abort a table load.
*
* DESCRIPTION: Execute a control method containing a block of module-level
* executable AML code. The control method is temporarily
* installed to the root node, then evaluated.
*
******************************************************************************/

static void
acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
struct acpi_evaluate_info *info)
{
union acpi_operand_object *root_obj;
acpi_status status;

ACPI_FUNCTION_TRACE(ns_exec_module_code);

/* Initialize the evaluation information block */

ACPI_MEMSET(info, 0, sizeof(struct acpi_evaluate_info));
info->prefix_node = acpi_gbl_root_node;

/*
* Get the currently attached root object. Add a reference, because the
* ref count will be decreased when the method object is installed to
* the root node.
*/
root_obj = acpi_ns_get_attached_object(acpi_gbl_root_node);
acpi_ut_add_reference(root_obj);

/* Install the method (module-level code) in the root node */

status = acpi_ns_attach_object(acpi_gbl_root_node, method_obj,
ACPI_TYPE_METHOD);
if (ACPI_FAILURE(status)) {
goto exit;
}

/* Execute the root node as a control method */

status = acpi_ns_evaluate(info);

ACPI_DEBUG_PRINT((ACPI_DB_INIT, "Executed module-level code at %p\n",
method_obj->method.aml_start));

/* Detach the temporary method object */

acpi_ns_detach_object(acpi_gbl_root_node);

/* Restore the original root object */

status =
acpi_ns_attach_object(acpi_gbl_root_node, root_obj,
ACPI_TYPE_DEVICE);

exit:
acpi_ut_remove_reference(root_obj);
return_VOID;
}
Loading

0 comments on commit 7f0c826

Please sign in to comment.