ACPICA: Consolidate method arg count validation code

Merge the code that validates control method argument counts into
the predefined validation module. Eliminates possible multiple
warnings for incorrect counts.

Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
Bob Moore 2008-11-13 11:19:24 +08:00 committed by Len Brown
parent a647b5c340
commit eeb4437e63
3 changed files with 104 additions and 74 deletions

View File

@ -89,6 +89,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
/* Initialize the return value to an invalid object */ /* Initialize the return value to an invalid object */
info->return_object = NULL; info->return_object = NULL;
info->param_count = 0;
/* /*
* Get the actual namespace node for the target object. Handles these cases: * Get the actual namespace node for the target object. Handles these cases:
@ -141,41 +142,17 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
return_ACPI_STATUS(AE_NULL_OBJECT); return_ACPI_STATUS(AE_NULL_OBJECT);
} }
/* /* Count the number of arguments being passed to the method */
* Calculate the number of arguments being passed to the method
*/
info->param_count = 0;
if (info->parameters) { if (info->parameters) {
while (info->parameters[info->param_count]) while (info->parameters[info->param_count]) {
if (info->param_count > ACPI_METHOD_MAX_ARG) {
return_ACPI_STATUS(AE_LIMIT);
}
info->param_count++; info->param_count++;
}
} }
/*
* Warning if too few or too many arguments have been passed by the
* caller. We don't want to abort here with an error because an
* incorrect number of arguments may not cause the method to fail.
* However, the method will fail if there are too few arguments passed
* and the method attempts to use one of the missing ones.
*/
if (info->param_count < info->obj_desc->method.param_count) {
ACPI_WARNING((AE_INFO,
"Insufficient arguments - "
"method [%4.4s] needs %d, found %d",
acpi_ut_get_node_name(info->resolved_node),
info->obj_desc->method.param_count,
info->param_count));
} else if (info->param_count >
info->obj_desc->method.param_count) {
ACPI_WARNING((AE_INFO,
"Excess arguments - "
"method [%4.4s] needs %d, found %d",
acpi_ut_get_node_name(info->
resolved_node),
info->obj_desc->method.param_count,
info->param_count));
}
ACPI_DUMP_PATHNAME(info->resolved_node, "Execute Method:", ACPI_DUMP_PATHNAME(info->resolved_node, "Execute Method:",
ACPI_LV_INFO, _COMPONENT); ACPI_LV_INFO, _COMPONENT);
@ -264,31 +241,13 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
} }
} }
/* Validation of return values for ACPI-predefined methods and objects */ /*
* Check input argument count against the ASL-defined count for a method.
if ((status == AE_OK) || (status == AE_CTRL_RETURN_VALUE)) { * Also check predefined names: argument count and return value against
/* * the ACPI specification. Some incorrect return value types are repaired.
* If this is the first evaluation, check the return value. This */
* ensures that any warnings will only be emitted during the very (void)acpi_ns_check_predefined_names(node, info->param_count,
* first evaluation of the object. status, &info->return_object);
*/
if (!(node->flags & ANOBJ_EVALUATED)) {
/*
* Check for a predefined ACPI name. If found, validate the
* returned object.
*
* Note: Ignore return status for now, emit warnings if there are
* problems with the returned object. May change later to abort
* the method on invalid return object.
*/
(void)acpi_ns_check_predefined_names(node,
&info->return_object);
}
/* Mark the node as having been evaluated */
node->flags |= ANOBJ_EVALUATED;
}
/* Check if there is a return value that must be dealt with */ /* Check if there is a return value that must be dealt with */

View File

@ -124,6 +124,8 @@ static const char *acpi_rtype_names[] = {
acpi_status acpi_status
acpi_ns_check_predefined_names(struct acpi_namespace_node *node, acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
u32 user_param_count,
acpi_status return_status,
union acpi_operand_object **return_object_ptr) union acpi_operand_object **return_object_ptr)
{ {
union acpi_operand_object *return_object = *return_object_ptr; union acpi_operand_object *return_object = *return_object_ptr;
@ -134,12 +136,6 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
/* Match the name for this method/object against the predefined list */ /* Match the name for this method/object against the predefined list */
predefined = acpi_ns_check_for_predefined_name(node); predefined = acpi_ns_check_for_predefined_name(node);
if (!predefined) {
/* Name was not one of the predefined names */
return (AE_OK);
}
/* Get the full pathname to the object, for use in error messages */ /* Get the full pathname to the object, for use in error messages */
@ -149,10 +145,37 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
} }
/* /*
* Check that the parameter count for this method is in accordance * Check that the parameter count for this method matches the ASL
* with the ACPI specification. * definition. For predefined names, ensure that both the caller and
* the method itself are in accordance with the ACPI specification.
*/ */
acpi_ns_check_parameter_count(pathname, node, predefined); acpi_ns_check_parameter_count(pathname, node, user_param_count,
predefined);
/* If not a predefined name, we cannot validate the return object */
if (!predefined) {
goto exit;
}
/* If the method failed, we cannot validate the return object */
if ((return_status != AE_OK) && (return_status != AE_CTRL_RETURN_VALUE)) {
goto exit;
}
/*
* Only validate the return value on the first successful evaluation of
* the method. This ensures that any warnings will only be emitted during
* the very first evaluation of the method/object.
*/
if (node->flags & ANOBJ_EVALUATED) {
goto exit;
}
/* Mark the node as having been successfully evaluated */
node->flags |= ANOBJ_EVALUATED;
/* /*
* If there is no return value, check if we require a return value for * If there is no return value, check if we require a return value for
@ -177,7 +200,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
* We have a return value, but if one wasn't expected, just exit, this is * We have a return value, but if one wasn't expected, just exit, this is
* not a problem * not a problem
* *
* For example, if "Implicit return value" is enabled, methods will * For example, if the "Implicit Return" feature is enabled, methods will
* always return a value * always return a value
*/ */
if (!predefined->info.expected_btypes) { if (!predefined->info.expected_btypes) {
@ -204,7 +227,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
} }
exit: exit:
if (pathname) { if (pathname != predefined->info.name) {
ACPI_FREE(pathname); ACPI_FREE(pathname);
} }
@ -217,6 +240,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
* *
* PARAMETERS: Pathname - Full pathname to the node (for error msgs) * PARAMETERS: Pathname - Full pathname to the node (for error msgs)
* Node - Namespace node for the method/object * Node - Namespace node for the method/object
* user_param_count - Number of args passed in by the caller
* Predefined - Pointer to entry in predefined name table * Predefined - Pointer to entry in predefined name table
* *
* RETURN: None * RETURN: None
@ -230,32 +254,76 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
void void
acpi_ns_check_parameter_count(char *pathname, acpi_ns_check_parameter_count(char *pathname,
struct acpi_namespace_node *node, struct acpi_namespace_node *node,
u32 user_param_count,
const union acpi_predefined_info *predefined) const union acpi_predefined_info *predefined)
{ {
u32 param_count; u32 param_count;
u32 required_params_current; u32 required_params_current;
u32 required_params_old; u32 required_params_old;
/* /* Methods have 0-7 parameters. All other types have zero. */
* Check that the ASL-defined parameter count is what is expected for
* this predefined name.
*
* Methods have 0-7 parameters. All other types have zero.
*/
param_count = 0; param_count = 0;
if (node->type == ACPI_TYPE_METHOD) { if (node->type == ACPI_TYPE_METHOD) {
param_count = node->object->method.param_count; param_count = node->object->method.param_count;
} }
/* Validate parameter count - allow two different legal counts (_SCP) */ /* Argument count check for non-predefined methods/objects */
if (!predefined) {
/*
* Warning if too few or too many arguments have been passed by the
* caller. An incorrect number of arguments may not cause the method
* to fail. However, the method will fail if there are too few
* arguments and the method attempts to use one of the missing ones.
*/
if (user_param_count < param_count) {
ACPI_WARNING((AE_INFO,
"%s: Insufficient arguments - needs %d, found %d",
pathname, param_count, user_param_count));
} else if (user_param_count > param_count) {
ACPI_WARNING((AE_INFO,
"%s: Excess arguments - needs %d, found %d",
pathname, param_count, user_param_count));
}
return;
}
/* Allow two different legal argument counts (_SCP, etc.) */
required_params_current = predefined->info.param_count & 0x0F; required_params_current = predefined->info.param_count & 0x0F;
required_params_old = predefined->info.param_count >> 4; required_params_old = predefined->info.param_count >> 4;
if (user_param_count != ACPI_UINT32_MAX) {
/* Validate the user-supplied parameter count */
if ((user_param_count != required_params_current) &&
(user_param_count != required_params_old)) {
ACPI_WARNING((AE_INFO,
"%s: Parameter count mismatch - caller passed %d, ACPI requires %d",
pathname, user_param_count,
required_params_current));
}
}
/*
* Only validate the argument count on the first successful evaluation of
* the method. This ensures that any warnings will only be emitted during
* the very first evaluation of the method/object.
*/
if (node->flags & ANOBJ_EVALUATED) {
return;
}
/*
* Check that the ASL-defined parameter count is what is expected for
* this predefined name.
*/
if ((param_count != required_params_current) && if ((param_count != required_params_current) &&
(param_count != required_params_old)) { (param_count != required_params_old)) {
ACPI_WARNING((AE_INFO, ACPI_WARNING((AE_INFO,
"%s: Parameter count mismatch - ASL declared %d, expected %d", "%s: Parameter count mismatch - ASL declared %d, ACPI requires %d",
pathname, param_count, required_params_current)); pathname, param_count, required_params_current));
} }
} }

View File

@ -182,6 +182,8 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info);
*/ */
acpi_status acpi_status
acpi_ns_check_predefined_names(struct acpi_namespace_node *node, acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
u32 user_param_count,
acpi_status return_status,
union acpi_operand_object **return_object); union acpi_operand_object **return_object);
const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
@ -191,6 +193,7 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
void void
acpi_ns_check_parameter_count(char *pathname, acpi_ns_check_parameter_count(char *pathname,
struct acpi_namespace_node *node, struct acpi_namespace_node *node,
u32 user_param_count,
const union acpi_predefined_info *info); const union acpi_predefined_info *info);
/* /*