1/******************************************************************************
2 *
3 * Module Name: nsrepair - Repair for objects returned by predefined methods
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 <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/acinterp.h>
48#include <contrib/dev/acpica/include/acpredef.h>
49#include <contrib/dev/acpica/include/amlresrc.h>
50
51#define _COMPONENT          ACPI_NAMESPACE
52        ACPI_MODULE_NAME    ("nsrepair")
53
54
55/*******************************************************************************
56 *
57 * This module attempts to repair or convert objects returned by the
58 * predefined methods to an object type that is expected, as per the ACPI
59 * specification. The need for this code is dictated by the many machines that
60 * return incorrect types for the standard predefined methods. Performing these
61 * conversions here, in one place, eliminates the need for individual ACPI
62 * device drivers to do the same. Note: Most of these conversions are different
63 * than the internal object conversion routines used for implicit object
64 * conversion.
65 *
66 * The following conversions can be performed as necessary:
67 *
68 * Integer -> String
69 * Integer -> Buffer
70 * String  -> Integer
71 * String  -> Buffer
72 * Buffer  -> Integer
73 * Buffer  -> String
74 * Buffer  -> Package of Integers
75 * Package -> Package of one Package
76 *
77 * Additional conversions that are available:
78 *  Convert a null return or zero return value to an EndTag descriptor
79 *  Convert an ASCII string to a Unicode buffer
80 *
81 * An incorrect standalone object is wrapped with required outer package
82 *
83 * Additional possible repairs:
84 * Required package elements that are NULL replaced by Integer/String/Buffer
85 *
86 ******************************************************************************/
87
88
89/* Local prototypes */
90
91static const ACPI_SIMPLE_REPAIR_INFO *
92AcpiNsMatchSimpleRepair (
93    ACPI_NAMESPACE_NODE     *Node,
94    UINT32                  ReturnBtype,
95    UINT32                  PackageIndex);
96
97
98/*
99 * Special but simple repairs for some names.
100 *
101 * 2nd argument: Unexpected types that can be repaired
102 */
103static const ACPI_SIMPLE_REPAIR_INFO    AcpiObjectRepairInfo[] =
104{
105    /* Resource descriptor conversions */
106
107    { "_CRS", ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER | ACPI_RTYPE_NONE,
108                ACPI_NOT_PACKAGE_ELEMENT,
109                AcpiNsConvertToResource },
110    { "_DMA", ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER | ACPI_RTYPE_NONE,
111                ACPI_NOT_PACKAGE_ELEMENT,
112                AcpiNsConvertToResource },
113    { "_PRS", ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER | ACPI_RTYPE_NONE,
114                ACPI_NOT_PACKAGE_ELEMENT,
115                AcpiNsConvertToResource },
116
117    /* Object reference conversions */
118
119    { "_DEP", ACPI_RTYPE_STRING, ACPI_ALL_PACKAGE_ELEMENTS,
120                AcpiNsConvertToReference },
121
122    /* Unicode conversions */
123
124    { "_MLS", ACPI_RTYPE_STRING, 1,
125                AcpiNsConvertToUnicode },
126    { "_STR", ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER,
127                ACPI_NOT_PACKAGE_ELEMENT,
128                AcpiNsConvertToUnicode },
129    { {0,0,0,0}, 0, 0, NULL } /* Table terminator */
130};
131
132
133/*******************************************************************************
134 *
135 * FUNCTION:    AcpiNsSimpleRepair
136 *
137 * PARAMETERS:  Info                - Method execution information block
138 *              ExpectedBtypes      - Object types expected
139 *              PackageIndex        - Index of object within parent package (if
140 *                                    applicable - ACPI_NOT_PACKAGE_ELEMENT
141 *                                    otherwise)
142 *              ReturnObjectPtr     - Pointer to the object returned from the
143 *                                    evaluation of a method or object
144 *
145 * RETURN:      Status. AE_OK if repair was successful.
146 *
147 * DESCRIPTION: Attempt to repair/convert a return object of a type that was
148 *              not expected.
149 *
150 ******************************************************************************/
151
152ACPI_STATUS
153AcpiNsSimpleRepair (
154    ACPI_EVALUATE_INFO      *Info,
155    UINT32                  ExpectedBtypes,
156    UINT32                  PackageIndex,
157    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
158{
159    ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
160    ACPI_OPERAND_OBJECT     *NewObject = NULL;
161    ACPI_STATUS             Status;
162    const ACPI_SIMPLE_REPAIR_INFO   *Predefined;
163
164
165    ACPI_FUNCTION_NAME (NsSimpleRepair);
166
167
168    /*
169     * Special repairs for certain names that are in the repair table.
170     * Check if this name is in the list of repairable names.
171     */
172    Predefined = AcpiNsMatchSimpleRepair (Info->Node,
173        Info->ReturnBtype, PackageIndex);
174    if (Predefined)
175    {
176        if (!ReturnObject)
177        {
178            ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname,
179                ACPI_WARN_ALWAYS, "Missing expected return value"));
180        }
181
182        Status = Predefined->ObjectConverter (Info->Node, ReturnObject,
183            &NewObject);
184        if (ACPI_FAILURE (Status))
185        {
186            /* A fatal error occurred during a conversion */
187
188            ACPI_EXCEPTION ((AE_INFO, Status,
189                "During return object analysis"));
190            return (Status);
191        }
192        if (NewObject)
193        {
194            goto ObjectRepaired;
195        }
196    }
197
198    /*
199     * Do not perform simple object repair unless the return type is not
200     * expected.
201     */
202    if (Info->ReturnBtype & ExpectedBtypes)
203    {
204        return (AE_OK);
205    }
206
207    /*
208     * At this point, we know that the type of the returned object was not
209     * one of the expected types for this predefined name. Attempt to
210     * repair the object by converting it to one of the expected object
211     * types for this predefined name.
212     */
213
214    /*
215     * If there is no return value, check if we require a return value for
216     * this predefined name. Either one return value is expected, or none,
217     * for both methods and other objects.
218     *
219     * Try to fix if there was no return object. Warning if failed to fix.
220     */
221    if (!ReturnObject)
222    {
223        if (ExpectedBtypes && (!(ExpectedBtypes & ACPI_RTYPE_NONE)))
224        {
225            if (PackageIndex != ACPI_NOT_PACKAGE_ELEMENT)
226            {
227                ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname,
228                    ACPI_WARN_ALWAYS, "Found unexpected NULL package element"));
229
230                Status = AcpiNsRepairNullElement (Info, ExpectedBtypes,
231                    PackageIndex, ReturnObjectPtr);
232                if (ACPI_SUCCESS (Status))
233                {
234                    return (AE_OK); /* Repair was successful */
235                }
236            }
237            else
238            {
239                ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname,
240                    ACPI_WARN_ALWAYS, "Missing expected return value"));
241            }
242
243            return (AE_AML_NO_RETURN_VALUE);
244        }
245    }
246
247    if (ExpectedBtypes & ACPI_RTYPE_INTEGER)
248    {
249        Status = AcpiNsConvertToInteger (ReturnObject, &NewObject);
250        if (ACPI_SUCCESS (Status))
251        {
252            goto ObjectRepaired;
253        }
254    }
255    if (ExpectedBtypes & ACPI_RTYPE_STRING)
256    {
257        Status = AcpiNsConvertToString (ReturnObject, &NewObject);
258        if (ACPI_SUCCESS (Status))
259        {
260            goto ObjectRepaired;
261        }
262    }
263    if (ExpectedBtypes & ACPI_RTYPE_BUFFER)
264    {
265        Status = AcpiNsConvertToBuffer (ReturnObject, &NewObject);
266        if (ACPI_SUCCESS (Status))
267        {
268            goto ObjectRepaired;
269        }
270    }
271    if (ExpectedBtypes & ACPI_RTYPE_PACKAGE)
272    {
273        /*
274         * A package is expected. We will wrap the existing object with a
275         * new package object. It is often the case that if a variable-length
276         * package is required, but there is only a single object needed, the
277         * BIOS will return that object instead of wrapping it with a Package
278         * object. Note: after the wrapping, the package will be validated
279         * for correct contents (expected object type or types).
280         */
281        Status = AcpiNsWrapWithPackage (Info, ReturnObject, &NewObject);
282        if (ACPI_SUCCESS (Status))
283        {
284            /*
285             * The original object just had its reference count
286             * incremented for being inserted into the new package.
287             */
288            *ReturnObjectPtr = NewObject;       /* New Package object */
289            Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
290            return (AE_OK);
291        }
292    }
293
294    /* We cannot repair this object */
295
296    return (AE_AML_OPERAND_TYPE);
297
298
299ObjectRepaired:
300
301    /* Object was successfully repaired */
302
303    if (PackageIndex != ACPI_NOT_PACKAGE_ELEMENT)
304    {
305        /*
306         * The original object is a package element. We need to
307         * decrement the reference count of the original object,
308         * for removing it from the package.
309         *
310         * However, if the original object was just wrapped with a
311         * package object as part of the repair, we don't need to
312         * change the reference count.
313         */
314        if (!(Info->ReturnFlags & ACPI_OBJECT_WRAPPED))
315        {
316            NewObject->Common.ReferenceCount =
317                ReturnObject->Common.ReferenceCount;
318
319            if (ReturnObject->Common.ReferenceCount > 1)
320            {
321                ReturnObject->Common.ReferenceCount--;
322            }
323        }
324
325        ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
326            "%s: Converted %s to expected %s at Package index %u\n",
327            Info->FullPathname, AcpiUtGetObjectTypeName (ReturnObject),
328            AcpiUtGetObjectTypeName (NewObject), PackageIndex));
329    }
330    else
331    {
332        ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
333            "%s: Converted %s to expected %s\n",
334            Info->FullPathname, AcpiUtGetObjectTypeName (ReturnObject),
335            AcpiUtGetObjectTypeName (NewObject)));
336    }
337
338    /* Delete old object, install the new return object */
339
340    AcpiUtRemoveReference (ReturnObject);
341    *ReturnObjectPtr = NewObject;
342    Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
343    return (AE_OK);
344}
345
346
347/******************************************************************************
348 *
349 * FUNCTION:    AcpiNsMatchSimpleRepair
350 *
351 * PARAMETERS:  Node                - Namespace node for the method/object
352 *              ReturnBtype         - Object type that was returned
353 *              PackageIndex        - Index of object within parent package (if
354 *                                    applicable - ACPI_NOT_PACKAGE_ELEMENT
355 *                                    otherwise)
356 *
357 * RETURN:      Pointer to entry in repair table. NULL indicates not found.
358 *
359 * DESCRIPTION: Check an object name against the repairable object list.
360 *
361 *****************************************************************************/
362
363static const ACPI_SIMPLE_REPAIR_INFO *
364AcpiNsMatchSimpleRepair (
365    ACPI_NAMESPACE_NODE     *Node,
366    UINT32                  ReturnBtype,
367    UINT32                  PackageIndex)
368{
369    const ACPI_SIMPLE_REPAIR_INFO   *ThisName;
370
371
372    /* Search info table for a repairable predefined method/object name */
373
374    ThisName = AcpiObjectRepairInfo;
375    while (ThisName->ObjectConverter)
376    {
377        if (ACPI_COMPARE_NAME (Node->Name.Ascii, ThisName->Name))
378        {
379            /* Check if we can actually repair this name/type combination */
380
381            if ((ReturnBtype & ThisName->UnexpectedBtypes) &&
382                (ThisName->PackageIndex == ACPI_ALL_PACKAGE_ELEMENTS ||
383                 PackageIndex == ThisName->PackageIndex))
384            {
385                return (ThisName);
386            }
387
388            return (NULL);
389        }
390
391        ThisName++;
392    }
393
394    return (NULL); /* Name was not found in the repair table */
395}
396
397
398/*******************************************************************************
399 *
400 * FUNCTION:    AcpiNsRepairNullElement
401 *
402 * PARAMETERS:  Info                - Method execution information block
403 *              ExpectedBtypes      - Object types expected
404 *              PackageIndex        - Index of object within parent package (if
405 *                                    applicable - ACPI_NOT_PACKAGE_ELEMENT
406 *                                    otherwise)
407 *              ReturnObjectPtr     - Pointer to the object returned from the
408 *                                    evaluation of a method or object
409 *
410 * RETURN:      Status. AE_OK if repair was successful.
411 *
412 * DESCRIPTION: Attempt to repair a NULL element of a returned Package object.
413 *
414 ******************************************************************************/
415
416ACPI_STATUS
417AcpiNsRepairNullElement (
418    ACPI_EVALUATE_INFO      *Info,
419    UINT32                  ExpectedBtypes,
420    UINT32                  PackageIndex,
421    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
422{
423    ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
424    ACPI_OPERAND_OBJECT     *NewObject;
425
426
427    ACPI_FUNCTION_NAME (NsRepairNullElement);
428
429
430    /* No repair needed if return object is non-NULL */
431
432    if (ReturnObject)
433    {
434        return (AE_OK);
435    }
436
437    /*
438     * Attempt to repair a NULL element of a Package object. This applies to
439     * predefined names that return a fixed-length package and each element
440     * is required. It does not apply to variable-length packages where NULL
441     * elements are allowed, especially at the end of the package.
442     */
443    if (ExpectedBtypes & ACPI_RTYPE_INTEGER)
444    {
445        /* Need an Integer - create a zero-value integer */
446
447        NewObject = AcpiUtCreateIntegerObject ((UINT64) 0);
448    }
449    else if (ExpectedBtypes & ACPI_RTYPE_STRING)
450    {
451        /* Need a String - create a NULL string */
452
453        NewObject = AcpiUtCreateStringObject (0);
454    }
455    else if (ExpectedBtypes & ACPI_RTYPE_BUFFER)
456    {
457        /* Need a Buffer - create a zero-length buffer */
458
459        NewObject = AcpiUtCreateBufferObject (0);
460    }
461    else
462    {
463        /* Error for all other expected types */
464
465        return (AE_AML_OPERAND_TYPE);
466    }
467
468    if (!NewObject)
469    {
470        return (AE_NO_MEMORY);
471    }
472
473    /* Set the reference count according to the parent Package object */
474
475    NewObject->Common.ReferenceCount =
476        Info->ParentPackage->Common.ReferenceCount;
477
478    ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
479        "%s: Converted NULL package element to expected %s at index %u\n",
480        Info->FullPathname, AcpiUtGetObjectTypeName (NewObject),
481        PackageIndex));
482
483    *ReturnObjectPtr = NewObject;
484    Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
485    return (AE_OK);
486}
487
488
489/******************************************************************************
490 *
491 * FUNCTION:    AcpiNsRemoveNullElements
492 *
493 * PARAMETERS:  Info                - Method execution information block
494 *              PackageType         - An AcpiReturnPackageTypes value
495 *              ObjDesc             - A Package object
496 *
497 * RETURN:      None.
498 *
499 * DESCRIPTION: Remove all NULL package elements from packages that contain
500 *              a variable number of subpackages. For these types of
501 *              packages, NULL elements can be safely removed.
502 *
503 *****************************************************************************/
504
505void
506AcpiNsRemoveNullElements (
507    ACPI_EVALUATE_INFO      *Info,
508    UINT8                   PackageType,
509    ACPI_OPERAND_OBJECT     *ObjDesc)
510{
511    ACPI_OPERAND_OBJECT     **Source;
512    ACPI_OPERAND_OBJECT     **Dest;
513    UINT32                  Count;
514    UINT32                  NewCount;
515    UINT32                  i;
516
517
518    ACPI_FUNCTION_NAME (NsRemoveNullElements);
519
520
521    /*
522     * We can safely remove all NULL elements from these package types:
523     * PTYPE1_VAR packages contain a variable number of simple data types.
524     * PTYPE2 packages contain a variable number of subpackages.
525     */
526    switch (PackageType)
527    {
528    case ACPI_PTYPE1_VAR:
529    case ACPI_PTYPE2:
530    case ACPI_PTYPE2_COUNT:
531    case ACPI_PTYPE2_PKG_COUNT:
532    case ACPI_PTYPE2_FIXED:
533    case ACPI_PTYPE2_MIN:
534    case ACPI_PTYPE2_REV_FIXED:
535    case ACPI_PTYPE2_FIX_VAR:
536        break;
537
538    default:
539    case ACPI_PTYPE2_VAR_VAR:
540    case ACPI_PTYPE1_FIXED:
541    case ACPI_PTYPE1_OPTION:
542        return;
543    }
544
545    Count = ObjDesc->Package.Count;
546    NewCount = Count;
547
548    Source = ObjDesc->Package.Elements;
549    Dest = Source;
550
551    /* Examine all elements of the package object, remove nulls */
552
553    for (i = 0; i < Count; i++)
554    {
555        if (!*Source)
556        {
557            NewCount--;
558        }
559        else
560        {
561            *Dest = *Source;
562            Dest++;
563        }
564
565        Source++;
566    }
567
568    /* Update parent package if any null elements were removed */
569
570    if (NewCount < Count)
571    {
572        ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
573            "%s: Found and removed %u NULL elements\n",
574            Info->FullPathname, (Count - NewCount)));
575
576        /* NULL terminate list and update the package count */
577
578        *Dest = NULL;
579        ObjDesc->Package.Count = NewCount;
580    }
581}
582
583
584/*******************************************************************************
585 *
586 * FUNCTION:    AcpiNsWrapWithPackage
587 *
588 * PARAMETERS:  Info                - Method execution information block
589 *              OriginalObject      - Pointer to the object to repair.
590 *              ObjDescPtr          - The new package object is returned here
591 *
592 * RETURN:      Status, new object in *ObjDescPtr
593 *
594 * DESCRIPTION: Repair a common problem with objects that are defined to
595 *              return a variable-length Package of sub-objects. If there is
596 *              only one sub-object, some BIOS code mistakenly simply declares
597 *              the single object instead of a Package with one sub-object.
598 *              This function attempts to repair this error by wrapping a
599 *              Package object around the original object, creating the
600 *              correct and expected Package with one sub-object.
601 *
602 *              Names that can be repaired in this manner include:
603 *              _ALR, _CSD, _HPX, _MLS, _PLD, _PRT, _PSS, _TRT, _TSS,
604 *              _BCL, _DOD, _FIX, _Sx
605 *
606 ******************************************************************************/
607
608ACPI_STATUS
609AcpiNsWrapWithPackage (
610    ACPI_EVALUATE_INFO      *Info,
611    ACPI_OPERAND_OBJECT     *OriginalObject,
612    ACPI_OPERAND_OBJECT     **ObjDescPtr)
613{
614    ACPI_OPERAND_OBJECT     *PkgObjDesc;
615
616
617    ACPI_FUNCTION_NAME (NsWrapWithPackage);
618
619
620    /*
621     * Create the new outer package and populate it. The new
622     * package will have a single element, the lone sub-object.
623     */
624    PkgObjDesc = AcpiUtCreatePackageObject (1);
625    if (!PkgObjDesc)
626    {
627        return (AE_NO_MEMORY);
628    }
629
630    PkgObjDesc->Package.Elements[0] = OriginalObject;
631
632    ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
633        "%s: Wrapped %s with expected Package object\n",
634        Info->FullPathname, AcpiUtGetObjectTypeName (OriginalObject)));
635
636    /* Return the new object in the object pointer */
637
638    *ObjDescPtr = PkgObjDesc;
639    Info->ReturnFlags |= ACPI_OBJECT_REPAIRED | ACPI_OBJECT_WRAPPED;
640    return (AE_OK);
641}
642