summary refs log tree commit diff
path: root/drivers/acpi/acpica/nseval.c
diff options
context:
space:
mode:
authorBob Moore <robert.moore@intel.com>2013-05-30 10:00:01 +0800
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-06-01 21:54:30 +0200
commit29a241cc02110b8b2259fd72719b8cadc03909be (patch)
treea96c10dd22a35479dc2e1ef140f7d90a442f9c03 /drivers/acpi/acpica/nseval.c
parente1405ca5ebf1068a0d62afd2fec8f0354038147a (diff)
downloadlinux-29a241cc02110b8b2259fd72719b8cadc03909be.tar.gz
ACPICA: Add argument typechecking for all predefined ACPI names
Fully implements typechecking on all incoming arguments for all
predefined names. This ensures that ACPI-related drivers are
passing the correct number of arguments, each of the correct
object type.

Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Acked-by: Len Brown <len.brown@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/acpica/nseval.c')
-rw-r--r--drivers/acpi/acpica/nseval.c247
1 files changed, 142 insertions, 105 deletions
diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c
index b61db69d5675..18108bc2e51c 100644
--- a/drivers/acpi/acpica/nseval.c
+++ b/drivers/acpi/acpica/nseval.c
@@ -61,7 +61,7 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
  *
  * PARAMETERS:  info            - Evaluation info block, contains:
  *                  prefix_node     - Prefix or Method/Object Node to execute
- *                  pathname        - Name of method to execute, If NULL, the
+ *                  relative_path   - Name of method to execute, If NULL, the
  *                                    Node is the object to execute
  *                  parameters      - List of parameters to pass to the method,
  *                                    terminated by NULL. Params itself may be
@@ -82,10 +82,9 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
  *
  ******************************************************************************/
 
-acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
+acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
 {
 	acpi_status status;
-	struct acpi_namespace_node *node;
 
 	ACPI_FUNCTION_TRACE(ns_evaluate);
 
@@ -93,83 +92,138 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
-	/* Initialize the return value to an invalid object */
-
-	info->return_object = NULL;
-	info->param_count = 0;
-
-	if (!info->resolved_node) {
+	if (!info->node) {
 		/*
-		 * Get the actual namespace node for the target object if we need to.
-		 * Handles these cases:
+		 * Get the actual namespace node for the target object if we
+		 * need to. Handles these cases:
 		 *
-		 * 1) Null node, Pathname (absolute path)
-		 * 2) Node, Pathname (path relative to Node)
-		 * 3) Node, Null Pathname
+		 * 1) Null node, valid pathname from root (absolute path)
+		 * 2) Node and valid pathname (path relative to Node)
+		 * 3) Node, Null pathname
 		 */
-		status = acpi_ns_get_node(info->prefix_node, info->pathname,
-					  ACPI_NS_NO_UPSEARCH,
-					  &info->resolved_node);
+		status =
+		    acpi_ns_get_node(info->prefix_node, info->relative_pathname,
+				     ACPI_NS_NO_UPSEARCH, &info->node);
 		if (ACPI_FAILURE(status)) {
 			return_ACPI_STATUS(status);
 		}
 	}
 
 	/*
-	 * For a method alias, we must grab the actual method node so that proper
-	 * scoping context will be established before execution.
+	 * For a method alias, we must grab the actual method node so that
+	 * proper scoping context will be established before execution.
 	 */
-	if (acpi_ns_get_type(info->resolved_node) ==
-	    ACPI_TYPE_LOCAL_METHOD_ALIAS) {
-		info->resolved_node =
+	if (acpi_ns_get_type(info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) {
+		info->node =
 		    ACPI_CAST_PTR(struct acpi_namespace_node,
-				  info->resolved_node->object);
+				  info->node->object);
+	}
+
+	/* Complete the info block initialization */
+
+	info->return_object = NULL;
+	info->node_flags = info->node->flags;
+	info->obj_desc = acpi_ns_get_attached_object(info->node);
+
+	ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n",
+			  info->relative_pathname, info->node,
+			  acpi_ns_get_attached_object(info->node)));
+
+	/* Get info if we have a predefined name (_HID, etc.) */
+
+	info->predefined =
+	    acpi_ut_match_predefined_method(info->node->name.ascii);
+
+	/* Get the full pathname to the object, for use in warning messages */
+
+	info->full_pathname = acpi_ns_get_external_pathname(info->node);
+	if (!info->full_pathname) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
 	}
 
-	ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n", info->pathname,
-			  info->resolved_node,
-			  acpi_ns_get_attached_object(info->resolved_node)));
+	/* Count the number of arguments being passed in */
+
+	info->param_count = 0;
+	if (info->parameters) {
+		while (info->parameters[info->param_count]) {
+			info->param_count++;
+		}
+
+		/* Warn on impossible argument count */
+
+		if (info->param_count > ACPI_METHOD_NUM_ARGS) {
+			ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+					      ACPI_WARN_ALWAYS,
+					      "Excess arguments (%u) - using only %u",
+					      info->param_count,
+					      ACPI_METHOD_NUM_ARGS));
+
+			info->param_count = ACPI_METHOD_NUM_ARGS;
+		}
+	}
+
+	/*
+	 * For predefined names: Check that the declared argument count
+	 * matches the ACPI spec -- otherwise this is a BIOS error.
+	 */
+	acpi_ns_check_acpi_compliance(info->full_pathname, info->node,
+				      info->predefined);
+
+	/*
+	 * For all names: Check that the incoming argument count for
+	 * this method/object matches the actual ASL/AML definition.
+	 */
+	acpi_ns_check_argument_count(info->full_pathname, info->node,
+				     info->param_count, info->predefined);
 
-	node = info->resolved_node;
+	/* For predefined names: Typecheck all incoming arguments */
+
+	acpi_ns_check_argument_types(info);
 
 	/*
-	 * Two major cases here:
+	 * Three major evaluation cases:
 	 *
-	 * 1) The object is a control method -- execute it
-	 * 2) The object is not a method -- just return it's current value
+	 * 1) Object types that cannot be evaluated by definition
+	 * 2) The object is a control method -- execute it
+	 * 3) The object is not a method -- just return it's current value
 	 */
-	if (acpi_ns_get_type(info->resolved_node) == ACPI_TYPE_METHOD) {
+	switch (acpi_ns_get_type(info->node)) {
+	case ACPI_TYPE_DEVICE:
+	case ACPI_TYPE_EVENT:
+	case ACPI_TYPE_MUTEX:
+	case ACPI_TYPE_REGION:
+	case ACPI_TYPE_THERMAL:
+	case ACPI_TYPE_LOCAL_SCOPE:
+		/*
+		 * 1) Disallow evaluation of certain object types. For these,
+		 *    object evaluation is undefined and not supported.
+		 */
+		ACPI_ERROR((AE_INFO,
+			    "%s: Evaluation of object type [%s] is not supported",
+			    info->full_pathname,
+			    acpi_ut_get_type_name(info->node->type)));
+
+		status = AE_TYPE;
+		goto cleanup;
+
+	case ACPI_TYPE_METHOD:
 		/*
-		 * 1) Object is a control method - execute it
+		 * 2) Object is a control method - execute it
 		 */
 
 		/* Verify that there is a method object associated with this node */
 
-		info->obj_desc =
-		    acpi_ns_get_attached_object(info->resolved_node);
 		if (!info->obj_desc) {
 			ACPI_ERROR((AE_INFO,
-				    "Control method has no attached sub-object"));
-			return_ACPI_STATUS(AE_NULL_OBJECT);
+				    "%s: Method has no attached sub-object",
+				    info->full_pathname));
+			status = AE_NULL_OBJECT;
+			goto cleanup;
 		}
 
-		/* Count the number of arguments being passed to the method */
-
-		if (info->parameters) {
-			while (info->parameters[info->param_count]) {
-				if (info->param_count > ACPI_METHOD_MAX_ARG) {
-					return_ACPI_STATUS(AE_LIMIT);
-				}
-				info->param_count++;
-			}
-		}
-
-
-		ACPI_DUMP_PATHNAME(info->resolved_node, "ACPI: Execute Method",
-				   ACPI_LV_INFO, _COMPONENT);
-
 		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-				  "Method at AML address %p Length %X\n",
+				  "**** Execute method [%s] at AML address %p length %X\n",
+				  info->full_pathname,
 				  info->obj_desc->method.aml_start + 1,
 				  info->obj_desc->method.aml_length - 1));
 
@@ -184,81 +238,61 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
 		acpi_ex_enter_interpreter();
 		status = acpi_ps_execute_method(info);
 		acpi_ex_exit_interpreter();
-	} else {
+		break;
+
+	default:
 		/*
-		 * 2) Object is not a method, return its current value
-		 *
-		 * Disallow certain object types. For these, "evaluation" is undefined.
+		 * 3) All other non-method objects -- get the current object value
 		 */
-		switch (info->resolved_node->type) {
-		case ACPI_TYPE_DEVICE:
-		case ACPI_TYPE_EVENT:
-		case ACPI_TYPE_MUTEX:
-		case ACPI_TYPE_REGION:
-		case ACPI_TYPE_THERMAL:
-		case ACPI_TYPE_LOCAL_SCOPE:
-
-			ACPI_ERROR((AE_INFO,
-				    "[%4.4s] Evaluation of object type [%s] is not supported",
-				    info->resolved_node->name.ascii,
-				    acpi_ut_get_type_name(info->resolved_node->
-							  type)));
-
-			return_ACPI_STATUS(AE_TYPE);
-
-		default:
-			break;
-		}
 
 		/*
-		 * Objects require additional resolution steps (e.g., the Node may be
-		 * a field that must be read, etc.) -- we can't just grab the object
-		 * out of the node.
+		 * Some objects require additional resolution steps (e.g., the Node
+		 * may be a field that must be read, etc.) -- we can't just grab
+		 * the object out of the node.
 		 *
 		 * Use resolve_node_to_value() to get the associated value.
 		 *
 		 * NOTE: we can get away with passing in NULL for a walk state because
-		 * resolved_node is guaranteed to not be a reference to either a method
+		 * the Node is guaranteed to not be a reference to either a method
 		 * local or a method argument (because this interface is never called
 		 * from a running method.)
 		 *
 		 * Even though we do not directly invoke the interpreter for object
-		 * resolution, we must lock it because we could access an opregion.
-		 * The opregion access code assumes that the interpreter is locked.
+		 * resolution, we must lock it because we could access an op_region.
+		 * The op_region access code assumes that the interpreter is locked.
 		 */
 		acpi_ex_enter_interpreter();
 
-		/* Function has a strange interface */
+		/* TBD: resolve_node_to_value has a strange interface, fix */
+
+		info->return_object =
+		    ACPI_CAST_PTR(union acpi_operand_object, info->node);
 
 		status =
-		    acpi_ex_resolve_node_to_value(&info->resolved_node, NULL);
+		    acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR
+						  (struct acpi_namespace_node,
+						   &info->return_object), NULL);
 		acpi_ex_exit_interpreter();
 
-		/*
-		 * If acpi_ex_resolve_node_to_value() succeeded, the return value was placed
-		 * in resolved_node.
-		 */
-		if (ACPI_SUCCESS(status)) {
-			status = AE_CTRL_RETURN_VALUE;
-			info->return_object =
-			    ACPI_CAST_PTR(union acpi_operand_object,
-					  info->resolved_node);
-
-			ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
-					  "Returning object %p [%s]\n",
-					  info->return_object,
-					  acpi_ut_get_object_type_name(info->
-								       return_object)));
+		if (ACPI_FAILURE(status)) {
+			goto cleanup;
 		}
+
+		ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Returned object %p [%s]\n",
+				  info->return_object,
+				  acpi_ut_get_object_type_name(info->
+							       return_object)));
+
+		status = AE_CTRL_RETURN_VALUE;	/* Always has a "return value" */
+		break;
 	}
 
 	/*
-	 * Check input argument count against the ASL-defined count for a method.
-	 * Also check predefined names: argument count and return value against
-	 * the ACPI specification. Some incorrect return value types are repaired.
+	 * For predefined names, check the return value against the ACPI
+	 * specification. Some incorrect return value types are repaired.
 	 */
-	(void)acpi_ns_check_predefined_names(node, info->param_count,
-		status, &info->return_object);
+	(void)acpi_ns_check_return_value(info->node, info, info->param_count,
+					 status, &info->return_object);
 
 	/* Check if there is a return value that must be dealt with */
 
@@ -278,12 +312,15 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
 
 	ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
 			  "*** Completed evaluation of object %s ***\n",
-			  info->pathname));
+			  info->relative_pathname));
 
+ cleanup:
 	/*
 	 * Namespace was unlocked by the handling acpi_ns* function, so we
-	 * just return
+	 * just free the pathname and return
 	 */
+	ACPI_FREE(info->full_pathname);
+	info->full_pathname = NULL;
 	return_ACPI_STATUS(status);
 }