nsprepkg.c revision 249663
150476Speter/******************************************************************************
223381Swosch *
3106146Sru * Module Name: nsprepkg - Validation of package objects for predefined names
4136910Sru *
5136910Sru *****************************************************************************/
623381Swosch
723381Swosch/*
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
56static ACPI_STATUS
57AcpiNsCheckPackageList (
58    ACPI_EVALUATE_INFO          *Info,
59    const ACPI_PREDEFINED_INFO  *Package,
60    ACPI_OPERAND_OBJECT         **Elements,
61    UINT32                      Count);
62
63static ACPI_STATUS
64AcpiNsCheckPackageElements (
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
89ACPI_STATUS
90AcpiNsCheckPackage (
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
348PackageTooSmall:
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
376static ACPI_STATUS
377AcpiNsCheckPackageList (
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
573PackageTooSmall:
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
604static ACPI_STATUS
605AcpiNsCheckPackageElements (
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