|
@@ -86,6 +86,9 @@ static acpi_status
|
|
|
acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
|
|
|
union acpi_parse_object *op, acpi_status status);
|
|
|
|
|
|
+static void
|
|
|
+acpi_ps_link_module_code(u8 *aml_start, u32 aml_length, acpi_owner_id owner_id);
|
|
|
+
|
|
|
/*******************************************************************************
|
|
|
*
|
|
|
* FUNCTION: acpi_ps_get_aml_opcode
|
|
@@ -390,6 +393,7 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
|
|
|
{
|
|
|
acpi_status status = AE_OK;
|
|
|
union acpi_parse_object *arg = NULL;
|
|
|
+ const struct acpi_opcode_info *op_info;
|
|
|
|
|
|
ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state);
|
|
|
|
|
@@ -449,13 +453,11 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
|
|
|
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) &&
|
|
|
+ /*
|
|
|
+ * Handle executable code at "module-level". This refers to
|
|
|
+ * executable opcodes that appear outside of any control method.
|
|
|
+ */
|
|
|
+ if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS2) &&
|
|
|
((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) {
|
|
|
/*
|
|
|
* We want to skip If/Else/While constructs during Pass1 because we
|
|
@@ -469,6 +471,23 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
|
|
|
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 (walk_state->pass_number ==
|
|
|
+ ACPI_IMODE_LOAD_PASS1) {
|
|
|
+ acpi_ps_link_module_code(aml_op_start,
|
|
|
+ walk_state->
|
|
|
+ parser_state.
|
|
|
+ pkg_end -
|
|
|
+ aml_op_start,
|
|
|
+ walk_state->
|
|
|
+ owner_id);
|
|
|
+ }
|
|
|
+
|
|
|
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
|
|
|
"Pass1: Skipping an If/Else/While body\n"));
|
|
|
|
|
@@ -480,10 +499,34 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
|
|
|
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 ((walk_state->pass_number ==
|
|
|
+ ACPI_IMODE_LOAD_PASS1)
|
|
|
+ && (op->common.parent->common.aml_opcode ==
|
|
|
+ AML_SCOPE_OP)) {
|
|
|
+ op_info =
|
|
|
+ acpi_ps_get_opcode_info(op->common.
|
|
|
+ aml_opcode);
|
|
|
+ if ((op_info->class ==
|
|
|
+ AML_CLASS_EXECUTE) && (!arg)) {
|
|
|
+ ACPI_WARNING((AE_INFO,
|
|
|
+ "Detected an unsupported executable opcode "
|
|
|
+ "at module-level: [0x%.4X] at table offset 0x%.4X",
|
|
|
+ op->common.aml_opcode,
|
|
|
+ (u32)((aml_op_start - walk_state->parser_state.aml_start)
|
|
|
+ + sizeof(struct acpi_table_header))));
|
|
|
+ }
|
|
|
+ }
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
-#endif
|
|
|
+
|
|
|
+ /* Special processing for certain opcodes */
|
|
|
|
|
|
switch (op->common.aml_opcode) {
|
|
|
case AML_METHOD_OP:
|
|
@@ -551,6 +594,66 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
|
|
|
return_ACPI_STATUS(AE_OK);
|
|
|
}
|
|
|
|
|
|
+/*******************************************************************************
|
|
|
+ *
|
|
|
+ * FUNCTION: acpi_ps_link_module_code
|
|
|
+ *
|
|
|
+ * PARAMETERS: aml_start - Pointer to the AML
|
|
|
+ * aml_length - Length of executable AML
|
|
|
+ * owner_id - owner_id of module level code
|
|
|
+ *
|
|
|
+ * RETURN: None.
|
|
|
+ *
|
|
|
+ * DESCRIPTION: Wrap the module-level code with a method object and link the
|
|
|
+ * object to the global list. Note, the mutex field of the method
|
|
|
+ * object is used to link multiple module-level code objects.
|
|
|
+ *
|
|
|
+ ******************************************************************************/
|
|
|
+
|
|
|
+static void
|
|
|
+acpi_ps_link_module_code(u8 *aml_start, u32 aml_length, acpi_owner_id owner_id)
|
|
|
+{
|
|
|
+ union acpi_operand_object *prev;
|
|
|
+ union acpi_operand_object *next;
|
|
|
+ union acpi_operand_object *method_obj;
|
|
|
+
|
|
|
+ /* Get the tail of the list */
|
|
|
+
|
|
|
+ prev = next = acpi_gbl_module_code_list;
|
|
|
+ while (next) {
|
|
|
+ prev = next;
|
|
|
+ next = next->method.mutex;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Insert the module level code into the list. Merge it if it is
|
|
|
+ * adjacent to the previous element.
|
|
|
+ */
|
|
|
+ if (!prev ||
|
|
|
+ ((prev->method.aml_start + prev->method.aml_length) != aml_start)) {
|
|
|
+
|
|
|
+ /* Create, initialize, and link a new temporary method object */
|
|
|
+
|
|
|
+ method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
|
|
|
+ if (!method_obj) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ method_obj->method.aml_start = aml_start;
|
|
|
+ method_obj->method.aml_length = aml_length;
|
|
|
+ method_obj->method.owner_id = owner_id;
|
|
|
+ method_obj->method.flags |= AOPOBJ_MODULE_LEVEL;
|
|
|
+
|
|
|
+ if (!prev) {
|
|
|
+ acpi_gbl_module_code_list = method_obj;
|
|
|
+ } else {
|
|
|
+ prev->method.mutex = method_obj;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ prev->method.aml_length += aml_length;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/*******************************************************************************
|
|
|
*
|
|
|
* FUNCTION: acpi_ps_complete_op
|