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