162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: nsprepkg - Validation of package objects for predefined names 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("nsprepkg") 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* Local prototypes */ 1962306a36Sopenharmony_cistatic acpi_status 2062306a36Sopenharmony_ciacpi_ns_check_package_list(struct acpi_evaluate_info *info, 2162306a36Sopenharmony_ci const union acpi_predefined_info *package, 2262306a36Sopenharmony_ci union acpi_operand_object **elements, u32 count); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic acpi_status 2562306a36Sopenharmony_ciacpi_ns_check_package_elements(struct acpi_evaluate_info *info, 2662306a36Sopenharmony_ci union acpi_operand_object **elements, 2762306a36Sopenharmony_ci u8 type1, 2862306a36Sopenharmony_ci u32 count1, 2962306a36Sopenharmony_ci u8 type2, u32 count2, u32 start_index); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic acpi_status 3262306a36Sopenharmony_ciacpi_ns_custom_package(struct acpi_evaluate_info *info, 3362306a36Sopenharmony_ci union acpi_operand_object **elements, u32 count); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/******************************************************************************* 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * FUNCTION: acpi_ns_check_package 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * PARAMETERS: info - Method execution information block 4062306a36Sopenharmony_ci * return_object_ptr - Pointer to the object returned from the 4162306a36Sopenharmony_ci * evaluation of a method or object 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * RETURN: Status 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * DESCRIPTION: Check a returned package object for the correct count and 4662306a36Sopenharmony_ci * correct type of all sub-objects. 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci ******************************************************************************/ 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ciacpi_status 5162306a36Sopenharmony_ciacpi_ns_check_package(struct acpi_evaluate_info *info, 5262306a36Sopenharmony_ci union acpi_operand_object **return_object_ptr) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci union acpi_operand_object *return_object = *return_object_ptr; 5562306a36Sopenharmony_ci const union acpi_predefined_info *package; 5662306a36Sopenharmony_ci union acpi_operand_object **elements; 5762306a36Sopenharmony_ci acpi_status status = AE_OK; 5862306a36Sopenharmony_ci u32 expected_count; 5962306a36Sopenharmony_ci u32 count; 6062306a36Sopenharmony_ci u32 i; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_check_package); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* The package info for this name is in the next table entry */ 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci package = info->predefined + 1; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 6962306a36Sopenharmony_ci "%s Validating return Package of Type %X, Count %X\n", 7062306a36Sopenharmony_ci info->full_pathname, package->ret_info.type, 7162306a36Sopenharmony_ci return_object->package.count)); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* 7462306a36Sopenharmony_ci * For variable-length Packages, we can safely remove all embedded 7562306a36Sopenharmony_ci * and trailing NULL package elements 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci acpi_ns_remove_null_elements(info, package->ret_info.type, 7862306a36Sopenharmony_ci return_object); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* Extract package count and elements array */ 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci elements = return_object->package.elements; 8362306a36Sopenharmony_ci count = return_object->package.count; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* 8662306a36Sopenharmony_ci * Most packages must have at least one element. The only exception 8762306a36Sopenharmony_ci * is the variable-length package (ACPI_PTYPE1_VAR). 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci if (!count) { 9062306a36Sopenharmony_ci if (package->ret_info.type == ACPI_PTYPE1_VAR) { 9162306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, 9562306a36Sopenharmony_ci info->node_flags, 9662306a36Sopenharmony_ci "Return Package has no elements (empty)")); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_OPERAND_VALUE); 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* 10262306a36Sopenharmony_ci * Decode the type of the expected package contents 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * PTYPE1 packages contain no subpackages 10562306a36Sopenharmony_ci * PTYPE2 packages contain subpackages 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ci switch (package->ret_info.type) { 10862306a36Sopenharmony_ci case ACPI_PTYPE_CUSTOM: 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci status = acpi_ns_custom_package(info, elements, count); 11162306a36Sopenharmony_ci break; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci case ACPI_PTYPE1_FIXED: 11462306a36Sopenharmony_ci /* 11562306a36Sopenharmony_ci * The package count is fixed and there are no subpackages 11662306a36Sopenharmony_ci * 11762306a36Sopenharmony_ci * If package is too small, exit. 11862306a36Sopenharmony_ci * If package is larger than expected, issue warning but continue 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci expected_count = 12162306a36Sopenharmony_ci package->ret_info.count1 + package->ret_info.count2; 12262306a36Sopenharmony_ci if (count < expected_count) { 12362306a36Sopenharmony_ci goto package_too_small; 12462306a36Sopenharmony_ci } else if (count > expected_count) { 12562306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, 12662306a36Sopenharmony_ci "%s: Return Package is larger than needed - " 12762306a36Sopenharmony_ci "found %u, expected %u\n", 12862306a36Sopenharmony_ci info->full_pathname, count, 12962306a36Sopenharmony_ci expected_count)); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* Validate all elements of the returned package */ 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci status = acpi_ns_check_package_elements(info, elements, 13562306a36Sopenharmony_ci package->ret_info. 13662306a36Sopenharmony_ci object_type1, 13762306a36Sopenharmony_ci package->ret_info. 13862306a36Sopenharmony_ci count1, 13962306a36Sopenharmony_ci package->ret_info. 14062306a36Sopenharmony_ci object_type2, 14162306a36Sopenharmony_ci package->ret_info. 14262306a36Sopenharmony_ci count2, 0); 14362306a36Sopenharmony_ci break; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci case ACPI_PTYPE1_VAR: 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * The package count is variable, there are no subpackages, and all 14862306a36Sopenharmony_ci * elements must be of the same type 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci for (i = 0; i < count; i++) { 15162306a36Sopenharmony_ci status = acpi_ns_check_object_type(info, elements, 15262306a36Sopenharmony_ci package->ret_info. 15362306a36Sopenharmony_ci object_type1, i); 15462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 15562306a36Sopenharmony_ci return_ACPI_STATUS(status); 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci elements++; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci break; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci case ACPI_PTYPE1_OPTION: 16362306a36Sopenharmony_ci /* 16462306a36Sopenharmony_ci * The package count is variable, there are no subpackages. There are 16562306a36Sopenharmony_ci * a fixed number of required elements, and a variable number of 16662306a36Sopenharmony_ci * optional elements. 16762306a36Sopenharmony_ci * 16862306a36Sopenharmony_ci * Check if package is at least as large as the minimum required 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ci expected_count = package->ret_info3.count; 17162306a36Sopenharmony_ci if (count < expected_count) { 17262306a36Sopenharmony_ci goto package_too_small; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* Variable number of sub-objects */ 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci for (i = 0; i < count; i++) { 17862306a36Sopenharmony_ci if (i < package->ret_info3.count) { 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* These are the required package elements (0, 1, or 2) */ 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci status = 18362306a36Sopenharmony_ci acpi_ns_check_object_type(info, elements, 18462306a36Sopenharmony_ci package-> 18562306a36Sopenharmony_ci ret_info3. 18662306a36Sopenharmony_ci object_type[i], 18762306a36Sopenharmony_ci i); 18862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 18962306a36Sopenharmony_ci return_ACPI_STATUS(status); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci } else { 19262306a36Sopenharmony_ci /* These are the optional package elements */ 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci status = 19562306a36Sopenharmony_ci acpi_ns_check_object_type(info, elements, 19662306a36Sopenharmony_ci package-> 19762306a36Sopenharmony_ci ret_info3. 19862306a36Sopenharmony_ci tail_object_type, 19962306a36Sopenharmony_ci i); 20062306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 20162306a36Sopenharmony_ci return_ACPI_STATUS(status); 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci elements++; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci break; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci case ACPI_PTYPE2_REV_FIXED: 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* First element is the (Integer) revision */ 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci status = 21462306a36Sopenharmony_ci acpi_ns_check_object_type(info, elements, 21562306a36Sopenharmony_ci ACPI_RTYPE_INTEGER, 0); 21662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 21762306a36Sopenharmony_ci return_ACPI_STATUS(status); 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci elements++; 22162306a36Sopenharmony_ci count--; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* Examine the subpackages */ 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci status = 22662306a36Sopenharmony_ci acpi_ns_check_package_list(info, package, elements, count); 22762306a36Sopenharmony_ci break; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci case ACPI_PTYPE2_PKG_COUNT: 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* First element is the (Integer) count of subpackages to follow */ 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci status = 23462306a36Sopenharmony_ci acpi_ns_check_object_type(info, elements, 23562306a36Sopenharmony_ci ACPI_RTYPE_INTEGER, 0); 23662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 23762306a36Sopenharmony_ci return_ACPI_STATUS(status); 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* 24162306a36Sopenharmony_ci * Count cannot be larger than the parent package length, but allow it 24262306a36Sopenharmony_ci * to be smaller. The >= accounts for the Integer above. 24362306a36Sopenharmony_ci */ 24462306a36Sopenharmony_ci expected_count = (u32)(*elements)->integer.value; 24562306a36Sopenharmony_ci if (expected_count >= count) { 24662306a36Sopenharmony_ci goto package_too_small; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci count = expected_count; 25062306a36Sopenharmony_ci elements++; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* Examine the subpackages */ 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci status = 25562306a36Sopenharmony_ci acpi_ns_check_package_list(info, package, elements, count); 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci case ACPI_PTYPE2: 25962306a36Sopenharmony_ci case ACPI_PTYPE2_FIXED: 26062306a36Sopenharmony_ci case ACPI_PTYPE2_MIN: 26162306a36Sopenharmony_ci case ACPI_PTYPE2_COUNT: 26262306a36Sopenharmony_ci case ACPI_PTYPE2_FIX_VAR: 26362306a36Sopenharmony_ci /* 26462306a36Sopenharmony_ci * These types all return a single Package that consists of a 26562306a36Sopenharmony_ci * variable number of subpackages. 26662306a36Sopenharmony_ci * 26762306a36Sopenharmony_ci * First, ensure that the first element is a subpackage. If not, 26862306a36Sopenharmony_ci * the BIOS may have incorrectly returned the object as a single 26962306a36Sopenharmony_ci * package instead of a Package of Packages (a common error if 27062306a36Sopenharmony_ci * there is only one entry). We may be able to repair this by 27162306a36Sopenharmony_ci * wrapping the returned Package with a new outer Package. 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci if (*elements 27462306a36Sopenharmony_ci && ((*elements)->common.type != ACPI_TYPE_PACKAGE)) { 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* Create the new outer package and populate it */ 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci status = 27962306a36Sopenharmony_ci acpi_ns_wrap_with_package(info, return_object, 28062306a36Sopenharmony_ci return_object_ptr); 28162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 28262306a36Sopenharmony_ci return_ACPI_STATUS(status); 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* Update locals to point to the new package (of 1 element) */ 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return_object = *return_object_ptr; 28862306a36Sopenharmony_ci elements = return_object->package.elements; 28962306a36Sopenharmony_ci count = 1; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* Examine the subpackages */ 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci status = 29562306a36Sopenharmony_ci acpi_ns_check_package_list(info, package, elements, count); 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci case ACPI_PTYPE2_VAR_VAR: 29962306a36Sopenharmony_ci /* 30062306a36Sopenharmony_ci * Returns a variable list of packages, each with a variable list 30162306a36Sopenharmony_ci * of objects. 30262306a36Sopenharmony_ci */ 30362306a36Sopenharmony_ci break; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci case ACPI_PTYPE2_UUID_PAIR: 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* The package must contain pairs of (UUID + type) */ 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (count & 1) { 31062306a36Sopenharmony_ci expected_count = count + 1; 31162306a36Sopenharmony_ci goto package_too_small; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci while (count > 0) { 31562306a36Sopenharmony_ci status = acpi_ns_check_object_type(info, elements, 31662306a36Sopenharmony_ci package->ret_info. 31762306a36Sopenharmony_ci object_type1, 0); 31862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 31962306a36Sopenharmony_ci return_ACPI_STATUS(status); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* Validate length of the UUID buffer */ 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if ((*elements)->buffer.length != 16) { 32562306a36Sopenharmony_ci ACPI_WARN_PREDEFINED((AE_INFO, 32662306a36Sopenharmony_ci info->full_pathname, 32762306a36Sopenharmony_ci info->node_flags, 32862306a36Sopenharmony_ci "Invalid length for UUID Buffer")); 32962306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_OPERAND_VALUE); 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci status = acpi_ns_check_object_type(info, elements + 1, 33362306a36Sopenharmony_ci package->ret_info. 33462306a36Sopenharmony_ci object_type2, 0); 33562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 33662306a36Sopenharmony_ci return_ACPI_STATUS(status); 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci elements += 2; 34062306a36Sopenharmony_ci count -= 2; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci break; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci default: 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* Should not get here if predefined info table is correct */ 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, 34962306a36Sopenharmony_ci info->node_flags, 35062306a36Sopenharmony_ci "Invalid internal return type in table entry: %X", 35162306a36Sopenharmony_ci package->ret_info.type)); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_INTERNAL); 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci return_ACPI_STATUS(status); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cipackage_too_small: 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* Error exit for the case with an incorrect package count */ 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags, 36362306a36Sopenharmony_ci "Return Package is too small - found %u elements, expected %u", 36462306a36Sopenharmony_ci count, expected_count)); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_OPERAND_VALUE); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci/******************************************************************************* 37062306a36Sopenharmony_ci * 37162306a36Sopenharmony_ci * FUNCTION: acpi_ns_check_package_list 37262306a36Sopenharmony_ci * 37362306a36Sopenharmony_ci * PARAMETERS: info - Method execution information block 37462306a36Sopenharmony_ci * package - Pointer to package-specific info for method 37562306a36Sopenharmony_ci * elements - Element list of parent package. All elements 37662306a36Sopenharmony_ci * of this list should be of type Package. 37762306a36Sopenharmony_ci * count - Count of subpackages 37862306a36Sopenharmony_ci * 37962306a36Sopenharmony_ci * RETURN: Status 38062306a36Sopenharmony_ci * 38162306a36Sopenharmony_ci * DESCRIPTION: Examine a list of subpackages 38262306a36Sopenharmony_ci * 38362306a36Sopenharmony_ci ******************************************************************************/ 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic acpi_status 38662306a36Sopenharmony_ciacpi_ns_check_package_list(struct acpi_evaluate_info *info, 38762306a36Sopenharmony_ci const union acpi_predefined_info *package, 38862306a36Sopenharmony_ci union acpi_operand_object **elements, u32 count) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci union acpi_operand_object *sub_package; 39162306a36Sopenharmony_ci union acpi_operand_object **sub_elements; 39262306a36Sopenharmony_ci acpi_status status; 39362306a36Sopenharmony_ci u32 expected_count; 39462306a36Sopenharmony_ci u32 i; 39562306a36Sopenharmony_ci u32 j; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* 39862306a36Sopenharmony_ci * Validate each subpackage in the parent Package 39962306a36Sopenharmony_ci * 40062306a36Sopenharmony_ci * NOTE: assumes list of subpackages contains no NULL elements. 40162306a36Sopenharmony_ci * Any NULL elements should have been removed by earlier call 40262306a36Sopenharmony_ci * to acpi_ns_remove_null_elements. 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ci for (i = 0; i < count; i++) { 40562306a36Sopenharmony_ci sub_package = *elements; 40662306a36Sopenharmony_ci sub_elements = sub_package->package.elements; 40762306a36Sopenharmony_ci info->parent_package = sub_package; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* Each sub-object must be of type Package */ 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci status = acpi_ns_check_object_type(info, &sub_package, 41262306a36Sopenharmony_ci ACPI_RTYPE_PACKAGE, i); 41362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 41462306a36Sopenharmony_ci return (status); 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci /* Examine the different types of expected subpackages */ 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci info->parent_package = sub_package; 42062306a36Sopenharmony_ci switch (package->ret_info.type) { 42162306a36Sopenharmony_ci case ACPI_PTYPE2: 42262306a36Sopenharmony_ci case ACPI_PTYPE2_PKG_COUNT: 42362306a36Sopenharmony_ci case ACPI_PTYPE2_REV_FIXED: 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* Each subpackage has a fixed number of elements */ 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci expected_count = 42862306a36Sopenharmony_ci package->ret_info.count1 + package->ret_info.count2; 42962306a36Sopenharmony_ci if (sub_package->package.count < expected_count) { 43062306a36Sopenharmony_ci goto package_too_small; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci status = 43462306a36Sopenharmony_ci acpi_ns_check_package_elements(info, sub_elements, 43562306a36Sopenharmony_ci package->ret_info. 43662306a36Sopenharmony_ci object_type1, 43762306a36Sopenharmony_ci package->ret_info. 43862306a36Sopenharmony_ci count1, 43962306a36Sopenharmony_ci package->ret_info. 44062306a36Sopenharmony_ci object_type2, 44162306a36Sopenharmony_ci package->ret_info. 44262306a36Sopenharmony_ci count2, 0); 44362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 44462306a36Sopenharmony_ci return (status); 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci break; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci case ACPI_PTYPE2_FIX_VAR: 44962306a36Sopenharmony_ci /* 45062306a36Sopenharmony_ci * Each subpackage has a fixed number of elements and an 45162306a36Sopenharmony_ci * optional element 45262306a36Sopenharmony_ci */ 45362306a36Sopenharmony_ci expected_count = 45462306a36Sopenharmony_ci package->ret_info.count1 + package->ret_info.count2; 45562306a36Sopenharmony_ci if (sub_package->package.count < expected_count) { 45662306a36Sopenharmony_ci goto package_too_small; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci status = 46062306a36Sopenharmony_ci acpi_ns_check_package_elements(info, sub_elements, 46162306a36Sopenharmony_ci package->ret_info. 46262306a36Sopenharmony_ci object_type1, 46362306a36Sopenharmony_ci package->ret_info. 46462306a36Sopenharmony_ci count1, 46562306a36Sopenharmony_ci package->ret_info. 46662306a36Sopenharmony_ci object_type2, 46762306a36Sopenharmony_ci sub_package->package. 46862306a36Sopenharmony_ci count - 46962306a36Sopenharmony_ci package->ret_info. 47062306a36Sopenharmony_ci count1, 0); 47162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 47262306a36Sopenharmony_ci return (status); 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci break; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci case ACPI_PTYPE2_VAR_VAR: 47762306a36Sopenharmony_ci /* 47862306a36Sopenharmony_ci * Each subpackage has a fixed or variable number of elements 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci case ACPI_PTYPE2_FIXED: 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* Each subpackage has a fixed length */ 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci expected_count = package->ret_info2.count; 48762306a36Sopenharmony_ci if (sub_package->package.count < expected_count) { 48862306a36Sopenharmony_ci goto package_too_small; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* Check the type of each subpackage element */ 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci for (j = 0; j < expected_count; j++) { 49462306a36Sopenharmony_ci status = 49562306a36Sopenharmony_ci acpi_ns_check_object_type(info, 49662306a36Sopenharmony_ci &sub_elements[j], 49762306a36Sopenharmony_ci package-> 49862306a36Sopenharmony_ci ret_info2. 49962306a36Sopenharmony_ci object_type[j], 50062306a36Sopenharmony_ci j); 50162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 50262306a36Sopenharmony_ci return (status); 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci break; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci case ACPI_PTYPE2_MIN: 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* Each subpackage has a variable but minimum length */ 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci expected_count = package->ret_info.count1; 51262306a36Sopenharmony_ci if (sub_package->package.count < expected_count) { 51362306a36Sopenharmony_ci goto package_too_small; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* Check the type of each subpackage element */ 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci status = 51962306a36Sopenharmony_ci acpi_ns_check_package_elements(info, sub_elements, 52062306a36Sopenharmony_ci package->ret_info. 52162306a36Sopenharmony_ci object_type1, 52262306a36Sopenharmony_ci sub_package->package. 52362306a36Sopenharmony_ci count, 0, 0, 0); 52462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 52562306a36Sopenharmony_ci return (status); 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci break; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci case ACPI_PTYPE2_COUNT: 53062306a36Sopenharmony_ci /* 53162306a36Sopenharmony_ci * First element is the (Integer) count of elements, including 53262306a36Sopenharmony_ci * the count field (the ACPI name is num_elements) 53362306a36Sopenharmony_ci */ 53462306a36Sopenharmony_ci status = acpi_ns_check_object_type(info, sub_elements, 53562306a36Sopenharmony_ci ACPI_RTYPE_INTEGER, 53662306a36Sopenharmony_ci 0); 53762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 53862306a36Sopenharmony_ci return (status); 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* 54262306a36Sopenharmony_ci * Make sure package is large enough for the Count and is 54362306a36Sopenharmony_ci * is as large as the minimum size 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_ci expected_count = (u32)(*sub_elements)->integer.value; 54662306a36Sopenharmony_ci if (sub_package->package.count < expected_count) { 54762306a36Sopenharmony_ci goto package_too_small; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (sub_package->package.count < 55162306a36Sopenharmony_ci package->ret_info.count1) { 55262306a36Sopenharmony_ci expected_count = package->ret_info.count1; 55362306a36Sopenharmony_ci goto package_too_small; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (expected_count == 0) { 55762306a36Sopenharmony_ci /* 55862306a36Sopenharmony_ci * Either the num_entries element was originally zero or it was 55962306a36Sopenharmony_ci * a NULL element and repaired to an Integer of value zero. 56062306a36Sopenharmony_ci * In either case, repair it by setting num_entries to be the 56162306a36Sopenharmony_ci * actual size of the subpackage. 56262306a36Sopenharmony_ci */ 56362306a36Sopenharmony_ci expected_count = sub_package->package.count; 56462306a36Sopenharmony_ci (*sub_elements)->integer.value = expected_count; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci /* Check the type of each subpackage element */ 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci status = 57062306a36Sopenharmony_ci acpi_ns_check_package_elements(info, 57162306a36Sopenharmony_ci (sub_elements + 1), 57262306a36Sopenharmony_ci package->ret_info. 57362306a36Sopenharmony_ci object_type1, 57462306a36Sopenharmony_ci (expected_count - 1), 57562306a36Sopenharmony_ci 0, 0, 1); 57662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 57762306a36Sopenharmony_ci return (status); 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci break; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci default: /* Should not get here, type was validated by caller */ 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Invalid Package type: %X", 58462306a36Sopenharmony_ci package->ret_info.type)); 58562306a36Sopenharmony_ci return (AE_AML_INTERNAL); 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci elements++; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci return (AE_OK); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cipackage_too_small: 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* The subpackage count was smaller than required */ 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags, 59862306a36Sopenharmony_ci "Return SubPackage[%u] is too small - found %u elements, expected %u", 59962306a36Sopenharmony_ci i, sub_package->package.count, expected_count)); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci return (AE_AML_OPERAND_VALUE); 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci/******************************************************************************* 60562306a36Sopenharmony_ci * 60662306a36Sopenharmony_ci * FUNCTION: acpi_ns_custom_package 60762306a36Sopenharmony_ci * 60862306a36Sopenharmony_ci * PARAMETERS: info - Method execution information block 60962306a36Sopenharmony_ci * elements - Pointer to the package elements array 61062306a36Sopenharmony_ci * count - Element count for the package 61162306a36Sopenharmony_ci * 61262306a36Sopenharmony_ci * RETURN: Status 61362306a36Sopenharmony_ci * 61462306a36Sopenharmony_ci * DESCRIPTION: Check a returned package object for the correct count and 61562306a36Sopenharmony_ci * correct type of all sub-objects. 61662306a36Sopenharmony_ci * 61762306a36Sopenharmony_ci * NOTE: Currently used for the _BIX method only. When needed for two or more 61862306a36Sopenharmony_ci * methods, probably a detect/dispatch mechanism will be required. 61962306a36Sopenharmony_ci * 62062306a36Sopenharmony_ci ******************************************************************************/ 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic acpi_status 62362306a36Sopenharmony_ciacpi_ns_custom_package(struct acpi_evaluate_info *info, 62462306a36Sopenharmony_ci union acpi_operand_object **elements, u32 count) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci u32 expected_count; 62762306a36Sopenharmony_ci u32 version; 62862306a36Sopenharmony_ci acpi_status status = AE_OK; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci ACPI_FUNCTION_NAME(ns_custom_package); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci /* Get version number, must be Integer */ 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if ((*elements)->common.type != ACPI_TYPE_INTEGER) { 63562306a36Sopenharmony_ci ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, 63662306a36Sopenharmony_ci info->node_flags, 63762306a36Sopenharmony_ci "Return Package has invalid object type for version number")); 63862306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_OPERAND_TYPE); 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci version = (u32)(*elements)->integer.value; 64262306a36Sopenharmony_ci expected_count = 21; /* Version 1 */ 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (version == 0) { 64562306a36Sopenharmony_ci expected_count = 20; /* Version 0 */ 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (count < expected_count) { 64962306a36Sopenharmony_ci ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, 65062306a36Sopenharmony_ci info->node_flags, 65162306a36Sopenharmony_ci "Return Package is too small - found %u elements, expected %u", 65262306a36Sopenharmony_ci count, expected_count)); 65362306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_OPERAND_VALUE); 65462306a36Sopenharmony_ci } else if (count > expected_count) { 65562306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, 65662306a36Sopenharmony_ci "%s: Return Package is larger than needed - " 65762306a36Sopenharmony_ci "found %u, expected %u\n", 65862306a36Sopenharmony_ci info->full_pathname, count, expected_count)); 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci /* Validate all elements of the returned package */ 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci status = acpi_ns_check_package_elements(info, elements, 66462306a36Sopenharmony_ci ACPI_RTYPE_INTEGER, 16, 66562306a36Sopenharmony_ci ACPI_RTYPE_STRING, 4, 0); 66662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 66762306a36Sopenharmony_ci return_ACPI_STATUS(status); 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* Version 1 has a single trailing integer */ 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (version > 0) { 67362306a36Sopenharmony_ci status = acpi_ns_check_package_elements(info, elements + 20, 67462306a36Sopenharmony_ci ACPI_RTYPE_INTEGER, 1, 67562306a36Sopenharmony_ci 0, 0, 20); 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci return_ACPI_STATUS(status); 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci/******************************************************************************* 68262306a36Sopenharmony_ci * 68362306a36Sopenharmony_ci * FUNCTION: acpi_ns_check_package_elements 68462306a36Sopenharmony_ci * 68562306a36Sopenharmony_ci * PARAMETERS: info - Method execution information block 68662306a36Sopenharmony_ci * elements - Pointer to the package elements array 68762306a36Sopenharmony_ci * type1 - Object type for first group 68862306a36Sopenharmony_ci * count1 - Count for first group 68962306a36Sopenharmony_ci * type2 - Object type for second group 69062306a36Sopenharmony_ci * count2 - Count for second group 69162306a36Sopenharmony_ci * start_index - Start of the first group of elements 69262306a36Sopenharmony_ci * 69362306a36Sopenharmony_ci * RETURN: Status 69462306a36Sopenharmony_ci * 69562306a36Sopenharmony_ci * DESCRIPTION: Check that all elements of a package are of the correct object 69662306a36Sopenharmony_ci * type. Supports up to two groups of different object types. 69762306a36Sopenharmony_ci * 69862306a36Sopenharmony_ci ******************************************************************************/ 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic acpi_status 70162306a36Sopenharmony_ciacpi_ns_check_package_elements(struct acpi_evaluate_info *info, 70262306a36Sopenharmony_ci union acpi_operand_object **elements, 70362306a36Sopenharmony_ci u8 type1, 70462306a36Sopenharmony_ci u32 count1, 70562306a36Sopenharmony_ci u8 type2, u32 count2, u32 start_index) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci union acpi_operand_object **this_element = elements; 70862306a36Sopenharmony_ci acpi_status status; 70962306a36Sopenharmony_ci u32 i; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_check_package_elements); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* 71462306a36Sopenharmony_ci * Up to two groups of package elements are supported by the data 71562306a36Sopenharmony_ci * structure. All elements in each group must be of the same type. 71662306a36Sopenharmony_ci * The second group can have a count of zero. 71762306a36Sopenharmony_ci */ 71862306a36Sopenharmony_ci for (i = 0; i < count1; i++) { 71962306a36Sopenharmony_ci status = acpi_ns_check_object_type(info, this_element, 72062306a36Sopenharmony_ci type1, i + start_index); 72162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 72262306a36Sopenharmony_ci return_ACPI_STATUS(status); 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci this_element++; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci for (i = 0; i < count2; i++) { 72962306a36Sopenharmony_ci status = acpi_ns_check_object_type(info, this_element, 73062306a36Sopenharmony_ci type2, 73162306a36Sopenharmony_ci (i + count1 + start_index)); 73262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 73362306a36Sopenharmony_ci return_ACPI_STATUS(status); 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci this_element++; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 74062306a36Sopenharmony_ci} 741