xref: /openbmc/linux/drivers/acpi/acpica/nsprepkg.c (revision 7c7e33b7)
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
3  *
4  * Module Name: nsprepkg - Validation of package objects for predefined names
5  *
6  * Copyright (C) 2000 - 2023, Intel Corp.
7  *
8  *****************************************************************************/
9 
10 #include <acpi/acpi.h>
11 #include "accommon.h"
12 #include "acnamesp.h"
13 #include "acpredef.h"
14 
15 #define _COMPONENT          ACPI_NAMESPACE
16 ACPI_MODULE_NAME("nsprepkg")
17 
18 /* Local prototypes */
19 static acpi_status
20 acpi_ns_check_package_list(struct acpi_evaluate_info *info,
21 			   const union acpi_predefined_info *package,
22 			   union acpi_operand_object **elements, u32 count);
23 
24 static acpi_status
25 acpi_ns_check_package_elements(struct acpi_evaluate_info *info,
26 			       union acpi_operand_object **elements,
27 			       u8 type1,
28 			       u32 count1,
29 			       u8 type2, u32 count2, u32 start_index);
30 
31 static acpi_status
32 acpi_ns_custom_package(struct acpi_evaluate_info *info,
33 		       union acpi_operand_object **elements, u32 count);
34 
35 /*******************************************************************************
36  *
37  * FUNCTION:    acpi_ns_check_package
38  *
39  * PARAMETERS:  info                - Method execution information block
40  *              return_object_ptr   - Pointer to the object returned from the
41  *                                    evaluation of a method or object
42  *
43  * RETURN:      Status
44  *
45  * DESCRIPTION: Check a returned package object for the correct count and
46  *              correct type of all sub-objects.
47  *
48  ******************************************************************************/
49 
50 acpi_status
51 acpi_ns_check_package(struct acpi_evaluate_info *info,
52 		      union acpi_operand_object **return_object_ptr)
53 {
54 	union acpi_operand_object *return_object = *return_object_ptr;
55 	const union acpi_predefined_info *package;
56 	union acpi_operand_object **elements;
57 	acpi_status status = AE_OK;
58 	u32 expected_count;
59 	u32 count;
60 	u32 i;
61 
62 	ACPI_FUNCTION_TRACE(ns_check_package);
63 
64 	/* The package info for this name is in the next table entry */
65 
66 	package = info->predefined + 1;
67 
68 	ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
69 			  "%s Validating return Package of Type %X, Count %X\n",
70 			  info->full_pathname, package->ret_info.type,
71 			  return_object->package.count));
72 
73 	/*
74 	 * For variable-length Packages, we can safely remove all embedded
75 	 * and trailing NULL package elements
76 	 */
77 	acpi_ns_remove_null_elements(info, package->ret_info.type,
78 				     return_object);
79 
80 	/* Extract package count and elements array */
81 
82 	elements = return_object->package.elements;
83 	count = return_object->package.count;
84 
85 	/*
86 	 * Most packages must have at least one element. The only exception
87 	 * is the variable-length package (ACPI_PTYPE1_VAR).
88 	 */
89 	if (!count) {
90 		if (package->ret_info.type == ACPI_PTYPE1_VAR) {
91 			return_ACPI_STATUS(AE_OK);
92 		}
93 
94 		ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
95 				      info->node_flags,
96 				      "Return Package has no elements (empty)"));
97 
98 		return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
99 	}
100 
101 	/*
102 	 * Decode the type of the expected package contents
103 	 *
104 	 * PTYPE1 packages contain no subpackages
105 	 * PTYPE2 packages contain subpackages
106 	 */
107 	switch (package->ret_info.type) {
108 	case ACPI_PTYPE_CUSTOM:
109 
110 		status = acpi_ns_custom_package(info, elements, count);
111 		break;
112 
113 	case ACPI_PTYPE1_FIXED:
114 		/*
115 		 * The package count is fixed and there are no subpackages
116 		 *
117 		 * If package is too small, exit.
118 		 * If package is larger than expected, issue warning but continue
119 		 */
120 		expected_count =
121 		    package->ret_info.count1 + package->ret_info.count2;
122 		if (count < expected_count) {
123 			goto package_too_small;
124 		} else if (count > expected_count) {
125 			ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
126 					  "%s: Return Package is larger than needed - "
127 					  "found %u, expected %u\n",
128 					  info->full_pathname, count,
129 					  expected_count));
130 		}
131 
132 		/* Validate all elements of the returned package */
133 
134 		status = acpi_ns_check_package_elements(info, elements,
135 							package->ret_info.
136 							object_type1,
137 							package->ret_info.
138 							count1,
139 							package->ret_info.
140 							object_type2,
141 							package->ret_info.
142 							count2, 0);
143 		break;
144 
145 	case ACPI_PTYPE1_VAR:
146 		/*
147 		 * The package count is variable, there are no subpackages, and all
148 		 * elements must be of the same type
149 		 */
150 		for (i = 0; i < count; i++) {
151 			status = acpi_ns_check_object_type(info, elements,
152 							   package->ret_info.
153 							   object_type1, i);
154 			if (ACPI_FAILURE(status)) {
155 				return_ACPI_STATUS(status);
156 			}
157 
158 			elements++;
159 		}
160 		break;
161 
162 	case ACPI_PTYPE1_OPTION:
163 		/*
164 		 * The package count is variable, there are no subpackages. There are
165 		 * a fixed number of required elements, and a variable number of
166 		 * optional elements.
167 		 *
168 		 * Check if package is at least as large as the minimum required
169 		 */
170 		expected_count = package->ret_info3.count;
171 		if (count < expected_count) {
172 			goto package_too_small;
173 		}
174 
175 		/* Variable number of sub-objects */
176 
177 		for (i = 0; i < count; i++) {
178 			if (i < package->ret_info3.count) {
179 
180 				/* These are the required package elements (0, 1, or 2) */
181 
182 				status =
183 				    acpi_ns_check_object_type(info, elements,
184 							      package->
185 							      ret_info3.
186 							      object_type[i],
187 							      i);
188 				if (ACPI_FAILURE(status)) {
189 					return_ACPI_STATUS(status);
190 				}
191 			} else {
192 				/* These are the optional package elements */
193 
194 				status =
195 				    acpi_ns_check_object_type(info, elements,
196 							      package->
197 							      ret_info3.
198 							      tail_object_type,
199 							      i);
200 				if (ACPI_FAILURE(status)) {
201 					return_ACPI_STATUS(status);
202 				}
203 			}
204 
205 			elements++;
206 		}
207 		break;
208 
209 	case ACPI_PTYPE2_REV_FIXED:
210 
211 		/* First element is the (Integer) revision */
212 
213 		status =
214 		    acpi_ns_check_object_type(info, elements,
215 					      ACPI_RTYPE_INTEGER, 0);
216 		if (ACPI_FAILURE(status)) {
217 			return_ACPI_STATUS(status);
218 		}
219 
220 		elements++;
221 		count--;
222 
223 		/* Examine the subpackages */
224 
225 		status =
226 		    acpi_ns_check_package_list(info, package, elements, count);
227 		break;
228 
229 	case ACPI_PTYPE2_PKG_COUNT:
230 
231 		/* First element is the (Integer) count of subpackages to follow */
232 
233 		status =
234 		    acpi_ns_check_object_type(info, elements,
235 					      ACPI_RTYPE_INTEGER, 0);
236 		if (ACPI_FAILURE(status)) {
237 			return_ACPI_STATUS(status);
238 		}
239 
240 		/*
241 		 * Count cannot be larger than the parent package length, but allow it
242 		 * to be smaller. The >= accounts for the Integer above.
243 		 */
244 		expected_count = (u32)(*elements)->integer.value;
245 		if (expected_count >= count) {
246 			goto package_too_small;
247 		}
248 
249 		count = expected_count;
250 		elements++;
251 
252 		/* Examine the subpackages */
253 
254 		status =
255 		    acpi_ns_check_package_list(info, package, elements, count);
256 		break;
257 
258 	case ACPI_PTYPE2:
259 	case ACPI_PTYPE2_FIXED:
260 	case ACPI_PTYPE2_MIN:
261 	case ACPI_PTYPE2_COUNT:
262 	case ACPI_PTYPE2_FIX_VAR:
263 		/*
264 		 * These types all return a single Package that consists of a
265 		 * variable number of subpackages.
266 		 *
267 		 * First, ensure that the first element is a subpackage. If not,
268 		 * the BIOS may have incorrectly returned the object as a single
269 		 * package instead of a Package of Packages (a common error if
270 		 * there is only one entry). We may be able to repair this by
271 		 * wrapping the returned Package with a new outer Package.
272 		 */
273 		if (*elements
274 		    && ((*elements)->common.type != ACPI_TYPE_PACKAGE)) {
275 
276 			/* Create the new outer package and populate it */
277 
278 			status =
279 			    acpi_ns_wrap_with_package(info, return_object,
280 						      return_object_ptr);
281 			if (ACPI_FAILURE(status)) {
282 				return_ACPI_STATUS(status);
283 			}
284 
285 			/* Update locals to point to the new package (of 1 element) */
286 
287 			return_object = *return_object_ptr;
288 			elements = return_object->package.elements;
289 			count = 1;
290 		}
291 
292 		/* Examine the subpackages */
293 
294 		status =
295 		    acpi_ns_check_package_list(info, package, elements, count);
296 		break;
297 
298 	case ACPI_PTYPE2_VAR_VAR:
299 		/*
300 		 * Returns a variable list of packages, each with a variable list
301 		 * of objects.
302 		 */
303 		break;
304 
305 	case ACPI_PTYPE2_UUID_PAIR:
306 
307 		/* The package must contain pairs of (UUID + type) */
308 
309 		if (count & 1) {
310 			expected_count = count + 1;
311 			goto package_too_small;
312 		}
313 
314 		while (count > 0) {
315 			status = acpi_ns_check_object_type(info, elements,
316 							   package->ret_info.
317 							   object_type1, 0);
318 			if (ACPI_FAILURE(status)) {
319 				return_ACPI_STATUS(status);
320 			}
321 
322 			/* Validate length of the UUID buffer */
323 
324 			if ((*elements)->buffer.length != 16) {
325 				ACPI_WARN_PREDEFINED((AE_INFO,
326 						      info->full_pathname,
327 						      info->node_flags,
328 						      "Invalid length for UUID Buffer"));
329 				return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
330 			}
331 
332 			status = acpi_ns_check_object_type(info, elements + 1,
333 							   package->ret_info.
334 							   object_type2, 0);
335 			if (ACPI_FAILURE(status)) {
336 				return_ACPI_STATUS(status);
337 			}
338 
339 			elements += 2;
340 			count -= 2;
341 		}
342 		break;
343 
344 	default:
345 
346 		/* Should not get here if predefined info table is correct */
347 
348 		ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
349 				      info->node_flags,
350 				      "Invalid internal return type in table entry: %X",
351 				      package->ret_info.type));
352 
353 		return_ACPI_STATUS(AE_AML_INTERNAL);
354 	}
355 
356 	return_ACPI_STATUS(status);
357 
358 package_too_small:
359 
360 	/* Error exit for the case with an incorrect package count */
361 
362 	ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags,
363 			      "Return Package is too small - found %u elements, expected %u",
364 			      count, expected_count));
365 
366 	return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
367 }
368 
369 /*******************************************************************************
370  *
371  * FUNCTION:    acpi_ns_check_package_list
372  *
373  * PARAMETERS:  info            - Method execution information block
374  *              package         - Pointer to package-specific info for method
375  *              elements        - Element list of parent package. All elements
376  *                                of this list should be of type Package.
377  *              count           - Count of subpackages
378  *
379  * RETURN:      Status
380  *
381  * DESCRIPTION: Examine a list of subpackages
382  *
383  ******************************************************************************/
384 
385 static acpi_status
386 acpi_ns_check_package_list(struct acpi_evaluate_info *info,
387 			   const union acpi_predefined_info *package,
388 			   union acpi_operand_object **elements, u32 count)
389 {
390 	union acpi_operand_object *sub_package;
391 	union acpi_operand_object **sub_elements;
392 	acpi_status status;
393 	u32 expected_count;
394 	u32 i;
395 	u32 j;
396 
397 	/*
398 	 * Validate each subpackage in the parent Package
399 	 *
400 	 * NOTE: assumes list of subpackages contains no NULL elements.
401 	 * Any NULL elements should have been removed by earlier call
402 	 * to acpi_ns_remove_null_elements.
403 	 */
404 	for (i = 0; i < count; i++) {
405 		sub_package = *elements;
406 		sub_elements = sub_package->package.elements;
407 		info->parent_package = sub_package;
408 
409 		/* Each sub-object must be of type Package */
410 
411 		status = acpi_ns_check_object_type(info, &sub_package,
412 						   ACPI_RTYPE_PACKAGE, i);
413 		if (ACPI_FAILURE(status)) {
414 			return (status);
415 		}
416 
417 		/* Examine the different types of expected subpackages */
418 
419 		info->parent_package = sub_package;
420 		switch (package->ret_info.type) {
421 		case ACPI_PTYPE2:
422 		case ACPI_PTYPE2_PKG_COUNT:
423 		case ACPI_PTYPE2_REV_FIXED:
424 
425 			/* Each subpackage has a fixed number of elements */
426 
427 			expected_count =
428 			    package->ret_info.count1 + package->ret_info.count2;
429 			if (sub_package->package.count < expected_count) {
430 				goto package_too_small;
431 			}
432 
433 			status =
434 			    acpi_ns_check_package_elements(info, sub_elements,
435 							   package->ret_info.
436 							   object_type1,
437 							   package->ret_info.
438 							   count1,
439 							   package->ret_info.
440 							   object_type2,
441 							   package->ret_info.
442 							   count2, 0);
443 			if (ACPI_FAILURE(status)) {
444 				return (status);
445 			}
446 			break;
447 
448 		case ACPI_PTYPE2_FIX_VAR:
449 			/*
450 			 * Each subpackage has a fixed number of elements and an
451 			 * optional element
452 			 */
453 			expected_count =
454 			    package->ret_info.count1 + package->ret_info.count2;
455 			if (sub_package->package.count < expected_count) {
456 				goto package_too_small;
457 			}
458 
459 			status =
460 			    acpi_ns_check_package_elements(info, sub_elements,
461 							   package->ret_info.
462 							   object_type1,
463 							   package->ret_info.
464 							   count1,
465 							   package->ret_info.
466 							   object_type2,
467 							   sub_package->package.
468 							   count -
469 							   package->ret_info.
470 							   count1, 0);
471 			if (ACPI_FAILURE(status)) {
472 				return (status);
473 			}
474 			break;
475 
476 		case ACPI_PTYPE2_VAR_VAR:
477 			/*
478 			 * Each subpackage has a fixed or variable number of elements
479 			 */
480 			break;
481 
482 		case ACPI_PTYPE2_FIXED:
483 
484 			/* Each subpackage has a fixed length */
485 
486 			expected_count = package->ret_info2.count;
487 			if (sub_package->package.count < expected_count) {
488 				goto package_too_small;
489 			}
490 
491 			/* Check the type of each subpackage element */
492 
493 			for (j = 0; j < expected_count; j++) {
494 				status =
495 				    acpi_ns_check_object_type(info,
496 							      &sub_elements[j],
497 							      package->
498 							      ret_info2.
499 							      object_type[j],
500 							      j);
501 				if (ACPI_FAILURE(status)) {
502 					return (status);
503 				}
504 			}
505 			break;
506 
507 		case ACPI_PTYPE2_MIN:
508 
509 			/* Each subpackage has a variable but minimum length */
510 
511 			expected_count = package->ret_info.count1;
512 			if (sub_package->package.count < expected_count) {
513 				goto package_too_small;
514 			}
515 
516 			/* Check the type of each subpackage element */
517 
518 			status =
519 			    acpi_ns_check_package_elements(info, sub_elements,
520 							   package->ret_info.
521 							   object_type1,
522 							   sub_package->package.
523 							   count, 0, 0, 0);
524 			if (ACPI_FAILURE(status)) {
525 				return (status);
526 			}
527 			break;
528 
529 		case ACPI_PTYPE2_COUNT:
530 			/*
531 			 * First element is the (Integer) count of elements, including
532 			 * the count field (the ACPI name is num_elements)
533 			 */
534 			status = acpi_ns_check_object_type(info, sub_elements,
535 							   ACPI_RTYPE_INTEGER,
536 							   0);
537 			if (ACPI_FAILURE(status)) {
538 				return (status);
539 			}
540 
541 			/*
542 			 * Make sure package is large enough for the Count and is
543 			 * is as large as the minimum size
544 			 */
545 			expected_count = (u32)(*sub_elements)->integer.value;
546 			if (sub_package->package.count < expected_count) {
547 				goto package_too_small;
548 			}
549 
550 			if (sub_package->package.count <
551 			    package->ret_info.count1) {
552 				expected_count = package->ret_info.count1;
553 				goto package_too_small;
554 			}
555 
556 			if (expected_count == 0) {
557 				/*
558 				 * Either the num_entries element was originally zero or it was
559 				 * a NULL element and repaired to an Integer of value zero.
560 				 * In either case, repair it by setting num_entries to be the
561 				 * actual size of the subpackage.
562 				 */
563 				expected_count = sub_package->package.count;
564 				(*sub_elements)->integer.value = expected_count;
565 			}
566 
567 			/* Check the type of each subpackage element */
568 
569 			status =
570 			    acpi_ns_check_package_elements(info,
571 							   (sub_elements + 1),
572 							   package->ret_info.
573 							   object_type1,
574 							   (expected_count - 1),
575 							   0, 0, 1);
576 			if (ACPI_FAILURE(status)) {
577 				return (status);
578 			}
579 			break;
580 
581 		default:	/* Should not get here, type was validated by caller */
582 
583 			ACPI_ERROR((AE_INFO, "Invalid Package type: %X",
584 				    package->ret_info.type));
585 			return (AE_AML_INTERNAL);
586 		}
587 
588 		elements++;
589 	}
590 
591 	return (AE_OK);
592 
593 package_too_small:
594 
595 	/* The subpackage count was smaller than required */
596 
597 	ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags,
598 			      "Return SubPackage[%u] is too small - found %u elements, expected %u",
599 			      i, sub_package->package.count, expected_count));
600 
601 	return (AE_AML_OPERAND_VALUE);
602 }
603 
604 /*******************************************************************************
605  *
606  * FUNCTION:    acpi_ns_custom_package
607  *
608  * PARAMETERS:  info                - Method execution information block
609  *              elements            - Pointer to the package elements array
610  *              count               - Element count for the package
611  *
612  * RETURN:      Status
613  *
614  * DESCRIPTION: Check a returned package object for the correct count and
615  *              correct type of all sub-objects.
616  *
617  * NOTE: Currently used for the _BIX method only. When needed for two or more
618  * methods, probably a detect/dispatch mechanism will be required.
619  *
620  ******************************************************************************/
621 
622 static acpi_status
623 acpi_ns_custom_package(struct acpi_evaluate_info *info,
624 		       union acpi_operand_object **elements, u32 count)
625 {
626 	u32 expected_count;
627 	u32 version;
628 	acpi_status status = AE_OK;
629 
630 	ACPI_FUNCTION_NAME(ns_custom_package);
631 
632 	/* Get version number, must be Integer */
633 
634 	if ((*elements)->common.type != ACPI_TYPE_INTEGER) {
635 		ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
636 				      info->node_flags,
637 				      "Return Package has invalid object type for version number"));
638 		return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
639 	}
640 
641 	version = (u32)(*elements)->integer.value;
642 	expected_count = 21;	/* Version 1 */
643 
644 	if (version == 0) {
645 		expected_count = 20;	/* Version 0 */
646 	}
647 
648 	if (count < expected_count) {
649 		ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
650 				      info->node_flags,
651 				      "Return Package is too small - found %u elements, expected %u",
652 				      count, expected_count));
653 		return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
654 	} else if (count > expected_count) {
655 		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
656 				  "%s: Return Package is larger than needed - "
657 				  "found %u, expected %u\n",
658 				  info->full_pathname, count, expected_count));
659 	}
660 
661 	/* Validate all elements of the returned package */
662 
663 	status = acpi_ns_check_package_elements(info, elements,
664 						ACPI_RTYPE_INTEGER, 16,
665 						ACPI_RTYPE_STRING, 4, 0);
666 	if (ACPI_FAILURE(status)) {
667 		return_ACPI_STATUS(status);
668 	}
669 
670 	/* Version 1 has a single trailing integer */
671 
672 	if (version > 0) {
673 		status = acpi_ns_check_package_elements(info, elements + 20,
674 							ACPI_RTYPE_INTEGER, 1,
675 							0, 0, 20);
676 	}
677 
678 	return_ACPI_STATUS(status);
679 }
680 
681 /*******************************************************************************
682  *
683  * FUNCTION:    acpi_ns_check_package_elements
684  *
685  * PARAMETERS:  info            - Method execution information block
686  *              elements        - Pointer to the package elements array
687  *              type1           - Object type for first group
688  *              count1          - Count for first group
689  *              type2           - Object type for second group
690  *              count2          - Count for second group
691  *              start_index     - Start of the first group of elements
692  *
693  * RETURN:      Status
694  *
695  * DESCRIPTION: Check that all elements of a package are of the correct object
696  *              type. Supports up to two groups of different object types.
697  *
698  ******************************************************************************/
699 
700 static acpi_status
701 acpi_ns_check_package_elements(struct acpi_evaluate_info *info,
702 			       union acpi_operand_object **elements,
703 			       u8 type1,
704 			       u32 count1,
705 			       u8 type2, u32 count2, u32 start_index)
706 {
707 	union acpi_operand_object **this_element = elements;
708 	acpi_status status;
709 	u32 i;
710 
711 	ACPI_FUNCTION_TRACE(ns_check_package_elements);
712 
713 	/*
714 	 * Up to two groups of package elements are supported by the data
715 	 * structure. All elements in each group must be of the same type.
716 	 * The second group can have a count of zero.
717 	 */
718 	for (i = 0; i < count1; i++) {
719 		status = acpi_ns_check_object_type(info, this_element,
720 						   type1, i + start_index);
721 		if (ACPI_FAILURE(status)) {
722 			return_ACPI_STATUS(status);
723 		}
724 
725 		this_element++;
726 	}
727 
728 	for (i = 0; i < count2; i++) {
729 		status = acpi_ns_check_object_type(info, this_element,
730 						   type2,
731 						   (i + count1 + start_index));
732 		if (ACPI_FAILURE(status)) {
733 			return_ACPI_STATUS(status);
734 		}
735 
736 		this_element++;
737 	}
738 
739 	return_ACPI_STATUS(AE_OK);
740 }
741