xref: /linux/drivers/acpi/acpica/nsprepkg.c (revision 1fad87385e7e82f656fb661aef0f841e42991974)
142f8fb75SBob Moore /******************************************************************************
242f8fb75SBob Moore  *
342f8fb75SBob Moore  * Module Name: nsprepkg - Validation of package objects for predefined names
442f8fb75SBob Moore  *
542f8fb75SBob Moore  *****************************************************************************/
642f8fb75SBob Moore 
742f8fb75SBob Moore /*
882a80941SDavid E. Box  * Copyright (C) 2000 - 2015, Intel Corp.
942f8fb75SBob Moore  * All rights reserved.
1042f8fb75SBob Moore  *
1142f8fb75SBob Moore  * Redistribution and use in source and binary forms, with or without
1242f8fb75SBob Moore  * modification, are permitted provided that the following conditions
1342f8fb75SBob Moore  * are met:
1442f8fb75SBob Moore  * 1. Redistributions of source code must retain the above copyright
1542f8fb75SBob Moore  *    notice, this list of conditions, and the following disclaimer,
1642f8fb75SBob Moore  *    without modification.
1742f8fb75SBob Moore  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1842f8fb75SBob Moore  *    substantially similar to the "NO WARRANTY" disclaimer below
1942f8fb75SBob Moore  *    ("Disclaimer") and any redistribution must be conditioned upon
2042f8fb75SBob Moore  *    including a substantially similar Disclaimer requirement for further
2142f8fb75SBob Moore  *    binary redistribution.
2242f8fb75SBob Moore  * 3. Neither the names of the above-listed copyright holders nor the names
2342f8fb75SBob Moore  *    of any contributors may be used to endorse or promote products derived
2442f8fb75SBob Moore  *    from this software without specific prior written permission.
2542f8fb75SBob Moore  *
2642f8fb75SBob Moore  * Alternatively, this software may be distributed under the terms of the
2742f8fb75SBob Moore  * GNU General Public License ("GPL") version 2 as published by the Free
2842f8fb75SBob Moore  * Software Foundation.
2942f8fb75SBob Moore  *
3042f8fb75SBob Moore  * NO WARRANTY
3142f8fb75SBob Moore  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3242f8fb75SBob Moore  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3342f8fb75SBob Moore  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3442f8fb75SBob Moore  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3542f8fb75SBob Moore  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3642f8fb75SBob Moore  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3742f8fb75SBob Moore  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3842f8fb75SBob Moore  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3942f8fb75SBob Moore  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
4042f8fb75SBob Moore  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4142f8fb75SBob Moore  * POSSIBILITY OF SUCH DAMAGES.
4242f8fb75SBob Moore  */
4342f8fb75SBob Moore 
4442f8fb75SBob Moore #include <acpi/acpi.h>
4542f8fb75SBob Moore #include "accommon.h"
4642f8fb75SBob Moore #include "acnamesp.h"
4742f8fb75SBob Moore #include "acpredef.h"
4842f8fb75SBob Moore 
4942f8fb75SBob Moore #define _COMPONENT          ACPI_NAMESPACE
5042f8fb75SBob Moore ACPI_MODULE_NAME("nsprepkg")
5142f8fb75SBob Moore 
5242f8fb75SBob Moore /* Local prototypes */
5342f8fb75SBob Moore static acpi_status
5429a241ccSBob Moore acpi_ns_check_package_list(struct acpi_evaluate_info *info,
5542f8fb75SBob Moore 			   const union acpi_predefined_info *package,
5642f8fb75SBob Moore 			   union acpi_operand_object **elements, u32 count);
5742f8fb75SBob Moore 
5842f8fb75SBob Moore static acpi_status
5929a241ccSBob Moore acpi_ns_check_package_elements(struct acpi_evaluate_info *info,
6042f8fb75SBob Moore 			       union acpi_operand_object **elements,
6142f8fb75SBob Moore 			       u8 type1,
6242f8fb75SBob Moore 			       u32 count1,
6342f8fb75SBob Moore 			       u8 type2, u32 count2, u32 start_index);
6442f8fb75SBob Moore 
6542f8fb75SBob Moore /*******************************************************************************
6642f8fb75SBob Moore  *
6742f8fb75SBob Moore  * FUNCTION:    acpi_ns_check_package
6842f8fb75SBob Moore  *
6929a241ccSBob Moore  * PARAMETERS:  info                - Method execution information block
7042f8fb75SBob Moore  *              return_object_ptr   - Pointer to the object returned from the
7142f8fb75SBob Moore  *                                    evaluation of a method or object
7242f8fb75SBob Moore  *
7342f8fb75SBob Moore  * RETURN:      Status
7442f8fb75SBob Moore  *
7542f8fb75SBob Moore  * DESCRIPTION: Check a returned package object for the correct count and
7642f8fb75SBob Moore  *              correct type of all sub-objects.
7742f8fb75SBob Moore  *
7842f8fb75SBob Moore  ******************************************************************************/
7942f8fb75SBob Moore 
8042f8fb75SBob Moore acpi_status
8129a241ccSBob Moore acpi_ns_check_package(struct acpi_evaluate_info *info,
8242f8fb75SBob Moore 		      union acpi_operand_object **return_object_ptr)
8342f8fb75SBob Moore {
8442f8fb75SBob Moore 	union acpi_operand_object *return_object = *return_object_ptr;
8542f8fb75SBob Moore 	const union acpi_predefined_info *package;
8642f8fb75SBob Moore 	union acpi_operand_object **elements;
8742f8fb75SBob Moore 	acpi_status status = AE_OK;
8842f8fb75SBob Moore 	u32 expected_count;
8942f8fb75SBob Moore 	u32 count;
9042f8fb75SBob Moore 	u32 i;
9142f8fb75SBob Moore 
9242f8fb75SBob Moore 	ACPI_FUNCTION_NAME(ns_check_package);
9342f8fb75SBob Moore 
9442f8fb75SBob Moore 	/* The package info for this name is in the next table entry */
9542f8fb75SBob Moore 
9629a241ccSBob Moore 	package = info->predefined + 1;
9742f8fb75SBob Moore 
9842f8fb75SBob Moore 	ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
9942f8fb75SBob Moore 			  "%s Validating return Package of Type %X, Count %X\n",
10029a241ccSBob Moore 			  info->full_pathname, package->ret_info.type,
10142f8fb75SBob Moore 			  return_object->package.count));
10242f8fb75SBob Moore 
10342f8fb75SBob Moore 	/*
10442f8fb75SBob Moore 	 * For variable-length Packages, we can safely remove all embedded
10542f8fb75SBob Moore 	 * and trailing NULL package elements
10642f8fb75SBob Moore 	 */
10729a241ccSBob Moore 	acpi_ns_remove_null_elements(info, package->ret_info.type,
10842f8fb75SBob Moore 				     return_object);
10942f8fb75SBob Moore 
11042f8fb75SBob Moore 	/* Extract package count and elements array */
11142f8fb75SBob Moore 
11242f8fb75SBob Moore 	elements = return_object->package.elements;
11342f8fb75SBob Moore 	count = return_object->package.count;
11442f8fb75SBob Moore 
11502d4fb36SBob Moore 	/*
11602d4fb36SBob Moore 	 * Most packages must have at least one element. The only exception
11702d4fb36SBob Moore 	 * is the variable-length package (ACPI_PTYPE1_VAR).
11802d4fb36SBob Moore 	 */
11942f8fb75SBob Moore 	if (!count) {
12002d4fb36SBob Moore 		if (package->ret_info.type == ACPI_PTYPE1_VAR) {
12102d4fb36SBob Moore 			return (AE_OK);
12202d4fb36SBob Moore 		}
12302d4fb36SBob Moore 
12429a241ccSBob Moore 		ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
12529a241ccSBob Moore 				      info->node_flags,
12642f8fb75SBob Moore 				      "Return Package has no elements (empty)"));
12742f8fb75SBob Moore 
12842f8fb75SBob Moore 		return (AE_AML_OPERAND_VALUE);
12942f8fb75SBob Moore 	}
13042f8fb75SBob Moore 
13142f8fb75SBob Moore 	/*
13242f8fb75SBob Moore 	 * Decode the type of the expected package contents
13342f8fb75SBob Moore 	 *
13442f8fb75SBob Moore 	 * PTYPE1 packages contain no subpackages
1350a16d12aSBob Moore 	 * PTYPE2 packages contain subpackages
13642f8fb75SBob Moore 	 */
13742f8fb75SBob Moore 	switch (package->ret_info.type) {
13842f8fb75SBob Moore 	case ACPI_PTYPE1_FIXED:
13942f8fb75SBob Moore 		/*
1400a16d12aSBob Moore 		 * The package count is fixed and there are no subpackages
14142f8fb75SBob Moore 		 *
14242f8fb75SBob Moore 		 * If package is too small, exit.
14342f8fb75SBob Moore 		 * If package is larger than expected, issue warning but continue
14442f8fb75SBob Moore 		 */
14542f8fb75SBob Moore 		expected_count =
14642f8fb75SBob Moore 		    package->ret_info.count1 + package->ret_info.count2;
14742f8fb75SBob Moore 		if (count < expected_count) {
14842f8fb75SBob Moore 			goto package_too_small;
14942f8fb75SBob Moore 		} else if (count > expected_count) {
15042f8fb75SBob Moore 			ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
15142f8fb75SBob Moore 					  "%s: Return Package is larger than needed - "
15242f8fb75SBob Moore 					  "found %u, expected %u\n",
15329a241ccSBob Moore 					  info->full_pathname, count,
15442f8fb75SBob Moore 					  expected_count));
15542f8fb75SBob Moore 		}
15642f8fb75SBob Moore 
15742f8fb75SBob Moore 		/* Validate all elements of the returned package */
15842f8fb75SBob Moore 
15929a241ccSBob Moore 		status = acpi_ns_check_package_elements(info, elements,
16042f8fb75SBob Moore 							package->ret_info.
16142f8fb75SBob Moore 							object_type1,
16242f8fb75SBob Moore 							package->ret_info.
16342f8fb75SBob Moore 							count1,
16442f8fb75SBob Moore 							package->ret_info.
16542f8fb75SBob Moore 							object_type2,
16642f8fb75SBob Moore 							package->ret_info.
16742f8fb75SBob Moore 							count2, 0);
16842f8fb75SBob Moore 		break;
16942f8fb75SBob Moore 
17042f8fb75SBob Moore 	case ACPI_PTYPE1_VAR:
17142f8fb75SBob Moore 		/*
1720a16d12aSBob Moore 		 * The package count is variable, there are no subpackages, and all
17342f8fb75SBob Moore 		 * elements must be of the same type
17442f8fb75SBob Moore 		 */
17542f8fb75SBob Moore 		for (i = 0; i < count; i++) {
17629a241ccSBob Moore 			status = acpi_ns_check_object_type(info, elements,
17742f8fb75SBob Moore 							   package->ret_info.
17842f8fb75SBob Moore 							   object_type1, i);
17942f8fb75SBob Moore 			if (ACPI_FAILURE(status)) {
18042f8fb75SBob Moore 				return (status);
18142f8fb75SBob Moore 			}
18242f8fb75SBob Moore 			elements++;
18342f8fb75SBob Moore 		}
18442f8fb75SBob Moore 		break;
18542f8fb75SBob Moore 
18642f8fb75SBob Moore 	case ACPI_PTYPE1_OPTION:
18742f8fb75SBob Moore 		/*
1880a16d12aSBob Moore 		 * The package count is variable, there are no subpackages. There are
18942f8fb75SBob Moore 		 * a fixed number of required elements, and a variable number of
19042f8fb75SBob Moore 		 * optional elements.
19142f8fb75SBob Moore 		 *
19242f8fb75SBob Moore 		 * Check if package is at least as large as the minimum required
19342f8fb75SBob Moore 		 */
19442f8fb75SBob Moore 		expected_count = package->ret_info3.count;
19542f8fb75SBob Moore 		if (count < expected_count) {
19642f8fb75SBob Moore 			goto package_too_small;
19742f8fb75SBob Moore 		}
19842f8fb75SBob Moore 
19942f8fb75SBob Moore 		/* Variable number of sub-objects */
20042f8fb75SBob Moore 
20142f8fb75SBob Moore 		for (i = 0; i < count; i++) {
20242f8fb75SBob Moore 			if (i < package->ret_info3.count) {
20342f8fb75SBob Moore 
20442f8fb75SBob Moore 				/* These are the required package elements (0, 1, or 2) */
20542f8fb75SBob Moore 
20642f8fb75SBob Moore 				status =
20729a241ccSBob Moore 				    acpi_ns_check_object_type(info, elements,
20842f8fb75SBob Moore 							      package->
20942f8fb75SBob Moore 							      ret_info3.
21042f8fb75SBob Moore 							      object_type[i],
21142f8fb75SBob Moore 							      i);
21242f8fb75SBob Moore 				if (ACPI_FAILURE(status)) {
21342f8fb75SBob Moore 					return (status);
21442f8fb75SBob Moore 				}
21542f8fb75SBob Moore 			} else {
21642f8fb75SBob Moore 				/* These are the optional package elements */
21742f8fb75SBob Moore 
21842f8fb75SBob Moore 				status =
21929a241ccSBob Moore 				    acpi_ns_check_object_type(info, elements,
22042f8fb75SBob Moore 							      package->
22142f8fb75SBob Moore 							      ret_info3.
22242f8fb75SBob Moore 							      tail_object_type,
22342f8fb75SBob Moore 							      i);
22442f8fb75SBob Moore 				if (ACPI_FAILURE(status)) {
22542f8fb75SBob Moore 					return (status);
22642f8fb75SBob Moore 				}
22742f8fb75SBob Moore 			}
22842f8fb75SBob Moore 			elements++;
22942f8fb75SBob Moore 		}
23042f8fb75SBob Moore 		break;
23142f8fb75SBob Moore 
23242f8fb75SBob Moore 	case ACPI_PTYPE2_REV_FIXED:
23342f8fb75SBob Moore 
23442f8fb75SBob Moore 		/* First element is the (Integer) revision */
23542f8fb75SBob Moore 
236*1fad8738SBob Moore 		status =
237*1fad8738SBob Moore 		    acpi_ns_check_object_type(info, elements,
23842f8fb75SBob Moore 					      ACPI_RTYPE_INTEGER, 0);
23942f8fb75SBob Moore 		if (ACPI_FAILURE(status)) {
24042f8fb75SBob Moore 			return (status);
24142f8fb75SBob Moore 		}
24242f8fb75SBob Moore 
24342f8fb75SBob Moore 		elements++;
24442f8fb75SBob Moore 		count--;
24542f8fb75SBob Moore 
2460a16d12aSBob Moore 		/* Examine the subpackages */
24742f8fb75SBob Moore 
24842f8fb75SBob Moore 		status =
24929a241ccSBob Moore 		    acpi_ns_check_package_list(info, package, elements, count);
25042f8fb75SBob Moore 		break;
25142f8fb75SBob Moore 
25242f8fb75SBob Moore 	case ACPI_PTYPE2_PKG_COUNT:
25342f8fb75SBob Moore 
2540a16d12aSBob Moore 		/* First element is the (Integer) count of subpackages to follow */
25542f8fb75SBob Moore 
256*1fad8738SBob Moore 		status =
257*1fad8738SBob Moore 		    acpi_ns_check_object_type(info, elements,
25842f8fb75SBob Moore 					      ACPI_RTYPE_INTEGER, 0);
25942f8fb75SBob Moore 		if (ACPI_FAILURE(status)) {
26042f8fb75SBob Moore 			return (status);
26142f8fb75SBob Moore 		}
26242f8fb75SBob Moore 
26342f8fb75SBob Moore 		/*
26442f8fb75SBob Moore 		 * Count cannot be larger than the parent package length, but allow it
26542f8fb75SBob Moore 		 * to be smaller. The >= accounts for the Integer above.
26642f8fb75SBob Moore 		 */
26742f8fb75SBob Moore 		expected_count = (u32)(*elements)->integer.value;
26842f8fb75SBob Moore 		if (expected_count >= count) {
26942f8fb75SBob Moore 			goto package_too_small;
27042f8fb75SBob Moore 		}
27142f8fb75SBob Moore 
27242f8fb75SBob Moore 		count = expected_count;
27342f8fb75SBob Moore 		elements++;
27442f8fb75SBob Moore 
2750a16d12aSBob Moore 		/* Examine the subpackages */
27642f8fb75SBob Moore 
27742f8fb75SBob Moore 		status =
27829a241ccSBob Moore 		    acpi_ns_check_package_list(info, package, elements, count);
27942f8fb75SBob Moore 		break;
28042f8fb75SBob Moore 
28142f8fb75SBob Moore 	case ACPI_PTYPE2:
28242f8fb75SBob Moore 	case ACPI_PTYPE2_FIXED:
28342f8fb75SBob Moore 	case ACPI_PTYPE2_MIN:
28442f8fb75SBob Moore 	case ACPI_PTYPE2_COUNT:
28542f8fb75SBob Moore 	case ACPI_PTYPE2_FIX_VAR:
28642f8fb75SBob Moore 		/*
28742f8fb75SBob Moore 		 * These types all return a single Package that consists of a
2880a16d12aSBob Moore 		 * variable number of subpackages.
28942f8fb75SBob Moore 		 *
2900a16d12aSBob Moore 		 * First, ensure that the first element is a subpackage. If not,
29142f8fb75SBob Moore 		 * the BIOS may have incorrectly returned the object as a single
29242f8fb75SBob Moore 		 * package instead of a Package of Packages (a common error if
29342f8fb75SBob Moore 		 * there is only one entry). We may be able to repair this by
29442f8fb75SBob Moore 		 * wrapping the returned Package with a new outer Package.
29542f8fb75SBob Moore 		 */
29642f8fb75SBob Moore 		if (*elements
29742f8fb75SBob Moore 		    && ((*elements)->common.type != ACPI_TYPE_PACKAGE)) {
29842f8fb75SBob Moore 
29942f8fb75SBob Moore 			/* Create the new outer package and populate it */
30042f8fb75SBob Moore 
30142f8fb75SBob Moore 			status =
30229a241ccSBob Moore 			    acpi_ns_wrap_with_package(info, return_object,
30342f8fb75SBob Moore 						      return_object_ptr);
30442f8fb75SBob Moore 			if (ACPI_FAILURE(status)) {
30542f8fb75SBob Moore 				return (status);
30642f8fb75SBob Moore 			}
30742f8fb75SBob Moore 
30842f8fb75SBob Moore 			/* Update locals to point to the new package (of 1 element) */
30942f8fb75SBob Moore 
31042f8fb75SBob Moore 			return_object = *return_object_ptr;
31142f8fb75SBob Moore 			elements = return_object->package.elements;
31242f8fb75SBob Moore 			count = 1;
31342f8fb75SBob Moore 		}
31442f8fb75SBob Moore 
3150a16d12aSBob Moore 		/* Examine the subpackages */
31642f8fb75SBob Moore 
31742f8fb75SBob Moore 		status =
31829a241ccSBob Moore 		    acpi_ns_check_package_list(info, package, elements, count);
31942f8fb75SBob Moore 		break;
32042f8fb75SBob Moore 
321e34a7813SBob Moore 	case ACPI_PTYPE2_VAR_VAR:
322e34a7813SBob Moore 		/*
323e34a7813SBob Moore 		 * Returns a variable list of packages, each with a variable list
324e34a7813SBob Moore 		 * of objects.
325e34a7813SBob Moore 		 */
326e34a7813SBob Moore 		break;
327e34a7813SBob Moore 
328b1272e1fSMika Westerberg 	case ACPI_PTYPE2_UUID_PAIR:
329b1272e1fSMika Westerberg 
330b1272e1fSMika Westerberg 		/* The package must contain pairs of (UUID + type) */
331b1272e1fSMika Westerberg 
332b1272e1fSMika Westerberg 		if (count & 1) {
333b1272e1fSMika Westerberg 			expected_count = count + 1;
334b1272e1fSMika Westerberg 			goto package_too_small;
335b1272e1fSMika Westerberg 		}
336b1272e1fSMika Westerberg 
337b1272e1fSMika Westerberg 		while (count > 0) {
338b1272e1fSMika Westerberg 			status = acpi_ns_check_object_type(info, elements,
339b1272e1fSMika Westerberg 							   package->ret_info.
340b1272e1fSMika Westerberg 							   object_type1, 0);
341b1272e1fSMika Westerberg 			if (ACPI_FAILURE(status)) {
342b1272e1fSMika Westerberg 				return (status);
343b1272e1fSMika Westerberg 			}
344b1272e1fSMika Westerberg 
345b1272e1fSMika Westerberg 			/* Validate length of the UUID buffer */
346b1272e1fSMika Westerberg 
347b1272e1fSMika Westerberg 			if ((*elements)->buffer.length != 16) {
348b1272e1fSMika Westerberg 				ACPI_WARN_PREDEFINED((AE_INFO,
349b1272e1fSMika Westerberg 						      info->full_pathname,
350b1272e1fSMika Westerberg 						      info->node_flags,
351b1272e1fSMika Westerberg 						      "Invalid length for UUID Buffer"));
352b1272e1fSMika Westerberg 				return (AE_AML_OPERAND_VALUE);
353b1272e1fSMika Westerberg 			}
354b1272e1fSMika Westerberg 
355b1272e1fSMika Westerberg 			status = acpi_ns_check_object_type(info, elements + 1,
356b1272e1fSMika Westerberg 							   package->ret_info.
357b1272e1fSMika Westerberg 							   object_type2, 0);
358b1272e1fSMika Westerberg 			if (ACPI_FAILURE(status)) {
359b1272e1fSMika Westerberg 				return (status);
360b1272e1fSMika Westerberg 			}
361b1272e1fSMika Westerberg 
362b1272e1fSMika Westerberg 			elements += 2;
363b1272e1fSMika Westerberg 			count -= 2;
364b1272e1fSMika Westerberg 		}
365b1272e1fSMika Westerberg 		break;
366b1272e1fSMika Westerberg 
36742f8fb75SBob Moore 	default:
36842f8fb75SBob Moore 
36942f8fb75SBob Moore 		/* Should not get here if predefined info table is correct */
37042f8fb75SBob Moore 
37129a241ccSBob Moore 		ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
37229a241ccSBob Moore 				      info->node_flags,
37342f8fb75SBob Moore 				      "Invalid internal return type in table entry: %X",
37442f8fb75SBob Moore 				      package->ret_info.type));
37542f8fb75SBob Moore 
37642f8fb75SBob Moore 		return (AE_AML_INTERNAL);
37742f8fb75SBob Moore 	}
37842f8fb75SBob Moore 
37942f8fb75SBob Moore 	return (status);
38042f8fb75SBob Moore 
38142f8fb75SBob Moore package_too_small:
38242f8fb75SBob Moore 
38342f8fb75SBob Moore 	/* Error exit for the case with an incorrect package count */
38442f8fb75SBob Moore 
38529a241ccSBob Moore 	ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags,
38642f8fb75SBob Moore 			      "Return Package is too small - found %u elements, expected %u",
38742f8fb75SBob Moore 			      count, expected_count));
38842f8fb75SBob Moore 
38942f8fb75SBob Moore 	return (AE_AML_OPERAND_VALUE);
39042f8fb75SBob Moore }
39142f8fb75SBob Moore 
39242f8fb75SBob Moore /*******************************************************************************
39342f8fb75SBob Moore  *
39442f8fb75SBob Moore  * FUNCTION:    acpi_ns_check_package_list
39542f8fb75SBob Moore  *
39629a241ccSBob Moore  * PARAMETERS:  info            - Method execution information block
39742f8fb75SBob Moore  *              package         - Pointer to package-specific info for method
39842f8fb75SBob Moore  *              elements        - Element list of parent package. All elements
39942f8fb75SBob Moore  *                                of this list should be of type Package.
40042f8fb75SBob Moore  *              count           - Count of subpackages
40142f8fb75SBob Moore  *
40242f8fb75SBob Moore  * RETURN:      Status
40342f8fb75SBob Moore  *
40442f8fb75SBob Moore  * DESCRIPTION: Examine a list of subpackages
40542f8fb75SBob Moore  *
40642f8fb75SBob Moore  ******************************************************************************/
40742f8fb75SBob Moore 
40842f8fb75SBob Moore static acpi_status
40929a241ccSBob Moore acpi_ns_check_package_list(struct acpi_evaluate_info *info,
41042f8fb75SBob Moore 			   const union acpi_predefined_info *package,
41142f8fb75SBob Moore 			   union acpi_operand_object **elements, u32 count)
41242f8fb75SBob Moore {
41342f8fb75SBob Moore 	union acpi_operand_object *sub_package;
41442f8fb75SBob Moore 	union acpi_operand_object **sub_elements;
41542f8fb75SBob Moore 	acpi_status status;
41642f8fb75SBob Moore 	u32 expected_count;
41742f8fb75SBob Moore 	u32 i;
41842f8fb75SBob Moore 	u32 j;
41942f8fb75SBob Moore 
42042f8fb75SBob Moore 	/*
4210a16d12aSBob Moore 	 * Validate each subpackage in the parent Package
42242f8fb75SBob Moore 	 *
4230a16d12aSBob Moore 	 * NOTE: assumes list of subpackages contains no NULL elements.
42442f8fb75SBob Moore 	 * Any NULL elements should have been removed by earlier call
42542f8fb75SBob Moore 	 * to acpi_ns_remove_null_elements.
42642f8fb75SBob Moore 	 */
42742f8fb75SBob Moore 	for (i = 0; i < count; i++) {
42842f8fb75SBob Moore 		sub_package = *elements;
42942f8fb75SBob Moore 		sub_elements = sub_package->package.elements;
43029a241ccSBob Moore 		info->parent_package = sub_package;
43142f8fb75SBob Moore 
43242f8fb75SBob Moore 		/* Each sub-object must be of type Package */
43342f8fb75SBob Moore 
43429a241ccSBob Moore 		status = acpi_ns_check_object_type(info, &sub_package,
43542f8fb75SBob Moore 						   ACPI_RTYPE_PACKAGE, i);
43642f8fb75SBob Moore 		if (ACPI_FAILURE(status)) {
43742f8fb75SBob Moore 			return (status);
43842f8fb75SBob Moore 		}
43942f8fb75SBob Moore 
4400a16d12aSBob Moore 		/* Examine the different types of expected subpackages */
44142f8fb75SBob Moore 
44229a241ccSBob Moore 		info->parent_package = sub_package;
44342f8fb75SBob Moore 		switch (package->ret_info.type) {
44442f8fb75SBob Moore 		case ACPI_PTYPE2:
44542f8fb75SBob Moore 		case ACPI_PTYPE2_PKG_COUNT:
44642f8fb75SBob Moore 		case ACPI_PTYPE2_REV_FIXED:
44742f8fb75SBob Moore 
44842f8fb75SBob Moore 			/* Each subpackage has a fixed number of elements */
44942f8fb75SBob Moore 
45042f8fb75SBob Moore 			expected_count =
45142f8fb75SBob Moore 			    package->ret_info.count1 + package->ret_info.count2;
45242f8fb75SBob Moore 			if (sub_package->package.count < expected_count) {
45342f8fb75SBob Moore 				goto package_too_small;
45442f8fb75SBob Moore 			}
45542f8fb75SBob Moore 
45642f8fb75SBob Moore 			status =
45729a241ccSBob Moore 			    acpi_ns_check_package_elements(info, sub_elements,
45842f8fb75SBob Moore 							   package->ret_info.
45942f8fb75SBob Moore 							   object_type1,
46042f8fb75SBob Moore 							   package->ret_info.
46142f8fb75SBob Moore 							   count1,
46242f8fb75SBob Moore 							   package->ret_info.
46342f8fb75SBob Moore 							   object_type2,
46442f8fb75SBob Moore 							   package->ret_info.
46542f8fb75SBob Moore 							   count2, 0);
46642f8fb75SBob Moore 			if (ACPI_FAILURE(status)) {
46742f8fb75SBob Moore 				return (status);
46842f8fb75SBob Moore 			}
46942f8fb75SBob Moore 			break;
47042f8fb75SBob Moore 
47142f8fb75SBob Moore 		case ACPI_PTYPE2_FIX_VAR:
47242f8fb75SBob Moore 			/*
47342f8fb75SBob Moore 			 * Each subpackage has a fixed number of elements and an
47442f8fb75SBob Moore 			 * optional element
47542f8fb75SBob Moore 			 */
47642f8fb75SBob Moore 			expected_count =
47742f8fb75SBob Moore 			    package->ret_info.count1 + package->ret_info.count2;
47842f8fb75SBob Moore 			if (sub_package->package.count < expected_count) {
47942f8fb75SBob Moore 				goto package_too_small;
48042f8fb75SBob Moore 			}
48142f8fb75SBob Moore 
48242f8fb75SBob Moore 			status =
48329a241ccSBob Moore 			    acpi_ns_check_package_elements(info, sub_elements,
48442f8fb75SBob Moore 							   package->ret_info.
48542f8fb75SBob Moore 							   object_type1,
48642f8fb75SBob Moore 							   package->ret_info.
48742f8fb75SBob Moore 							   count1,
48842f8fb75SBob Moore 							   package->ret_info.
48942f8fb75SBob Moore 							   object_type2,
49042f8fb75SBob Moore 							   sub_package->package.
49142f8fb75SBob Moore 							   count -
49242f8fb75SBob Moore 							   package->ret_info.
49342f8fb75SBob Moore 							   count1, 0);
49442f8fb75SBob Moore 			if (ACPI_FAILURE(status)) {
49542f8fb75SBob Moore 				return (status);
49642f8fb75SBob Moore 			}
49742f8fb75SBob Moore 			break;
49842f8fb75SBob Moore 
499e34a7813SBob Moore 		case ACPI_PTYPE2_VAR_VAR:
500e34a7813SBob Moore 			/*
501e34a7813SBob Moore 			 * Each subpackage has a fixed or variable number of elements
502e34a7813SBob Moore 			 */
503e34a7813SBob Moore 			break;
504e34a7813SBob Moore 
50542f8fb75SBob Moore 		case ACPI_PTYPE2_FIXED:
50642f8fb75SBob Moore 
5070a16d12aSBob Moore 			/* Each subpackage has a fixed length */
50842f8fb75SBob Moore 
50942f8fb75SBob Moore 			expected_count = package->ret_info2.count;
51042f8fb75SBob Moore 			if (sub_package->package.count < expected_count) {
51142f8fb75SBob Moore 				goto package_too_small;
51242f8fb75SBob Moore 			}
51342f8fb75SBob Moore 
5140a16d12aSBob Moore 			/* Check the type of each subpackage element */
51542f8fb75SBob Moore 
51642f8fb75SBob Moore 			for (j = 0; j < expected_count; j++) {
51742f8fb75SBob Moore 				status =
51829a241ccSBob Moore 				    acpi_ns_check_object_type(info,
51942f8fb75SBob Moore 							      &sub_elements[j],
52042f8fb75SBob Moore 							      package->
52142f8fb75SBob Moore 							      ret_info2.
52242f8fb75SBob Moore 							      object_type[j],
52342f8fb75SBob Moore 							      j);
52442f8fb75SBob Moore 				if (ACPI_FAILURE(status)) {
52542f8fb75SBob Moore 					return (status);
52642f8fb75SBob Moore 				}
52742f8fb75SBob Moore 			}
52842f8fb75SBob Moore 			break;
52942f8fb75SBob Moore 
53042f8fb75SBob Moore 		case ACPI_PTYPE2_MIN:
53142f8fb75SBob Moore 
5320a16d12aSBob Moore 			/* Each subpackage has a variable but minimum length */
53342f8fb75SBob Moore 
53442f8fb75SBob Moore 			expected_count = package->ret_info.count1;
53542f8fb75SBob Moore 			if (sub_package->package.count < expected_count) {
53642f8fb75SBob Moore 				goto package_too_small;
53742f8fb75SBob Moore 			}
53842f8fb75SBob Moore 
5390a16d12aSBob Moore 			/* Check the type of each subpackage element */
54042f8fb75SBob Moore 
54142f8fb75SBob Moore 			status =
54229a241ccSBob Moore 			    acpi_ns_check_package_elements(info, sub_elements,
54342f8fb75SBob Moore 							   package->ret_info.
54442f8fb75SBob Moore 							   object_type1,
54542f8fb75SBob Moore 							   sub_package->package.
54642f8fb75SBob Moore 							   count, 0, 0, 0);
54742f8fb75SBob Moore 			if (ACPI_FAILURE(status)) {
54842f8fb75SBob Moore 				return (status);
54942f8fb75SBob Moore 			}
55042f8fb75SBob Moore 			break;
55142f8fb75SBob Moore 
55242f8fb75SBob Moore 		case ACPI_PTYPE2_COUNT:
55342f8fb75SBob Moore 			/*
55442f8fb75SBob Moore 			 * First element is the (Integer) count of elements, including
55542f8fb75SBob Moore 			 * the count field (the ACPI name is num_elements)
55642f8fb75SBob Moore 			 */
55729a241ccSBob Moore 			status = acpi_ns_check_object_type(info, sub_elements,
55842f8fb75SBob Moore 							   ACPI_RTYPE_INTEGER,
55942f8fb75SBob Moore 							   0);
56042f8fb75SBob Moore 			if (ACPI_FAILURE(status)) {
56142f8fb75SBob Moore 				return (status);
56242f8fb75SBob Moore 			}
56342f8fb75SBob Moore 
56442f8fb75SBob Moore 			/*
56542f8fb75SBob Moore 			 * Make sure package is large enough for the Count and is
56642f8fb75SBob Moore 			 * is as large as the minimum size
56742f8fb75SBob Moore 			 */
56842f8fb75SBob Moore 			expected_count = (u32)(*sub_elements)->integer.value;
56942f8fb75SBob Moore 			if (sub_package->package.count < expected_count) {
57042f8fb75SBob Moore 				goto package_too_small;
57142f8fb75SBob Moore 			}
57242f8fb75SBob Moore 			if (sub_package->package.count <
57342f8fb75SBob Moore 			    package->ret_info.count1) {
57442f8fb75SBob Moore 				expected_count = package->ret_info.count1;
57542f8fb75SBob Moore 				goto package_too_small;
57642f8fb75SBob Moore 			}
57742f8fb75SBob Moore 			if (expected_count == 0) {
57842f8fb75SBob Moore 				/*
57942f8fb75SBob Moore 				 * Either the num_entries element was originally zero or it was
58042f8fb75SBob Moore 				 * a NULL element and repaired to an Integer of value zero.
58142f8fb75SBob Moore 				 * In either case, repair it by setting num_entries to be the
58242f8fb75SBob Moore 				 * actual size of the subpackage.
58342f8fb75SBob Moore 				 */
58442f8fb75SBob Moore 				expected_count = sub_package->package.count;
58542f8fb75SBob Moore 				(*sub_elements)->integer.value = expected_count;
58642f8fb75SBob Moore 			}
58742f8fb75SBob Moore 
5880a16d12aSBob Moore 			/* Check the type of each subpackage element */
58942f8fb75SBob Moore 
59042f8fb75SBob Moore 			status =
59129a241ccSBob Moore 			    acpi_ns_check_package_elements(info,
59242f8fb75SBob Moore 							   (sub_elements + 1),
59342f8fb75SBob Moore 							   package->ret_info.
59442f8fb75SBob Moore 							   object_type1,
59542f8fb75SBob Moore 							   (expected_count - 1),
59642f8fb75SBob Moore 							   0, 0, 1);
59742f8fb75SBob Moore 			if (ACPI_FAILURE(status)) {
59842f8fb75SBob Moore 				return (status);
59942f8fb75SBob Moore 			}
60042f8fb75SBob Moore 			break;
60142f8fb75SBob Moore 
60242f8fb75SBob Moore 		default:	/* Should not get here, type was validated by caller */
60342f8fb75SBob Moore 
60442f8fb75SBob Moore 			return (AE_AML_INTERNAL);
60542f8fb75SBob Moore 		}
60642f8fb75SBob Moore 
60742f8fb75SBob Moore 		elements++;
60842f8fb75SBob Moore 	}
60942f8fb75SBob Moore 
61042f8fb75SBob Moore 	return (AE_OK);
61142f8fb75SBob Moore 
61242f8fb75SBob Moore package_too_small:
61342f8fb75SBob Moore 
6140a16d12aSBob Moore 	/* The subpackage count was smaller than required */
61542f8fb75SBob Moore 
61629a241ccSBob Moore 	ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags,
6170a16d12aSBob Moore 			      "Return SubPackage[%u] is too small - found %u elements, expected %u",
61842f8fb75SBob Moore 			      i, sub_package->package.count, expected_count));
61942f8fb75SBob Moore 
62042f8fb75SBob Moore 	return (AE_AML_OPERAND_VALUE);
62142f8fb75SBob Moore }
62242f8fb75SBob Moore 
62342f8fb75SBob Moore /*******************************************************************************
62442f8fb75SBob Moore  *
62542f8fb75SBob Moore  * FUNCTION:    acpi_ns_check_package_elements
62642f8fb75SBob Moore  *
62729a241ccSBob Moore  * PARAMETERS:  info            - Method execution information block
62842f8fb75SBob Moore  *              elements        - Pointer to the package elements array
62942f8fb75SBob Moore  *              type1           - Object type for first group
63042f8fb75SBob Moore  *              count1          - Count for first group
63142f8fb75SBob Moore  *              type2           - Object type for second group
63242f8fb75SBob Moore  *              count2          - Count for second group
63342f8fb75SBob Moore  *              start_index     - Start of the first group of elements
63442f8fb75SBob Moore  *
63542f8fb75SBob Moore  * RETURN:      Status
63642f8fb75SBob Moore  *
63742f8fb75SBob Moore  * DESCRIPTION: Check that all elements of a package are of the correct object
63842f8fb75SBob Moore  *              type. Supports up to two groups of different object types.
63942f8fb75SBob Moore  *
64042f8fb75SBob Moore  ******************************************************************************/
64142f8fb75SBob Moore 
64242f8fb75SBob Moore static acpi_status
64329a241ccSBob Moore acpi_ns_check_package_elements(struct acpi_evaluate_info *info,
64442f8fb75SBob Moore 			       union acpi_operand_object **elements,
64542f8fb75SBob Moore 			       u8 type1,
64642f8fb75SBob Moore 			       u32 count1,
64742f8fb75SBob Moore 			       u8 type2, u32 count2, u32 start_index)
64842f8fb75SBob Moore {
64942f8fb75SBob Moore 	union acpi_operand_object **this_element = elements;
65042f8fb75SBob Moore 	acpi_status status;
65142f8fb75SBob Moore 	u32 i;
65242f8fb75SBob Moore 
65342f8fb75SBob Moore 	/*
65442f8fb75SBob Moore 	 * Up to two groups of package elements are supported by the data
65542f8fb75SBob Moore 	 * structure. All elements in each group must be of the same type.
65642f8fb75SBob Moore 	 * The second group can have a count of zero.
65742f8fb75SBob Moore 	 */
65842f8fb75SBob Moore 	for (i = 0; i < count1; i++) {
65929a241ccSBob Moore 		status = acpi_ns_check_object_type(info, this_element,
66042f8fb75SBob Moore 						   type1, i + start_index);
66142f8fb75SBob Moore 		if (ACPI_FAILURE(status)) {
66242f8fb75SBob Moore 			return (status);
66342f8fb75SBob Moore 		}
66442f8fb75SBob Moore 		this_element++;
66542f8fb75SBob Moore 	}
66642f8fb75SBob Moore 
66742f8fb75SBob Moore 	for (i = 0; i < count2; i++) {
66829a241ccSBob Moore 		status = acpi_ns_check_object_type(info, this_element,
66942f8fb75SBob Moore 						   type2,
67042f8fb75SBob Moore 						   (i + count1 + start_index));
67142f8fb75SBob Moore 		if (ACPI_FAILURE(status)) {
67242f8fb75SBob Moore 			return (status);
67342f8fb75SBob Moore 		}
67442f8fb75SBob Moore 		this_element++;
67542f8fb75SBob Moore 	}
67642f8fb75SBob Moore 
67742f8fb75SBob Moore 	return (AE_OK);
67842f8fb75SBob Moore }
679