xref: /dflybsd-src/sys/contrib/dev/acpica/source/components/namespace/nsprepkg.c (revision 2ffe9f16c64a590bc6653e0284f95075c1319abb)
1 /******************************************************************************
2  *
3  * Module Name: nsprepkg - Validation of package objects for predefined names
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, 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 "acpi.h"
45 #include "accommon.h"
46 #include "acnamesp.h"
47 #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 subpackages
148      */
149     switch (Package->RetInfo.Type)
150     {
151     case ACPI_PTYPE1_FIXED:
152         /*
153          * The package count is fixed and there are no subpackages
154          *
155          * If package is too small, exit.
156          * If package is larger than expected, issue warning but continue
157          */
158         ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2;
159         if (Count < ExpectedCount)
160         {
161             goto PackageTooSmall;
162         }
163         else if (Count > ExpectedCount)
164         {
165             ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
166                 "%s: Return Package is larger than needed - "
167                 "found %u, expected %u\n",
168                 Info->FullPathname, Count, ExpectedCount));
169         }
170 
171         /* Validate all elements of the returned package */
172 
173         Status = AcpiNsCheckPackageElements (Info, Elements,
174             Package->RetInfo.ObjectType1, Package->RetInfo.Count1,
175             Package->RetInfo.ObjectType2, Package->RetInfo.Count2, 0);
176         break;
177 
178     case ACPI_PTYPE1_VAR:
179         /*
180          * The package count is variable, there are no subpackages, and all
181          * elements must be of the same type
182          */
183         for (i = 0; i < Count; i++)
184         {
185             Status = AcpiNsCheckObjectType (Info, Elements,
186                 Package->RetInfo.ObjectType1, i);
187             if (ACPI_FAILURE (Status))
188             {
189                 return (Status);
190             }
191 
192             Elements++;
193         }
194         break;
195 
196     case ACPI_PTYPE1_OPTION:
197         /*
198          * The package count is variable, there are no subpackages. There are
199          * a fixed number of required elements, and a variable number of
200          * optional elements.
201          *
202          * Check if package is at least as large as the minimum required
203          */
204         ExpectedCount = Package->RetInfo3.Count;
205         if (Count < ExpectedCount)
206         {
207             goto PackageTooSmall;
208         }
209 
210         /* Variable number of sub-objects */
211 
212         for (i = 0; i < Count; i++)
213         {
214             if (i < Package->RetInfo3.Count)
215             {
216                 /* These are the required package elements (0, 1, or 2) */
217 
218                 Status = AcpiNsCheckObjectType (Info, Elements,
219                     Package->RetInfo3.ObjectType[i], i);
220                 if (ACPI_FAILURE (Status))
221                 {
222                     return (Status);
223                 }
224             }
225             else
226             {
227                 /* These are the optional package elements */
228 
229                 Status = AcpiNsCheckObjectType (Info, Elements,
230                     Package->RetInfo3.TailObjectType, i);
231                 if (ACPI_FAILURE (Status))
232                 {
233                     return (Status);
234                 }
235             }
236 
237             Elements++;
238         }
239         break;
240 
241     case ACPI_PTYPE2_REV_FIXED:
242 
243         /* First element is the (Integer) revision */
244 
245         Status = AcpiNsCheckObjectType (
246             Info, Elements, ACPI_RTYPE_INTEGER, 0);
247         if (ACPI_FAILURE (Status))
248         {
249             return (Status);
250         }
251 
252         Elements++;
253         Count--;
254 
255         /* Examine the subpackages */
256 
257         Status = AcpiNsCheckPackageList (Info, Package, Elements, Count);
258         break;
259 
260     case ACPI_PTYPE2_PKG_COUNT:
261 
262         /* First element is the (Integer) count of subpackages to follow */
263 
264         Status = AcpiNsCheckObjectType (
265             Info, Elements, ACPI_RTYPE_INTEGER, 0);
266         if (ACPI_FAILURE (Status))
267         {
268             return (Status);
269         }
270 
271         /*
272          * Count cannot be larger than the parent package length, but allow it
273          * to be smaller. The >= accounts for the Integer above.
274          */
275         ExpectedCount = (UINT32) (*Elements)->Integer.Value;
276         if (ExpectedCount >= Count)
277         {
278             goto PackageTooSmall;
279         }
280 
281         Count = ExpectedCount;
282         Elements++;
283 
284         /* Examine the subpackages */
285 
286         Status = AcpiNsCheckPackageList (Info, Package, Elements, Count);
287         break;
288 
289     case ACPI_PTYPE2:
290     case ACPI_PTYPE2_FIXED:
291     case ACPI_PTYPE2_MIN:
292     case ACPI_PTYPE2_COUNT:
293     case ACPI_PTYPE2_FIX_VAR:
294         /*
295          * These types all return a single Package that consists of a
296          * variable number of subpackages.
297          *
298          * First, ensure that the first element is a subpackage. If not,
299          * the BIOS may have incorrectly returned the object as a single
300          * package instead of a Package of Packages (a common error if
301          * there is only one entry). We may be able to repair this by
302          * wrapping the returned Package with a new outer Package.
303          */
304         if (*Elements && ((*Elements)->Common.Type != ACPI_TYPE_PACKAGE))
305         {
306             /* Create the new outer package and populate it */
307 
308             Status = AcpiNsWrapWithPackage (
309                 Info, ReturnObject, ReturnObjectPtr);
310             if (ACPI_FAILURE (Status))
311             {
312                 return (Status);
313             }
314 
315             /* Update locals to point to the new package (of 1 element) */
316 
317             ReturnObject = *ReturnObjectPtr;
318             Elements = ReturnObject->Package.Elements;
319             Count = 1;
320         }
321 
322         /* Examine the subpackages */
323 
324         Status = AcpiNsCheckPackageList (Info, Package, Elements, Count);
325         break;
326 
327     case ACPI_PTYPE2_VAR_VAR:
328         /*
329          * Returns a variable list of packages, each with a variable list
330          * of objects.
331          */
332         break;
333 
334     case ACPI_PTYPE2_UUID_PAIR:
335 
336         /* The package must contain pairs of (UUID + type) */
337 
338         if (Count & 1)
339         {
340             ExpectedCount = Count + 1;
341             goto PackageTooSmall;
342         }
343 
344         while (Count > 0)
345         {
346             Status = AcpiNsCheckObjectType(Info, Elements,
347                 Package->RetInfo.ObjectType1, 0);
348             if (ACPI_FAILURE(Status))
349             {
350                 return (Status);
351             }
352 
353             /* Validate length of the UUID buffer */
354 
355             if ((*Elements)->Buffer.Length != 16)
356             {
357                 ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname,
358                     Info->NodeFlags, "Invalid length for UUID Buffer"));
359                 return (AE_AML_OPERAND_VALUE);
360             }
361 
362             Status = AcpiNsCheckObjectType(Info, Elements + 1,
363                 Package->RetInfo.ObjectType2, 0);
364             if (ACPI_FAILURE(Status))
365             {
366                 return (Status);
367             }
368 
369             Elements += 2;
370             Count -= 2;
371         }
372         break;
373 
374     default:
375 
376         /* Should not get here if predefined info table is correct */
377 
378         ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
379             "Invalid internal return type in table entry: %X",
380             Package->RetInfo.Type));
381 
382         return (AE_AML_INTERNAL);
383     }
384 
385     return (Status);
386 
387 
388 PackageTooSmall:
389 
390     /* Error exit for the case with an incorrect package count */
391 
392     ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
393         "Return Package is too small - found %u elements, expected %u",
394         Count, ExpectedCount));
395 
396     return (AE_AML_OPERAND_VALUE);
397 }
398 
399 
400 /*******************************************************************************
401  *
402  * FUNCTION:    AcpiNsCheckPackageList
403  *
404  * PARAMETERS:  Info            - Method execution information block
405  *              Package         - Pointer to package-specific info for method
406  *              Elements        - Element list of parent package. All elements
407  *                                of this list should be of type Package.
408  *              Count           - Count of subpackages
409  *
410  * RETURN:      Status
411  *
412  * DESCRIPTION: Examine a list of subpackages
413  *
414  ******************************************************************************/
415 
416 static ACPI_STATUS
417 AcpiNsCheckPackageList (
418     ACPI_EVALUATE_INFO          *Info,
419     const ACPI_PREDEFINED_INFO  *Package,
420     ACPI_OPERAND_OBJECT         **Elements,
421     UINT32                      Count)
422 {
423     ACPI_OPERAND_OBJECT         *SubPackage;
424     ACPI_OPERAND_OBJECT         **SubElements;
425     ACPI_STATUS                 Status;
426     UINT32                      ExpectedCount;
427     UINT32                      i;
428     UINT32                      j;
429 
430 
431     /*
432      * Validate each subpackage in the parent Package
433      *
434      * NOTE: assumes list of subpackages contains no NULL elements.
435      * Any NULL elements should have been removed by earlier call
436      * to AcpiNsRemoveNullElements.
437      */
438     for (i = 0; i < Count; i++)
439     {
440         SubPackage = *Elements;
441         SubElements = SubPackage->Package.Elements;
442         Info->ParentPackage = SubPackage;
443 
444         /* Each sub-object must be of type Package */
445 
446         Status = AcpiNsCheckObjectType (Info, &SubPackage,
447             ACPI_RTYPE_PACKAGE, i);
448         if (ACPI_FAILURE (Status))
449         {
450             return (Status);
451         }
452 
453         /* Examine the different types of expected subpackages */
454 
455         Info->ParentPackage = SubPackage;
456         switch (Package->RetInfo.Type)
457         {
458         case ACPI_PTYPE2:
459         case ACPI_PTYPE2_PKG_COUNT:
460         case ACPI_PTYPE2_REV_FIXED:
461 
462             /* Each subpackage has a fixed number of elements */
463 
464             ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2;
465             if (SubPackage->Package.Count < ExpectedCount)
466             {
467                 goto PackageTooSmall;
468             }
469 
470             Status = AcpiNsCheckPackageElements (Info, SubElements,
471                 Package->RetInfo.ObjectType1,
472                 Package->RetInfo.Count1,
473                 Package->RetInfo.ObjectType2,
474                 Package->RetInfo.Count2, 0);
475             if (ACPI_FAILURE (Status))
476             {
477                 return (Status);
478             }
479             break;
480 
481         case ACPI_PTYPE2_FIX_VAR:
482             /*
483              * Each subpackage has a fixed number of elements and an
484              * optional element
485              */
486             ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2;
487             if (SubPackage->Package.Count < ExpectedCount)
488             {
489                 goto PackageTooSmall;
490             }
491 
492             Status = AcpiNsCheckPackageElements (Info, SubElements,
493                 Package->RetInfo.ObjectType1,
494                 Package->RetInfo.Count1,
495                 Package->RetInfo.ObjectType2,
496                 SubPackage->Package.Count - Package->RetInfo.Count1, 0);
497             if (ACPI_FAILURE (Status))
498             {
499                 return (Status);
500             }
501             break;
502 
503         case ACPI_PTYPE2_VAR_VAR:
504             /*
505              * Each subpackage has a fixed or variable number of elements
506              */
507             break;
508 
509         case ACPI_PTYPE2_FIXED:
510 
511             /* Each subpackage has a fixed length */
512 
513             ExpectedCount = Package->RetInfo2.Count;
514             if (SubPackage->Package.Count < ExpectedCount)
515             {
516                 goto PackageTooSmall;
517             }
518 
519             /* Check the type of each subpackage element */
520 
521             for (j = 0; j < ExpectedCount; j++)
522             {
523                 Status = AcpiNsCheckObjectType (Info, &SubElements[j],
524                     Package->RetInfo2.ObjectType[j], j);
525                 if (ACPI_FAILURE (Status))
526                 {
527                     return (Status);
528                 }
529             }
530             break;
531 
532         case ACPI_PTYPE2_MIN:
533 
534             /* Each subpackage has a variable but minimum length */
535 
536             ExpectedCount = Package->RetInfo.Count1;
537             if (SubPackage->Package.Count < ExpectedCount)
538             {
539                 goto PackageTooSmall;
540             }
541 
542             /* Check the type of each subpackage element */
543 
544             Status = AcpiNsCheckPackageElements (Info, SubElements,
545                 Package->RetInfo.ObjectType1,
546                 SubPackage->Package.Count, 0, 0, 0);
547             if (ACPI_FAILURE (Status))
548             {
549                 return (Status);
550             }
551             break;
552 
553         case ACPI_PTYPE2_COUNT:
554             /*
555              * First element is the (Integer) count of elements, including
556              * the count field (the ACPI name is NumElements)
557              */
558             Status = AcpiNsCheckObjectType (Info, SubElements,
559                 ACPI_RTYPE_INTEGER, 0);
560             if (ACPI_FAILURE (Status))
561             {
562                 return (Status);
563             }
564 
565             /*
566              * Make sure package is large enough for the Count and is
567              * is as large as the minimum size
568              */
569             ExpectedCount = (UINT32) (*SubElements)->Integer.Value;
570             if (SubPackage->Package.Count < ExpectedCount)
571             {
572                 goto PackageTooSmall;
573             }
574 
575             if (SubPackage->Package.Count < Package->RetInfo.Count1)
576             {
577                 ExpectedCount = Package->RetInfo.Count1;
578                 goto PackageTooSmall;
579             }
580 
581             if (ExpectedCount == 0)
582             {
583                 /*
584                  * Either the NumEntries element was originally zero or it was
585                  * a NULL element and repaired to an Integer of value zero.
586                  * In either case, repair it by setting NumEntries to be the
587                  * actual size of the subpackage.
588                  */
589                 ExpectedCount = SubPackage->Package.Count;
590                 (*SubElements)->Integer.Value = ExpectedCount;
591             }
592 
593             /* Check the type of each subpackage element */
594 
595             Status = AcpiNsCheckPackageElements (Info, (SubElements + 1),
596                 Package->RetInfo.ObjectType1,
597                 (ExpectedCount - 1), 0, 0, 1);
598             if (ACPI_FAILURE (Status))
599             {
600                 return (Status);
601             }
602             break;
603 
604         default: /* Should not get here, type was validated by caller */
605 
606             return (AE_AML_INTERNAL);
607         }
608 
609         Elements++;
610     }
611 
612     return (AE_OK);
613 
614 
615 PackageTooSmall:
616 
617     /* The subpackage count was smaller than required */
618 
619     ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
620         "Return SubPackage[%u] is too small - found %u elements, expected %u",
621         i, SubPackage->Package.Count, ExpectedCount));
622 
623     return (AE_AML_OPERAND_VALUE);
624 }
625 
626 
627 /*******************************************************************************
628  *
629  * FUNCTION:    AcpiNsCheckPackageElements
630  *
631  * PARAMETERS:  Info            - Method execution information block
632  *              Elements        - Pointer to the package elements array
633  *              Type1           - Object type for first group
634  *              Count1          - Count for first group
635  *              Type2           - Object type for second group
636  *              Count2          - Count for second group
637  *              StartIndex      - Start of the first group of elements
638  *
639  * RETURN:      Status
640  *
641  * DESCRIPTION: Check that all elements of a package are of the correct object
642  *              type. Supports up to two groups of different object types.
643  *
644  ******************************************************************************/
645 
646 static ACPI_STATUS
647 AcpiNsCheckPackageElements (
648     ACPI_EVALUATE_INFO          *Info,
649     ACPI_OPERAND_OBJECT         **Elements,
650     UINT8                       Type1,
651     UINT32                      Count1,
652     UINT8                       Type2,
653     UINT32                      Count2,
654     UINT32                      StartIndex)
655 {
656     ACPI_OPERAND_OBJECT         **ThisElement = Elements;
657     ACPI_STATUS                 Status;
658     UINT32                      i;
659 
660 
661     /*
662      * Up to two groups of package elements are supported by the data
663      * structure. All elements in each group must be of the same type.
664      * The second group can have a count of zero.
665      */
666     for (i = 0; i < Count1; i++)
667     {
668         Status = AcpiNsCheckObjectType (Info, ThisElement,
669             Type1, i + StartIndex);
670         if (ACPI_FAILURE (Status))
671         {
672             return (Status);
673         }
674 
675         ThisElement++;
676     }
677 
678     for (i = 0; i < Count2; i++)
679     {
680         Status = AcpiNsCheckObjectType (Info, ThisElement,
681             Type2, (i + Count1 + StartIndex));
682         if (ACPI_FAILURE (Status))
683         {
684             return (Status);
685         }
686 
687         ThisElement++;
688     }
689 
690     return (AE_OK);
691 }
692