xref: /freebsd/sys/contrib/dev/acpica/components/namespace/nsprepkg.c (revision d9e22925e0cd52fc6b4e3fedf05367b3c6d401a1)
1 /******************************************************************************
2  *
3  * Module Name: nsprepkg - Validation of package objects for predefined names
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2013, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include <contrib/dev/acpica/include/acpi.h>
45 #include <contrib/dev/acpica/include/accommon.h>
46 #include <contrib/dev/acpica/include/acnamesp.h>
47 #include <contrib/dev/acpica/include/acpredef.h>
48 
49 
50 #define _COMPONENT          ACPI_NAMESPACE
51         ACPI_MODULE_NAME    ("nsprepkg")
52 
53 
54 /* Local prototypes */
55 
56 static ACPI_STATUS
57 AcpiNsCheckPackageList (
58     ACPI_EVALUATE_INFO          *Info,
59     const ACPI_PREDEFINED_INFO  *Package,
60     ACPI_OPERAND_OBJECT         **Elements,
61     UINT32                      Count);
62 
63 static ACPI_STATUS
64 AcpiNsCheckPackageElements (
65     ACPI_EVALUATE_INFO          *Info,
66     ACPI_OPERAND_OBJECT         **Elements,
67     UINT8                       Type1,
68     UINT32                      Count1,
69     UINT8                       Type2,
70     UINT32                      Count2,
71     UINT32                      StartIndex);
72 
73 
74 /*******************************************************************************
75  *
76  * FUNCTION:    AcpiNsCheckPackage
77  *
78  * PARAMETERS:  Info                - Method execution information block
79  *              ReturnObjectPtr     - Pointer to the object returned from the
80  *                                    evaluation of a method or object
81  *
82  * RETURN:      Status
83  *
84  * DESCRIPTION: Check a returned package object for the correct count and
85  *              correct type of all sub-objects.
86  *
87  ******************************************************************************/
88 
89 ACPI_STATUS
90 AcpiNsCheckPackage (
91     ACPI_EVALUATE_INFO          *Info,
92     ACPI_OPERAND_OBJECT         **ReturnObjectPtr)
93 {
94     ACPI_OPERAND_OBJECT         *ReturnObject = *ReturnObjectPtr;
95     const ACPI_PREDEFINED_INFO  *Package;
96     ACPI_OPERAND_OBJECT         **Elements;
97     ACPI_STATUS                 Status = AE_OK;
98     UINT32                      ExpectedCount;
99     UINT32                      Count;
100     UINT32                      i;
101 
102 
103     ACPI_FUNCTION_NAME (NsCheckPackage);
104 
105 
106     /* The package info for this name is in the next table entry */
107 
108     Package = Info->Predefined + 1;
109 
110     ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
111         "%s Validating return Package of Type %X, Count %X\n",
112         Info->FullPathname, Package->RetInfo.Type,
113         ReturnObject->Package.Count));
114 
115     /*
116      * For variable-length Packages, we can safely remove all embedded
117      * and trailing NULL package elements
118      */
119     AcpiNsRemoveNullElements (Info, Package->RetInfo.Type, ReturnObject);
120 
121     /* Extract package count and elements array */
122 
123     Elements = ReturnObject->Package.Elements;
124     Count = ReturnObject->Package.Count;
125 
126     /*
127      * Most packages must have at least one element. The only exception
128      * is the variable-length package (ACPI_PTYPE1_VAR).
129      */
130     if (!Count)
131     {
132         if (Package->RetInfo.Type == ACPI_PTYPE1_VAR)
133         {
134             return (AE_OK);
135         }
136 
137         ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
138             "Return Package has no elements (empty)"));
139 
140         return (AE_AML_OPERAND_VALUE);
141     }
142 
143     /*
144      * Decode the type of the expected package contents
145      *
146      * PTYPE1 packages contain no subpackages
147      * PTYPE2 packages contain sub-packages
148      */
149     switch (Package->RetInfo.Type)
150     {
151     case ACPI_PTYPE1_FIXED:
152 
153         /*
154          * The package count is fixed and there are no sub-packages
155          *
156          * If package is too small, exit.
157          * If package is larger than expected, issue warning but continue
158          */
159         ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2;
160         if (Count < ExpectedCount)
161         {
162             goto PackageTooSmall;
163         }
164         else if (Count > ExpectedCount)
165         {
166             ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
167                 "%s: Return Package is larger than needed - "
168                 "found %u, expected %u\n",
169                 Info->FullPathname, Count, ExpectedCount));
170         }
171 
172         /* Validate all elements of the returned package */
173 
174         Status = AcpiNsCheckPackageElements (Info, Elements,
175                     Package->RetInfo.ObjectType1, Package->RetInfo.Count1,
176                     Package->RetInfo.ObjectType2, Package->RetInfo.Count2, 0);
177         break;
178 
179 
180     case ACPI_PTYPE1_VAR:
181 
182         /*
183          * The package count is variable, there are no sub-packages, and all
184          * elements must be of the same type
185          */
186         for (i = 0; i < Count; i++)
187         {
188             Status = AcpiNsCheckObjectType (Info, Elements,
189                         Package->RetInfo.ObjectType1, i);
190             if (ACPI_FAILURE (Status))
191             {
192                 return (Status);
193             }
194             Elements++;
195         }
196         break;
197 
198 
199     case ACPI_PTYPE1_OPTION:
200 
201         /*
202          * The package count is variable, there are no sub-packages. There are
203          * a fixed number of required elements, and a variable number of
204          * optional elements.
205          *
206          * Check if package is at least as large as the minimum required
207          */
208         ExpectedCount = Package->RetInfo3.Count;
209         if (Count < ExpectedCount)
210         {
211             goto PackageTooSmall;
212         }
213 
214         /* Variable number of sub-objects */
215 
216         for (i = 0; i < Count; i++)
217         {
218             if (i < Package->RetInfo3.Count)
219             {
220                 /* These are the required package elements (0, 1, or 2) */
221 
222                 Status = AcpiNsCheckObjectType (Info, Elements,
223                             Package->RetInfo3.ObjectType[i], i);
224                 if (ACPI_FAILURE (Status))
225                 {
226                     return (Status);
227                 }
228             }
229             else
230             {
231                 /* These are the optional package elements */
232 
233                 Status = AcpiNsCheckObjectType (Info, Elements,
234                             Package->RetInfo3.TailObjectType, i);
235                 if (ACPI_FAILURE (Status))
236                 {
237                     return (Status);
238                 }
239             }
240             Elements++;
241         }
242         break;
243 
244 
245     case ACPI_PTYPE2_REV_FIXED:
246 
247         /* First element is the (Integer) revision */
248 
249         Status = AcpiNsCheckObjectType (Info, Elements,
250                     ACPI_RTYPE_INTEGER, 0);
251         if (ACPI_FAILURE (Status))
252         {
253             return (Status);
254         }
255 
256         Elements++;
257         Count--;
258 
259         /* Examine the sub-packages */
260 
261         Status = AcpiNsCheckPackageList (Info, Package, Elements, Count);
262         break;
263 
264 
265     case ACPI_PTYPE2_PKG_COUNT:
266 
267         /* First element is the (Integer) count of sub-packages to follow */
268 
269         Status = AcpiNsCheckObjectType (Info, Elements,
270                     ACPI_RTYPE_INTEGER, 0);
271         if (ACPI_FAILURE (Status))
272         {
273             return (Status);
274         }
275 
276         /*
277          * Count cannot be larger than the parent package length, but allow it
278          * to be smaller. The >= accounts for the Integer above.
279          */
280         ExpectedCount = (UINT32) (*Elements)->Integer.Value;
281         if (ExpectedCount >= Count)
282         {
283             goto PackageTooSmall;
284         }
285 
286         Count = ExpectedCount;
287         Elements++;
288 
289         /* Examine the sub-packages */
290 
291         Status = AcpiNsCheckPackageList (Info, Package, Elements, Count);
292         break;
293 
294 
295     case ACPI_PTYPE2:
296     case ACPI_PTYPE2_FIXED:
297     case ACPI_PTYPE2_MIN:
298     case ACPI_PTYPE2_COUNT:
299     case ACPI_PTYPE2_FIX_VAR:
300 
301         /*
302          * These types all return a single Package that consists of a
303          * variable number of sub-Packages.
304          *
305          * First, ensure that the first element is a sub-Package. If not,
306          * the BIOS may have incorrectly returned the object as a single
307          * package instead of a Package of Packages (a common error if
308          * there is only one entry). We may be able to repair this by
309          * wrapping the returned Package with a new outer Package.
310          */
311         if (*Elements && ((*Elements)->Common.Type != ACPI_TYPE_PACKAGE))
312         {
313             /* Create the new outer package and populate it */
314 
315             Status = AcpiNsWrapWithPackage (Info, ReturnObject, ReturnObjectPtr);
316             if (ACPI_FAILURE (Status))
317             {
318                 return (Status);
319             }
320 
321             /* Update locals to point to the new package (of 1 element) */
322 
323             ReturnObject = *ReturnObjectPtr;
324             Elements = ReturnObject->Package.Elements;
325             Count = 1;
326         }
327 
328         /* Examine the sub-packages */
329 
330         Status = AcpiNsCheckPackageList (Info, Package, Elements, Count);
331         break;
332 
333 
334     default:
335 
336         /* Should not get here if predefined info table is correct */
337 
338         ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
339             "Invalid internal return type in table entry: %X",
340             Package->RetInfo.Type));
341 
342         return (AE_AML_INTERNAL);
343     }
344 
345     return (Status);
346 
347 
348 PackageTooSmall:
349 
350     /* Error exit for the case with an incorrect package count */
351 
352     ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
353         "Return Package is too small - found %u elements, expected %u",
354         Count, ExpectedCount));
355 
356     return (AE_AML_OPERAND_VALUE);
357 }
358 
359 
360 /*******************************************************************************
361  *
362  * FUNCTION:    AcpiNsCheckPackageList
363  *
364  * PARAMETERS:  Info            - Method execution information block
365  *              Package         - Pointer to package-specific info for method
366  *              Elements        - Element list of parent package. All elements
367  *                                of this list should be of type Package.
368  *              Count           - Count of subpackages
369  *
370  * RETURN:      Status
371  *
372  * DESCRIPTION: Examine a list of subpackages
373  *
374  ******************************************************************************/
375 
376 static ACPI_STATUS
377 AcpiNsCheckPackageList (
378     ACPI_EVALUATE_INFO          *Info,
379     const ACPI_PREDEFINED_INFO  *Package,
380     ACPI_OPERAND_OBJECT         **Elements,
381     UINT32                      Count)
382 {
383     ACPI_OPERAND_OBJECT         *SubPackage;
384     ACPI_OPERAND_OBJECT         **SubElements;
385     ACPI_STATUS                 Status;
386     UINT32                      ExpectedCount;
387     UINT32                      i;
388     UINT32                      j;
389 
390 
391     /*
392      * Validate each sub-Package in the parent Package
393      *
394      * NOTE: assumes list of sub-packages contains no NULL elements.
395      * Any NULL elements should have been removed by earlier call
396      * to AcpiNsRemoveNullElements.
397      */
398     for (i = 0; i < Count; i++)
399     {
400         SubPackage = *Elements;
401         SubElements = SubPackage->Package.Elements;
402         Info->ParentPackage = SubPackage;
403 
404         /* Each sub-object must be of type Package */
405 
406         Status = AcpiNsCheckObjectType (Info, &SubPackage,
407                     ACPI_RTYPE_PACKAGE, i);
408         if (ACPI_FAILURE (Status))
409         {
410             return (Status);
411         }
412 
413         /* Examine the different types of expected sub-packages */
414 
415         Info->ParentPackage = SubPackage;
416         switch (Package->RetInfo.Type)
417         {
418         case ACPI_PTYPE2:
419         case ACPI_PTYPE2_PKG_COUNT:
420         case ACPI_PTYPE2_REV_FIXED:
421 
422             /* Each subpackage has a fixed number of elements */
423 
424             ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2;
425             if (SubPackage->Package.Count < ExpectedCount)
426             {
427                 goto PackageTooSmall;
428             }
429 
430             Status = AcpiNsCheckPackageElements (Info, SubElements,
431                         Package->RetInfo.ObjectType1,
432                         Package->RetInfo.Count1,
433                         Package->RetInfo.ObjectType2,
434                         Package->RetInfo.Count2, 0);
435             if (ACPI_FAILURE (Status))
436             {
437                 return (Status);
438             }
439             break;
440 
441 
442         case ACPI_PTYPE2_FIX_VAR:
443             /*
444              * Each subpackage has a fixed number of elements and an
445              * optional element
446              */
447             ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2;
448             if (SubPackage->Package.Count < ExpectedCount)
449             {
450                 goto PackageTooSmall;
451             }
452 
453             Status = AcpiNsCheckPackageElements (Info, SubElements,
454                         Package->RetInfo.ObjectType1,
455                         Package->RetInfo.Count1,
456                         Package->RetInfo.ObjectType2,
457                         SubPackage->Package.Count - Package->RetInfo.Count1, 0);
458             if (ACPI_FAILURE (Status))
459             {
460                 return (Status);
461             }
462             break;
463 
464 
465         case ACPI_PTYPE2_FIXED:
466 
467             /* Each sub-package has a fixed length */
468 
469             ExpectedCount = Package->RetInfo2.Count;
470             if (SubPackage->Package.Count < ExpectedCount)
471             {
472                 goto PackageTooSmall;
473             }
474 
475             /* Check the type of each sub-package element */
476 
477             for (j = 0; j < ExpectedCount; j++)
478             {
479                 Status = AcpiNsCheckObjectType (Info, &SubElements[j],
480                             Package->RetInfo2.ObjectType[j], j);
481                 if (ACPI_FAILURE (Status))
482                 {
483                     return (Status);
484                 }
485             }
486             break;
487 
488 
489         case ACPI_PTYPE2_MIN:
490 
491             /* Each sub-package has a variable but minimum length */
492 
493             ExpectedCount = Package->RetInfo.Count1;
494             if (SubPackage->Package.Count < ExpectedCount)
495             {
496                 goto PackageTooSmall;
497             }
498 
499             /* Check the type of each sub-package element */
500 
501             Status = AcpiNsCheckPackageElements (Info, SubElements,
502                         Package->RetInfo.ObjectType1,
503                         SubPackage->Package.Count, 0, 0, 0);
504             if (ACPI_FAILURE (Status))
505             {
506                 return (Status);
507             }
508             break;
509 
510 
511         case ACPI_PTYPE2_COUNT:
512 
513             /*
514              * First element is the (Integer) count of elements, including
515              * the count field (the ACPI name is NumElements)
516              */
517             Status = AcpiNsCheckObjectType (Info, SubElements,
518                         ACPI_RTYPE_INTEGER, 0);
519             if (ACPI_FAILURE (Status))
520             {
521                 return (Status);
522             }
523 
524             /*
525              * Make sure package is large enough for the Count and is
526              * is as large as the minimum size
527              */
528             ExpectedCount = (UINT32) (*SubElements)->Integer.Value;
529             if (SubPackage->Package.Count < ExpectedCount)
530             {
531                 goto PackageTooSmall;
532             }
533             if (SubPackage->Package.Count < Package->RetInfo.Count1)
534             {
535                 ExpectedCount = Package->RetInfo.Count1;
536                 goto PackageTooSmall;
537             }
538             if (ExpectedCount == 0)
539             {
540                 /*
541                  * Either the NumEntries element was originally zero or it was
542                  * a NULL element and repaired to an Integer of value zero.
543                  * In either case, repair it by setting NumEntries to be the
544                  * actual size of the subpackage.
545                  */
546                 ExpectedCount = SubPackage->Package.Count;
547                 (*SubElements)->Integer.Value = ExpectedCount;
548             }
549 
550             /* Check the type of each sub-package element */
551 
552             Status = AcpiNsCheckPackageElements (Info, (SubElements + 1),
553                         Package->RetInfo.ObjectType1,
554                         (ExpectedCount - 1), 0, 0, 1);
555             if (ACPI_FAILURE (Status))
556             {
557                 return (Status);
558             }
559             break;
560 
561 
562         default: /* Should not get here, type was validated by caller */
563 
564             return (AE_AML_INTERNAL);
565         }
566 
567         Elements++;
568     }
569 
570     return (AE_OK);
571 
572 
573 PackageTooSmall:
574 
575     /* The sub-package count was smaller than required */
576 
577     ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
578         "Return Sub-Package[%u] is too small - found %u elements, expected %u",
579         i, SubPackage->Package.Count, ExpectedCount));
580 
581     return (AE_AML_OPERAND_VALUE);
582 }
583 
584 
585 /*******************************************************************************
586  *
587  * FUNCTION:    AcpiNsCheckPackageElements
588  *
589  * PARAMETERS:  Info            - Method execution information block
590  *              Elements        - Pointer to the package elements array
591  *              Type1           - Object type for first group
592  *              Count1          - Count for first group
593  *              Type2           - Object type for second group
594  *              Count2          - Count for second group
595  *              StartIndex      - Start of the first group of elements
596  *
597  * RETURN:      Status
598  *
599  * DESCRIPTION: Check that all elements of a package are of the correct object
600  *              type. Supports up to two groups of different object types.
601  *
602  ******************************************************************************/
603 
604 static ACPI_STATUS
605 AcpiNsCheckPackageElements (
606     ACPI_EVALUATE_INFO          *Info,
607     ACPI_OPERAND_OBJECT         **Elements,
608     UINT8                       Type1,
609     UINT32                      Count1,
610     UINT8                       Type2,
611     UINT32                      Count2,
612     UINT32                      StartIndex)
613 {
614     ACPI_OPERAND_OBJECT         **ThisElement = Elements;
615     ACPI_STATUS                 Status;
616     UINT32                      i;
617 
618 
619     /*
620      * Up to two groups of package elements are supported by the data
621      * structure. All elements in each group must be of the same type.
622      * The second group can have a count of zero.
623      */
624     for (i = 0; i < Count1; i++)
625     {
626         Status = AcpiNsCheckObjectType (Info, ThisElement,
627                     Type1, i + StartIndex);
628         if (ACPI_FAILURE (Status))
629         {
630             return (Status);
631         }
632         ThisElement++;
633     }
634 
635     for (i = 0; i < Count2; i++)
636     {
637         Status = AcpiNsCheckObjectType (Info, ThisElement,
638                     Type2, (i + Count1 + StartIndex));
639         if (ACPI_FAILURE (Status))
640         {
641             return (Status);
642         }
643         ThisElement++;
644     }
645 
646     return (AE_OK);
647 }
648