162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: nsarguments - Validation of args for ACPI predefined methods 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci *****************************************************************************/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <acpi/acpi.h> 1162306a36Sopenharmony_ci#include "accommon.h" 1262306a36Sopenharmony_ci#include "acnamesp.h" 1362306a36Sopenharmony_ci#include "acpredef.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define _COMPONENT ACPI_NAMESPACE 1662306a36Sopenharmony_ciACPI_MODULE_NAME("nsarguments") 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/******************************************************************************* 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * FUNCTION: acpi_ns_check_argument_types 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * PARAMETERS: info - Method execution information block 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * RETURN: None 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * DESCRIPTION: Check the incoming argument count and all argument types 2762306a36Sopenharmony_ci * against the argument type list for a predefined name. 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci ******************************************************************************/ 3062306a36Sopenharmony_civoid acpi_ns_check_argument_types(struct acpi_evaluate_info *info) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci u16 arg_type_list; 3362306a36Sopenharmony_ci u8 arg_count; 3462306a36Sopenharmony_ci u8 arg_type; 3562306a36Sopenharmony_ci u8 user_arg_type; 3662306a36Sopenharmony_ci u32 i; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci /* 3962306a36Sopenharmony_ci * If not a predefined name, cannot typecheck args, because 4062306a36Sopenharmony_ci * we have no idea what argument types are expected. 4162306a36Sopenharmony_ci * Also, ignore typecheck if warnings/errors if this method 4262306a36Sopenharmony_ci * has already been evaluated at least once -- in order 4362306a36Sopenharmony_ci * to suppress repetitive messages. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci if (!info->predefined || (info->node->flags & ANOBJ_EVALUATED)) { 4662306a36Sopenharmony_ci return; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci arg_type_list = info->predefined->info.argument_list; 5062306a36Sopenharmony_ci arg_count = METHOD_GET_ARG_COUNT(arg_type_list); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci /* Typecheck all arguments */ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci for (i = 0; ((i < arg_count) && (i < info->param_count)); i++) { 5562306a36Sopenharmony_ci arg_type = METHOD_GET_NEXT_TYPE(arg_type_list); 5662306a36Sopenharmony_ci user_arg_type = info->parameters[i]->common.type; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* No typechecking for ACPI_TYPE_ANY */ 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if ((user_arg_type != arg_type) && (arg_type != ACPI_TYPE_ANY)) { 6162306a36Sopenharmony_ci ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, 6262306a36Sopenharmony_ci ACPI_WARN_ALWAYS, 6362306a36Sopenharmony_ci "Argument #%u type mismatch - " 6462306a36Sopenharmony_ci "Found [%s], ACPI requires [%s]", 6562306a36Sopenharmony_ci (i + 1), 6662306a36Sopenharmony_ci acpi_ut_get_type_name 6762306a36Sopenharmony_ci (user_arg_type), 6862306a36Sopenharmony_ci acpi_ut_get_type_name(arg_type))); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* Prevent any additional typechecking for this method */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci info->node->flags |= ANOBJ_EVALUATED; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/******************************************************************************* 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * FUNCTION: acpi_ns_check_acpi_compliance 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * PARAMETERS: pathname - Full pathname to the node (for error msgs) 8262306a36Sopenharmony_ci * node - Namespace node for the method/object 8362306a36Sopenharmony_ci * predefined - Pointer to entry in predefined name table 8462306a36Sopenharmony_ci * 8562306a36Sopenharmony_ci * RETURN: None 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * DESCRIPTION: Check that the declared parameter count (in ASL/AML) for a 8862306a36Sopenharmony_ci * predefined name is what is expected (matches what is defined in 8962306a36Sopenharmony_ci * the ACPI specification for this predefined name.) 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci ******************************************************************************/ 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_civoid 9462306a36Sopenharmony_ciacpi_ns_check_acpi_compliance(char *pathname, 9562306a36Sopenharmony_ci struct acpi_namespace_node *node, 9662306a36Sopenharmony_ci const union acpi_predefined_info *predefined) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci u32 aml_param_count; 9962306a36Sopenharmony_ci u32 required_param_count; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (!predefined || (node->flags & ANOBJ_EVALUATED)) { 10262306a36Sopenharmony_ci return; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* Get the ACPI-required arg count from the predefined info table */ 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci required_param_count = 10862306a36Sopenharmony_ci METHOD_GET_ARG_COUNT(predefined->info.argument_list); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* 11162306a36Sopenharmony_ci * If this object is not a control method, we can check if the ACPI 11262306a36Sopenharmony_ci * spec requires that it be a method. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_ci if (node->type != ACPI_TYPE_METHOD) { 11562306a36Sopenharmony_ci if (required_param_count > 0) { 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* Object requires args, must be implemented as a method */ 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname, 12062306a36Sopenharmony_ci ACPI_WARN_ALWAYS, 12162306a36Sopenharmony_ci "Object (%s) must be a control method with %u arguments", 12262306a36Sopenharmony_ci acpi_ut_get_type_name(node-> 12362306a36Sopenharmony_ci type), 12462306a36Sopenharmony_ci required_param_count)); 12562306a36Sopenharmony_ci } else if (!required_param_count 12662306a36Sopenharmony_ci && !predefined->info.expected_btypes) { 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* Object requires no args and no return value, must be a method */ 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname, 13162306a36Sopenharmony_ci ACPI_WARN_ALWAYS, 13262306a36Sopenharmony_ci "Object (%s) must be a control method " 13362306a36Sopenharmony_ci "with no arguments and no return value", 13462306a36Sopenharmony_ci acpi_ut_get_type_name(node-> 13562306a36Sopenharmony_ci type))); 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* 14262306a36Sopenharmony_ci * This is a control method. 14362306a36Sopenharmony_ci * Check that the ASL/AML-defined parameter count for this method 14462306a36Sopenharmony_ci * matches the ACPI-required parameter count 14562306a36Sopenharmony_ci * 14662306a36Sopenharmony_ci * Some methods are allowed to have a "minimum" number of args (_SCP) 14762306a36Sopenharmony_ci * because their definition in ACPI has changed over time. 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * Note: These are BIOS errors in the declaration of the object 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_ci aml_param_count = node->object->method.param_count; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (aml_param_count < required_param_count) { 15462306a36Sopenharmony_ci ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS, 15562306a36Sopenharmony_ci "Insufficient arguments - " 15662306a36Sopenharmony_ci "ASL declared %u, ACPI requires %u", 15762306a36Sopenharmony_ci aml_param_count, 15862306a36Sopenharmony_ci required_param_count)); 15962306a36Sopenharmony_ci } else if ((aml_param_count > required_param_count) 16062306a36Sopenharmony_ci && !(predefined->info. 16162306a36Sopenharmony_ci argument_list & ARG_COUNT_IS_MINIMUM)) { 16262306a36Sopenharmony_ci ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS, 16362306a36Sopenharmony_ci "Excess arguments - " 16462306a36Sopenharmony_ci "ASL declared %u, ACPI requires %u", 16562306a36Sopenharmony_ci aml_param_count, 16662306a36Sopenharmony_ci required_param_count)); 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/******************************************************************************* 17162306a36Sopenharmony_ci * 17262306a36Sopenharmony_ci * FUNCTION: acpi_ns_check_argument_count 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * PARAMETERS: pathname - Full pathname to the node (for error msgs) 17562306a36Sopenharmony_ci * node - Namespace node for the method/object 17662306a36Sopenharmony_ci * user_param_count - Number of args passed in by the caller 17762306a36Sopenharmony_ci * predefined - Pointer to entry in predefined name table 17862306a36Sopenharmony_ci * 17962306a36Sopenharmony_ci * RETURN: None 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci * DESCRIPTION: Check that incoming argument count matches the declared 18262306a36Sopenharmony_ci * parameter count (in the ASL/AML) for an object. 18362306a36Sopenharmony_ci * 18462306a36Sopenharmony_ci ******************************************************************************/ 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_civoid 18762306a36Sopenharmony_ciacpi_ns_check_argument_count(char *pathname, 18862306a36Sopenharmony_ci struct acpi_namespace_node *node, 18962306a36Sopenharmony_ci u32 user_param_count, 19062306a36Sopenharmony_ci const union acpi_predefined_info *predefined) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci u32 aml_param_count; 19362306a36Sopenharmony_ci u32 required_param_count; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (node->flags & ANOBJ_EVALUATED) { 19662306a36Sopenharmony_ci return; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (!predefined) { 20062306a36Sopenharmony_ci /* 20162306a36Sopenharmony_ci * Not a predefined name. Check the incoming user argument count 20262306a36Sopenharmony_ci * against the count that is specified in the method/object. 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_ci if (node->type != ACPI_TYPE_METHOD) { 20562306a36Sopenharmony_ci if (user_param_count) { 20662306a36Sopenharmony_ci ACPI_INFO_PREDEFINED((AE_INFO, pathname, 20762306a36Sopenharmony_ci ACPI_WARN_ALWAYS, 20862306a36Sopenharmony_ci "%u arguments were passed to a non-method ACPI object (%s)", 20962306a36Sopenharmony_ci user_param_count, 21062306a36Sopenharmony_ci acpi_ut_get_type_name 21162306a36Sopenharmony_ci (node->type))); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /* 21862306a36Sopenharmony_ci * This is a control method. Check the parameter count. 21962306a36Sopenharmony_ci * We can only check the incoming argument count against the 22062306a36Sopenharmony_ci * argument count declared for the method in the ASL/AML. 22162306a36Sopenharmony_ci * 22262306a36Sopenharmony_ci * Emit a message if too few or too many arguments have been passed 22362306a36Sopenharmony_ci * by the caller. 22462306a36Sopenharmony_ci * 22562306a36Sopenharmony_ci * Note: Too many arguments will not cause the method to 22662306a36Sopenharmony_ci * fail. However, the method will fail if there are too few 22762306a36Sopenharmony_ci * arguments and the method attempts to use one of the missing ones. 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_ci aml_param_count = node->object->method.param_count; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (user_param_count < aml_param_count) { 23262306a36Sopenharmony_ci ACPI_WARN_PREDEFINED((AE_INFO, pathname, 23362306a36Sopenharmony_ci ACPI_WARN_ALWAYS, 23462306a36Sopenharmony_ci "Insufficient arguments - " 23562306a36Sopenharmony_ci "Caller passed %u, method requires %u", 23662306a36Sopenharmony_ci user_param_count, 23762306a36Sopenharmony_ci aml_param_count)); 23862306a36Sopenharmony_ci } else if (user_param_count > aml_param_count) { 23962306a36Sopenharmony_ci ACPI_INFO_PREDEFINED((AE_INFO, pathname, 24062306a36Sopenharmony_ci ACPI_WARN_ALWAYS, 24162306a36Sopenharmony_ci "Excess arguments - " 24262306a36Sopenharmony_ci "Caller passed %u, method requires %u", 24362306a36Sopenharmony_ci user_param_count, 24462306a36Sopenharmony_ci aml_param_count)); 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci return; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* 25162306a36Sopenharmony_ci * This is a predefined name. Validate the user-supplied parameter 25262306a36Sopenharmony_ci * count against the ACPI specification. We don't validate against 25362306a36Sopenharmony_ci * the method itself because what is important here is that the 25462306a36Sopenharmony_ci * caller is in conformance with the spec. (The arg count for the 25562306a36Sopenharmony_ci * method was checked against the ACPI spec earlier.) 25662306a36Sopenharmony_ci * 25762306a36Sopenharmony_ci * Some methods are allowed to have a "minimum" number of args (_SCP) 25862306a36Sopenharmony_ci * because their definition in ACPI has changed over time. 25962306a36Sopenharmony_ci */ 26062306a36Sopenharmony_ci required_param_count = 26162306a36Sopenharmony_ci METHOD_GET_ARG_COUNT(predefined->info.argument_list); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (user_param_count < required_param_count) { 26462306a36Sopenharmony_ci ACPI_WARN_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS, 26562306a36Sopenharmony_ci "Insufficient arguments - " 26662306a36Sopenharmony_ci "Caller passed %u, ACPI requires %u", 26762306a36Sopenharmony_ci user_param_count, required_param_count)); 26862306a36Sopenharmony_ci } else if ((user_param_count > required_param_count) && 26962306a36Sopenharmony_ci !(predefined->info.argument_list & ARG_COUNT_IS_MINIMUM)) { 27062306a36Sopenharmony_ci ACPI_INFO_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS, 27162306a36Sopenharmony_ci "Excess arguments - " 27262306a36Sopenharmony_ci "Caller passed %u, ACPI requires %u", 27362306a36Sopenharmony_ci user_param_count, required_param_count)); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci} 276