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
16ACPI_MODULE_NAME("nsprepkg")
17
18/* Local prototypes */
19static acpi_status
20acpi_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
24static acpi_status
25acpi_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
31static acpi_status
32acpi_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
50acpi_status
51acpi_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_type: package->ret_info.type,
78 obj_desc: 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 type1: package->ret_info.
136 object_type1,
137 count1: package->ret_info.
138 count1,
139 type2: package->ret_info.
140 object_type2,
141 count2: package->ret_info.
142 count2, start_index: 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, return_object_ptr: elements,
152 expected_btypes: package->ret_info.
153 object_type1, package_index: 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, return_object_ptr: elements,
184 expected_btypes: package->
185 ret_info3.
186 object_type[i],
187 package_index: 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, return_object_ptr: elements,
196 expected_btypes: package->
197 ret_info3.
198 tail_object_type,
199 package_index: 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, return_object_ptr: elements,
215 ACPI_RTYPE_INTEGER, package_index: 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, return_object_ptr: elements,
235 ACPI_RTYPE_INTEGER, package_index: 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, original_object: return_object,
280 obj_desc_ptr: 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, return_object_ptr: elements,
316 expected_btypes: package->ret_info.
317 object_type1, package_index: 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, return_object_ptr: elements + 1,
333 expected_btypes: package->ret_info.
334 object_type2, package_index: 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
358package_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
385static acpi_status
386acpi_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, return_object_ptr: &sub_package,
412 ACPI_RTYPE_PACKAGE, package_index: 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, elements: sub_elements,
435 type1: package->ret_info.
436 object_type1,
437 count1: package->ret_info.
438 count1,
439 type2: package->ret_info.
440 object_type2,
441 count2: package->ret_info.
442 count2, start_index: 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, elements: sub_elements,
461 type1: package->ret_info.
462 object_type1,
463 count1: package->ret_info.
464 count1,
465 type2: package->ret_info.
466 object_type2,
467 count2: sub_package->package.
468 count -
469 package->ret_info.
470 count1, start_index: 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 return_object_ptr: &sub_elements[j],
497 expected_btypes: package->
498 ret_info2.
499 object_type[j],
500 package_index: 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, elements: sub_elements,
520 type1: package->ret_info.
521 object_type1,
522 count1: sub_package->package.
523 count, type2: 0, count2: 0, start_index: 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, return_object_ptr: sub_elements,
535 ACPI_RTYPE_INTEGER,
536 package_index: 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 elements: (sub_elements + 1),
572 type1: package->ret_info.
573 object_type1,
574 count1: (expected_count - 1),
575 type2: 0, count2: 0, start_index: 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
593package_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
622static acpi_status
623acpi_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, count1: 16,
665 ACPI_RTYPE_STRING, count2: 4, start_index: 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: elements + 20,
674 ACPI_RTYPE_INTEGER, count1: 1,
675 type2: 0, count2: 0, start_index: 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
700static acpi_status
701acpi_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, return_object_ptr: this_element,
720 expected_btypes: type1, package_index: 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, return_object_ptr: this_element,
730 expected_btypes: type2,
731 package_index: (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

source code of linux/drivers/acpi/acpica/nsprepkg.c