From defba1d8f233c0d5cf3e1ea6aeb898eca7231860 Mon Sep 17 00:00:00 2001
From: Bob Moore <robert.moore@intel.com>
Date: Fri, 16 Dec 2005 17:05:00 -0500
Subject: [ACPI] ACPICA 20051216

Implemented optional support to allow unresolved names
within ASL Package objects. A null object is inserted in
the package when a named reference cannot be located in
the current namespace. Enabled via the interpreter slack
flag which Linux has enabled by default (acpi=strict
to disable slack).  This should eliminate AE_NOT_FOUND
exceptions seen on machines that contain such code.

Implemented an optimization to the initialization
sequence that can improve boot time. During ACPI device
initialization, the _STA method is now run if and only
if the _INI method exists. The _STA method is used to
determine if the device is present; An _INI can only be
run if _STA returns present, but it is a waste of time to
run the _STA method if the _INI does not exist. (Prototype
and assistance from Dong Wei)

Implemented use of the C99 uintptr_t for the pointer
casting macros if it is available in the current
compiler. Otherwise, the default (void *) cast is used
as before.

Fixed some possible memory leaks found within the
execution path of the Break, Continue, If, and CreateField
operators. (Valery Podrezov)

Fixed a problem introduced in the 20051202 release where
an exception is generated during method execution if a
control method attempts to declare another method.

Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
 drivers/acpi/dispatcher/dsmethod.c |  65 +++++++++++++++++++++-
 drivers/acpi/dispatcher/dsobject.c |  81 +++++++++++++++++----------
 drivers/acpi/dispatcher/dswexec.c  |  33 +++--------
 drivers/acpi/dispatcher/dswload.c  | 110 +++++++++++++++++++++++++++----------
 4 files changed, 203 insertions(+), 86 deletions(-)

(limited to 'drivers/acpi/dispatcher')

diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index 58ad00b31ee9..e7ce86b8d954 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -47,10 +47,68 @@
 #include <acpi/acdispat.h>
 #include <acpi/acinterp.h>
 #include <acpi/acnamesp.h>
+#include <acpi/acdisasm.h>
 
 #define _COMPONENT          ACPI_DISPATCHER
 ACPI_MODULE_NAME("dsmethod")
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ds_method_error
+ *
+ * PARAMETERS:  Status          - Execution status
+ *              walk_state      - Current state
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Called on method error. Invoke the global exception handler if
+ *              present, dump the method data if the disassembler is configured
+ *
+ *              Note: Allows the exception handler to change the status code
+ *
+ ******************************************************************************/
+acpi_status
+acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
+{
+	ACPI_FUNCTION_ENTRY();
+
+	/* Ignore AE_OK and control exception codes */
+
+	if (ACPI_SUCCESS(status) || (status & AE_CODE_CONTROL)) {
+		return (status);
+	}
+
+	/* Invoke the global exception handler */
+
+	if (acpi_gbl_exception_handler) {
+		/* Exit the interpreter, allow handler to execute methods */
+
+		acpi_ex_exit_interpreter();
+
+		/*
+		 * Handler can map the exception code to anything it wants, including
+		 * AE_OK, in which case the executing method will not be aborted.
+		 */
+		status = acpi_gbl_exception_handler(status,
+						    walk_state->method_node ?
+						    walk_state->method_node->
+						    name.integer : 0,
+						    walk_state->opcode,
+						    walk_state->aml_offset,
+						    NULL);
+		(void)acpi_ex_enter_interpreter();
+	}
+#ifdef ACPI_DISASSEMBLER
+	if (ACPI_FAILURE(status)) {
+		/* Display method locals/args if disassembler is present */
+
+		acpi_dm_dump_method_info(status, walk_state, walk_state->op);
+	}
+#endif
+
+	return (status);
+}
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ds_begin_method_execution
@@ -66,10 +124,11 @@ ACPI_MODULE_NAME("dsmethod")
  *              for clearance to execute.
  *
  ******************************************************************************/
+
 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_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;
 
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
index 8ac0cd93adb5..905a84e4b145 100644
--- a/drivers/acpi/dispatcher/dsobject.c
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -51,6 +51,7 @@
 #define _COMPONENT          ACPI_DISPATCHER
 ACPI_MODULE_NAME("dsobject")
 
+/* Local prototypes */
 static acpi_status
 acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
 			      union acpi_parse_object *op,
@@ -85,7 +86,7 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
 	*obj_desc_ptr = NULL;
 	if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) {
 		/*
-		 * This is an named object reference.  If this name was
+		 * This is a named object reference. If this name was
 		 * previously looked up in the namespace, it was stored in this op.
 		 * Otherwise, go ahead and look it up now
 		 */
@@ -96,18 +97,48 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
 						ACPI_IMODE_EXECUTE,
 						ACPI_NS_SEARCH_PARENT |
 						ACPI_NS_DONT_OPEN_SCOPE, NULL,
-						(struct acpi_namespace_node **)
-						&(op->common.node));
-
+						ACPI_CAST_INDIRECT_PTR(struct
+								       acpi_namespace_node,
+								       &(op->
+									 common.
+									 node)));
 			if (ACPI_FAILURE(status)) {
-				ACPI_REPORT_NSERROR(op->common.value.string,
-						    status);
+				/* Check if we are resolving a named reference within a package */
+
+				if ((status == AE_NOT_FOUND)
+				    && (acpi_gbl_enable_interpreter_slack)
+				    &&
+				    ((op->common.parent->common.aml_opcode ==
+				      AML_PACKAGE_OP)
+				     || (op->common.parent->common.aml_opcode ==
+					 AML_VAR_PACKAGE_OP))) {
+					/*
+					 * We didn't find the target and we are populating elements
+					 * of a package - ignore if slack enabled. Some ASL code
+					 * contains dangling invalid references in packages and
+					 * expects that no exception will be issued. Leave the
+					 * element as a null element. It cannot be used, but it
+					 * can be overwritten by subsequent ASL code - this is
+					 * typically the case.
+					 */
+					ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+							  "Ignoring unresolved reference in package [%4.4s]\n",
+							  walk_state->
+							  scope_info->scope.
+							  node->name.ascii));
+
+					return_ACPI_STATUS(AE_OK);
+				} else {
+					ACPI_REPORT_NSERROR(op->common.value.
+							    string, status);
+				}
+
 				return_ACPI_STATUS(status);
 			}
 		}
 	}
 
-	/* Create and init the internal ACPI object */
+	/* Create and init a new internal ACPI object */
 
 	obj_desc = acpi_ut_create_internal_object((acpi_ps_get_opcode_info
 						   (op->common.aml_opcode))->
@@ -157,13 +188,13 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
 
 	ACPI_FUNCTION_TRACE("ds_build_internal_buffer_obj");
 
+	/*
+	 * If we are evaluating a Named buffer object "Name (xxxx, Buffer)".
+	 * The buffer object already exists (from the NS node), otherwise it must
+	 * be created.
+	 */
 	obj_desc = *obj_desc_ptr;
-	if (obj_desc) {
-		/*
-		 * We are evaluating a Named buffer object "Name (xxxx, Buffer)".
-		 * The buffer object already exists (from the NS node)
-		 */
-	} else {
+	if (!obj_desc) {
 		/* Create a new buffer object */
 
 		obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER);
@@ -259,7 +290,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
 	union acpi_operand_object *obj_desc = NULL;
 	u32 package_list_length;
 	acpi_status status = AE_OK;
-	u32 i;
+	acpi_native_uint i;
 
 	ACPI_FUNCTION_TRACE("ds_build_internal_package_obj");
 
@@ -271,13 +302,12 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
 		parent = parent->common.parent;
 	}
 
+	/*
+	 * If we are evaluating a Named package object "Name (xxxx, Package)",
+	 * the package object already exists, otherwise it must be created.
+	 */
 	obj_desc = *obj_desc_ptr;
-	if (obj_desc) {
-		/*
-		 * We are evaluating a Named package object "Name (xxxx, Package)".
-		 * Get the existing package object from the NS node
-		 */
-	} else {
+	if (!obj_desc) {
 		obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_PACKAGE);
 		*obj_desc_ptr = obj_desc;
 		if (!obj_desc) {
@@ -291,11 +321,9 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
 
 	/* Count the number of items in the package list */
 
-	package_list_length = 0;
 	arg = op->common.value.arg;
 	arg = arg->common.next;
-	while (arg) {
-		package_list_length++;
+	for (package_list_length = 0; arg; package_list_length++) {
 		arg = arg->common.next;
 	}
 
@@ -322,12 +350,11 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
 	}
 
 	/*
-	 * Now init the elements of the package
+	 * Initialize all elements of the package
 	 */
-	i = 0;
 	arg = op->common.value.arg;
 	arg = arg->common.next;
-	while (arg) {
+	for (i = 0; arg; i++) {
 		if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
 			/* Object (package or buffer) is already built */
 
@@ -340,8 +367,6 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
 							       package.
 							       elements[i]);
 		}
-
-		i++;
 		arg = arg->common.next;
 	}
 
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
index e522763bb692..74f6996db2d7 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -314,12 +314,13 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
 
 	case AML_CLASS_EXECUTE:
 	case AML_CLASS_CREATE:
-
 		/*
 		 * Most operators with arguments.
 		 * Start a new result/operand state
 		 */
-		status = acpi_ds_result_stack_push(walk_state);
+		if (walk_state->opcode != AML_CREATE_FIELD_OP) {
+			status = acpi_ds_result_stack_push(walk_state);
+		}
 		break;
 
 	default:
@@ -723,20 +724,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
 
       cleanup:
 
-	/* Invoke exception handler on error */
-
-	if (ACPI_FAILURE(status) &&
-	    acpi_gbl_exception_handler && !(status & AE_CODE_CONTROL)) {
-		acpi_ex_exit_interpreter();
-		status = acpi_gbl_exception_handler(status,
-						    walk_state->method_node->
-						    name.integer,
-						    walk_state->opcode,
-						    walk_state->aml_offset,
-						    NULL);
-		(void)acpi_ex_enter_interpreter();
-	}
-
 	if (walk_state->result_obj) {
 		/* Break to debugger to display result */
 
@@ -758,18 +745,14 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
 	}
 #endif
 
-	/* Always clear the object stack */
-
-	walk_state->num_operands = 0;
-
-#ifdef ACPI_DISASSEMBLER
-
-	/* On error, display method locals/args */
+	/* Invoke exception handler on error */
 
 	if (ACPI_FAILURE(status)) {
-		acpi_dm_dump_method_info(status, walk_state, op);
+		status = acpi_ds_method_error(status, walk_state);
 	}
-#endif
 
+	/* Always clear the object stack */
+
+	walk_state->num_operands = 0;
 	return_ACPI_STATUS(status);
 }
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
index 44d4f4bb2f92..441931cab08a 100644
--- a/drivers/acpi/dispatcher/dswload.c
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -428,43 +428,54 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state)
 		}
 	}
 
-	if (op->common.aml_opcode == AML_METHOD_OP) {
-		/*
-		 * method_op pkg_length name_string method_flags term_list
-		 *
-		 * Note: We must create the method node/object pair as soon as we
-		 * see the method declaration.  This allows later pass1 parsing
-		 * of invocations of the method (need to know the number of
-		 * arguments.)
-		 */
-		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
-				  "LOADING-Method: State=%p Op=%p named_obj=%p\n",
-				  walk_state, op, op->named.node));
+	/*
+	 * If we are executing a method, do not create any namespace objects
+	 * during the load phase, only during execution.
+	 */
+	if (!walk_state->method_node) {
+		if (op->common.aml_opcode == AML_METHOD_OP) {
+			/*
+			 * method_op pkg_length name_string method_flags term_list
+			 *
+			 * Note: We must create the method node/object pair as soon as we
+			 * see the method declaration.  This allows later pass1 parsing
+			 * of invocations of the method (need to know the number of
+			 * arguments.)
+			 */
+			ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+					  "LOADING-Method: State=%p Op=%p named_obj=%p\n",
+					  walk_state, op, op->named.node));
 
-		if (!acpi_ns_get_attached_object(op->named.node)) {
-			walk_state->operands[0] = (void *)op->named.node;
-			walk_state->num_operands = 1;
+			if (!acpi_ns_get_attached_object(op->named.node)) {
+				walk_state->operands[0] =
+				    ACPI_CAST_PTR(void, op->named.node);
+				walk_state->num_operands = 1;
 
-			status =
-			    acpi_ds_create_operands(walk_state,
-						    op->common.value.arg);
-			if (ACPI_SUCCESS(status)) {
-				status = acpi_ex_create_method(op->named.data,
-							       op->named.length,
-							       walk_state);
-			}
-			walk_state->operands[0] = NULL;
-			walk_state->num_operands = 0;
+				status =
+				    acpi_ds_create_operands(walk_state,
+							    op->common.value.
+							    arg);
+				if (ACPI_SUCCESS(status)) {
+					status =
+					    acpi_ex_create_method(op->named.
+								  data,
+								  op->named.
+								  length,
+								  walk_state);
+				}
+				walk_state->operands[0] = NULL;
+				walk_state->num_operands = 0;
 
-			if (ACPI_FAILURE(status)) {
-				return_ACPI_STATUS(status);
+				if (ACPI_FAILURE(status)) {
+					return_ACPI_STATUS(status);
+				}
 			}
 		}
 	}
 
-	/* Pop the scope stack */
+	/* Pop the scope stack (only if loading a table) */
 
-	if (acpi_ns_opens_scope(object_type)) {
+	if (!walk_state->method_node && acpi_ns_opens_scope(object_type)) {
 		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
 				  "(%s): Popping scope for Op %p\n",
 				  acpi_ut_get_type_name(object_type), op));
@@ -1015,11 +1026,50 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
 
 			status = acpi_ds_create_node(walk_state, node, op);
 			break;
+
+		case AML_METHOD_OP:
+			/*
+			 * method_op pkg_length name_string method_flags term_list
+			 *
+			 * Note: We must create the method node/object pair as soon as we
+			 * see the method declaration.  This allows later pass1 parsing
+			 * of invocations of the method (need to know the number of
+			 * arguments.)
+			 */
+			ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+					  "LOADING-Method: State=%p Op=%p named_obj=%p\n",
+					  walk_state, op, op->named.node));
+
+			if (!acpi_ns_get_attached_object(op->named.node)) {
+				walk_state->operands[0] =
+				    ACPI_CAST_PTR(void, op->named.node);
+				walk_state->num_operands = 1;
+
+				status =
+				    acpi_ds_create_operands(walk_state,
+							    op->common.value.
+							    arg);
+				if (ACPI_SUCCESS(status)) {
+					status =
+					    acpi_ex_create_method(op->named.
+								  data,
+								  op->named.
+								  length,
+								  walk_state);
+				}
+				walk_state->operands[0] = NULL;
+				walk_state->num_operands = 0;
+
+				if (ACPI_FAILURE(status)) {
+					return_ACPI_STATUS(status);
+				}
+			}
+			break;
+
 #endif				/* ACPI_NO_METHOD_EXECUTION */
 
 		default:
 			/* All NAMED_COMPLEX opcodes must be handled above */
-			/* Note: Method objects were already created in Pass 1 */
 			break;
 		}
 		break;
-- 
cgit v1.2.2