1 /******************************************************************************
2  *
3  * Module Name: nsrepair2 - Repair for objects returned by specific
4  *                          predefined methods
5  *
6  *****************************************************************************/
7 
8 /*
9  * Copyright (C) 2000 - 2015, Intel Corp.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions, and the following disclaimer,
17  *    without modification.
18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19  *    substantially similar to the "NO WARRANTY" disclaimer below
20  *    ("Disclaimer") and any redistribution must be conditioned upon
21  *    including a substantially similar Disclaimer requirement for further
22  *    binary redistribution.
23  * 3. Neither the names of the above-listed copyright holders nor the names
24  *    of any contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * Alternatively, this software may be distributed under the terms of the
28  * GNU General Public License ("GPL") version 2 as published by the Free
29  * Software Foundation.
30  *
31  * NO WARRANTY
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42  * POSSIBILITY OF SUCH DAMAGES.
43  */
44 
45 #include "acpi.h"
46 #include "accommon.h"
47 #include "acnamesp.h"
48 
49 #define _COMPONENT          ACPI_NAMESPACE
50         ACPI_MODULE_NAME    ("nsrepair2")
51 
52 
53 /*
54  * Information structure and handler for ACPI predefined names that can
55  * be repaired on a per-name basis.
56  */
57 typedef
58 ACPI_STATUS (*ACPI_REPAIR_FUNCTION) (
59     ACPI_EVALUATE_INFO      *Info,
60     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
61 
62 typedef struct acpi_repair_info
63 {
64     char                    Name[ACPI_NAME_SIZE];
65     ACPI_REPAIR_FUNCTION    RepairFunction;
66 
67 } ACPI_REPAIR_INFO;
68 
69 
70 /* Local prototypes */
71 
72 static const ACPI_REPAIR_INFO *
73 AcpiNsMatchComplexRepair (
74     ACPI_NAMESPACE_NODE     *Node);
75 
76 static ACPI_STATUS
77 AcpiNsRepair_ALR (
78     ACPI_EVALUATE_INFO      *Info,
79     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
80 
81 static ACPI_STATUS
82 AcpiNsRepair_CID (
83     ACPI_EVALUATE_INFO      *Info,
84     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
85 
86 static ACPI_STATUS
87 AcpiNsRepair_CST (
88     ACPI_EVALUATE_INFO      *Info,
89     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
90 
91 static ACPI_STATUS
92 AcpiNsRepair_FDE (
93     ACPI_EVALUATE_INFO      *Info,
94     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
95 
96 static ACPI_STATUS
97 AcpiNsRepair_HID (
98     ACPI_EVALUATE_INFO      *Info,
99     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
100 
101 static ACPI_STATUS
102 AcpiNsRepair_PRT (
103     ACPI_EVALUATE_INFO      *Info,
104     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
105 
106 static ACPI_STATUS
107 AcpiNsRepair_PSS (
108     ACPI_EVALUATE_INFO      *Info,
109     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
110 
111 static ACPI_STATUS
112 AcpiNsRepair_TSS (
113     ACPI_EVALUATE_INFO      *Info,
114     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
115 
116 static ACPI_STATUS
117 AcpiNsCheckSortedList (
118     ACPI_EVALUATE_INFO      *Info,
119     ACPI_OPERAND_OBJECT     *ReturnObject,
120     UINT32                  StartIndex,
121     UINT32                  ExpectedCount,
122     UINT32                  SortIndex,
123     UINT8                   SortDirection,
124     char                    *SortKeyName);
125 
126 /* Values for SortDirection above */
127 
128 #define ACPI_SORT_ASCENDING     0
129 #define ACPI_SORT_DESCENDING    1
130 
131 static void
132 AcpiNsRemoveElement (
133     ACPI_OPERAND_OBJECT     *ObjDesc,
134     UINT32                  Index);
135 
136 static void
137 AcpiNsSortList (
138     ACPI_OPERAND_OBJECT     **Elements,
139     UINT32                  Count,
140     UINT32                  Index,
141     UINT8                   SortDirection);
142 
143 
144 /*
145  * This table contains the names of the predefined methods for which we can
146  * perform more complex repairs.
147  *
148  * As necessary:
149  *
150  * _ALR: Sort the list ascending by AmbientIlluminance
151  * _CID: Strings: uppercase all, remove any leading asterisk
152  * _CST: Sort the list ascending by C state type
153  * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
154  * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
155  * _HID: Strings: uppercase all, remove any leading asterisk
156  * _PRT: Fix reversed SourceName and SourceIndex
157  * _PSS: Sort the list descending by Power
158  * _TSS: Sort the list descending by Power
159  *
160  * Names that must be packages, but cannot be sorted:
161  *
162  * _BCL: Values are tied to the Package index where they appear, and cannot
163  * be moved or sorted. These index values are used for _BQC and _BCM.
164  * However, we can fix the case where a buffer is returned, by converting
165  * it to a Package of integers.
166  */
167 static const ACPI_REPAIR_INFO       AcpiNsRepairableNames[] =
168 {
169     {"_ALR", AcpiNsRepair_ALR},
170     {"_CID", AcpiNsRepair_CID},
171     {"_CST", AcpiNsRepair_CST},
172     {"_FDE", AcpiNsRepair_FDE},
173     {"_GTM", AcpiNsRepair_FDE},     /* _GTM has same repair as _FDE */
174     {"_HID", AcpiNsRepair_HID},
175     {"_PRT", AcpiNsRepair_PRT},
176     {"_PSS", AcpiNsRepair_PSS},
177     {"_TSS", AcpiNsRepair_TSS},
178     {{0,0,0,0}, NULL}               /* Table terminator */
179 };
180 
181 
182 #define ACPI_FDE_FIELD_COUNT        5
183 #define ACPI_FDE_BYTE_BUFFER_SIZE   5
184 #define ACPI_FDE_DWORD_BUFFER_SIZE  (ACPI_FDE_FIELD_COUNT * sizeof (UINT32))
185 
186 
187 /******************************************************************************
188  *
189  * FUNCTION:    AcpiNsComplexRepairs
190  *
191  * PARAMETERS:  Info                - Method execution information block
192  *              Node                - Namespace node for the method/object
193  *              ValidateStatus      - Original status of earlier validation
194  *              ReturnObjectPtr     - Pointer to the object returned from the
195  *                                    evaluation of a method or object
196  *
197  * RETURN:      Status. AE_OK if repair was successful. If name is not
198  *              matched, ValidateStatus is returned.
199  *
200  * DESCRIPTION: Attempt to repair/convert a return object of a type that was
201  *              not expected.
202  *
203  *****************************************************************************/
204 
205 ACPI_STATUS
206 AcpiNsComplexRepairs (
207     ACPI_EVALUATE_INFO      *Info,
208     ACPI_NAMESPACE_NODE     *Node,
209     ACPI_STATUS             ValidateStatus,
210     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
211 {
212     const ACPI_REPAIR_INFO  *Predefined;
213     ACPI_STATUS             Status;
214 
215 
216     /* Check if this name is in the list of repairable names */
217 
218     Predefined = AcpiNsMatchComplexRepair (Node);
219     if (!Predefined)
220     {
221         return (ValidateStatus);
222     }
223 
224     Status = Predefined->RepairFunction (Info, ReturnObjectPtr);
225     return (Status);
226 }
227 
228 
229 /******************************************************************************
230  *
231  * FUNCTION:    AcpiNsMatchComplexRepair
232  *
233  * PARAMETERS:  Node                - Namespace node for the method/object
234  *
235  * RETURN:      Pointer to entry in repair table. NULL indicates not found.
236  *
237  * DESCRIPTION: Check an object name against the repairable object list.
238  *
239  *****************************************************************************/
240 
241 static const ACPI_REPAIR_INFO *
242 AcpiNsMatchComplexRepair (
243     ACPI_NAMESPACE_NODE     *Node)
244 {
245     const ACPI_REPAIR_INFO  *ThisName;
246 
247 
248     /* Search info table for a repairable predefined method/object name */
249 
250     ThisName = AcpiNsRepairableNames;
251     while (ThisName->RepairFunction)
252     {
253         if (ACPI_COMPARE_NAME (Node->Name.Ascii, ThisName->Name))
254         {
255             return (ThisName);
256         }
257         ThisName++;
258     }
259 
260     return (NULL); /* Not found */
261 }
262 
263 
264 /******************************************************************************
265  *
266  * FUNCTION:    AcpiNsRepair_ALR
267  *
268  * PARAMETERS:  Info                - Method execution information block
269  *              ReturnObjectPtr     - Pointer to the object returned from the
270  *                                    evaluation of a method or object
271  *
272  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
273  *
274  * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list
275  *              ascending by the ambient illuminance values.
276  *
277  *****************************************************************************/
278 
279 static ACPI_STATUS
280 AcpiNsRepair_ALR (
281     ACPI_EVALUATE_INFO      *Info,
282     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
283 {
284     ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
285     ACPI_STATUS             Status;
286 
287 
288     Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 2, 1,
289                 ACPI_SORT_ASCENDING, "AmbientIlluminance");
290 
291     return (Status);
292 }
293 
294 
295 /******************************************************************************
296  *
297  * FUNCTION:    AcpiNsRepair_FDE
298  *
299  * PARAMETERS:  Info                - Method execution information block
300  *              ReturnObjectPtr     - Pointer to the object returned from the
301  *                                    evaluation of a method or object
302  *
303  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
304  *
305  * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return
306  *              value is a Buffer of 5 DWORDs. This function repairs a common
307  *              problem where the return value is a Buffer of BYTEs, not
308  *              DWORDs.
309  *
310  *****************************************************************************/
311 
312 static ACPI_STATUS
313 AcpiNsRepair_FDE (
314     ACPI_EVALUATE_INFO      *Info,
315     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
316 {
317     ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
318     ACPI_OPERAND_OBJECT     *BufferObject;
319     UINT8                   *ByteBuffer;
320     UINT32                  *DwordBuffer;
321     UINT32                  i;
322 
323 
324     ACPI_FUNCTION_NAME (NsRepair_FDE);
325 
326 
327     switch (ReturnObject->Common.Type)
328     {
329     case ACPI_TYPE_BUFFER:
330 
331         /* This is the expected type. Length should be (at least) 5 DWORDs */
332 
333         if (ReturnObject->Buffer.Length >= ACPI_FDE_DWORD_BUFFER_SIZE)
334         {
335             return (AE_OK);
336         }
337 
338         /* We can only repair if we have exactly 5 BYTEs */
339 
340         if (ReturnObject->Buffer.Length != ACPI_FDE_BYTE_BUFFER_SIZE)
341         {
342             ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
343                 "Incorrect return buffer length %u, expected %u",
344                 ReturnObject->Buffer.Length, ACPI_FDE_DWORD_BUFFER_SIZE));
345 
346             return (AE_AML_OPERAND_TYPE);
347         }
348 
349         /* Create the new (larger) buffer object */
350 
351         BufferObject = AcpiUtCreateBufferObject (ACPI_FDE_DWORD_BUFFER_SIZE);
352         if (!BufferObject)
353         {
354             return (AE_NO_MEMORY);
355         }
356 
357         /* Expand each byte to a DWORD */
358 
359         ByteBuffer = ReturnObject->Buffer.Pointer;
360         DwordBuffer = ACPI_CAST_PTR (UINT32, BufferObject->Buffer.Pointer);
361 
362         for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++)
363         {
364             *DwordBuffer = (UINT32) *ByteBuffer;
365             DwordBuffer++;
366             ByteBuffer++;
367         }
368 
369         ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
370             "%s Expanded Byte Buffer to expected DWord Buffer\n",
371             Info->FullPathname));
372         break;
373 
374     default:
375 
376         return (AE_AML_OPERAND_TYPE);
377     }
378 
379     /* Delete the original return object, return the new buffer object */
380 
381     AcpiUtRemoveReference (ReturnObject);
382     *ReturnObjectPtr = BufferObject;
383 
384     Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
385     return (AE_OK);
386 }
387 
388 
389 /******************************************************************************
390  *
391  * FUNCTION:    AcpiNsRepair_CID
392  *
393  * PARAMETERS:  Info                - Method execution information block
394  *              ReturnObjectPtr     - Pointer to the object returned from the
395  *                                    evaluation of a method or object
396  *
397  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
398  *
399  * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
400  *              letters are uppercase and that there is no leading asterisk.
401  *              If a Package, ensure same for all string elements.
402  *
403  *****************************************************************************/
404 
405 static ACPI_STATUS
406 AcpiNsRepair_CID (
407     ACPI_EVALUATE_INFO      *Info,
408     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
409 {
410     ACPI_STATUS             Status;
411     ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
412     ACPI_OPERAND_OBJECT     **ElementPtr;
413     ACPI_OPERAND_OBJECT     *OriginalElement;
414     UINT16                  OriginalRefCount;
415     UINT32                  i;
416 
417 
418     /* Check for _CID as a simple string */
419 
420     if (ReturnObject->Common.Type == ACPI_TYPE_STRING)
421     {
422         Status = AcpiNsRepair_HID (Info, ReturnObjectPtr);
423         return (Status);
424     }
425 
426     /* Exit if not a Package */
427 
428     if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE)
429     {
430         return (AE_OK);
431     }
432 
433     /* Examine each element of the _CID package */
434 
435     ElementPtr = ReturnObject->Package.Elements;
436     for (i = 0; i < ReturnObject->Package.Count; i++)
437     {
438         OriginalElement = *ElementPtr;
439         OriginalRefCount = OriginalElement->Common.ReferenceCount;
440 
441         Status = AcpiNsRepair_HID (Info, ElementPtr);
442         if (ACPI_FAILURE (Status))
443         {
444             return (Status);
445         }
446 
447         /* Take care with reference counts */
448 
449         if (OriginalElement != *ElementPtr)
450         {
451             /* Element was replaced */
452 
453             (*ElementPtr)->Common.ReferenceCount =
454                 OriginalRefCount;
455 
456             AcpiUtRemoveReference (OriginalElement);
457         }
458 
459         ElementPtr++;
460     }
461 
462     return (AE_OK);
463 }
464 
465 
466 /******************************************************************************
467  *
468  * FUNCTION:    AcpiNsRepair_CST
469  *
470  * PARAMETERS:  Info                - Method execution information block
471  *              ReturnObjectPtr     - Pointer to the object returned from the
472  *                                    evaluation of a method or object
473  *
474  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
475  *
476  * DESCRIPTION: Repair for the _CST object:
477  *              1. Sort the list ascending by C state type
478  *              2. Ensure type cannot be zero
479  *              3. A subpackage count of zero means _CST is meaningless
480  *              4. Count must match the number of C state subpackages
481  *
482  *****************************************************************************/
483 
484 static ACPI_STATUS
485 AcpiNsRepair_CST (
486     ACPI_EVALUATE_INFO      *Info,
487     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
488 {
489     ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
490     ACPI_OPERAND_OBJECT     **OuterElements;
491     UINT32                  OuterElementCount;
492     ACPI_OPERAND_OBJECT     *ObjDesc;
493     ACPI_STATUS             Status;
494     BOOLEAN                 Removing;
495     UINT32                  i;
496 
497 
498     ACPI_FUNCTION_NAME (NsRepair_CST);
499 
500 
501     /*
502      * Check if the C-state type values are proportional.
503      */
504     OuterElementCount = ReturnObject->Package.Count - 1;
505     i = 0;
506     while (i < OuterElementCount)
507     {
508         OuterElements = &ReturnObject->Package.Elements[i + 1];
509         Removing = FALSE;
510 
511         if ((*OuterElements)->Package.Count == 0)
512         {
513             ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
514                 "SubPackage[%u] - removing entry due to zero count", i));
515             Removing = TRUE;
516             goto RemoveElement;
517         }
518 
519         ObjDesc = (*OuterElements)->Package.Elements[1]; /* Index1 = Type */
520         if ((UINT32) ObjDesc->Integer.Value == 0)
521         {
522             ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
523                 "SubPackage[%u] - removing entry due to invalid Type(0)", i));
524             Removing = TRUE;
525         }
526 
527 RemoveElement:
528         if (Removing)
529         {
530             AcpiNsRemoveElement (ReturnObject, i + 1);
531             OuterElementCount--;
532         }
533         else
534         {
535             i++;
536         }
537     }
538 
539     /* Update top-level package count, Type "Integer" checked elsewhere */
540 
541     ObjDesc = ReturnObject->Package.Elements[0];
542     ObjDesc->Integer.Value = OuterElementCount;
543 
544     /*
545      * Entries (subpackages) in the _CST Package must be sorted by the
546      * C-state type, in ascending order.
547      */
548     Status = AcpiNsCheckSortedList (Info, ReturnObject, 1, 4, 1,
549                 ACPI_SORT_ASCENDING, "C-State Type");
550     if (ACPI_FAILURE (Status))
551     {
552         return (Status);
553     }
554 
555     return (AE_OK);
556 }
557 
558 
559 /******************************************************************************
560  *
561  * FUNCTION:    AcpiNsRepair_HID
562  *
563  * PARAMETERS:  Info                - Method execution information block
564  *              ReturnObjectPtr     - Pointer to the object returned from the
565  *                                    evaluation of a method or object
566  *
567  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
568  *
569  * DESCRIPTION: Repair for the _HID object. If a string, ensure that all
570  *              letters are uppercase and that there is no leading asterisk.
571  *
572  *****************************************************************************/
573 
574 static ACPI_STATUS
575 AcpiNsRepair_HID (
576     ACPI_EVALUATE_INFO      *Info,
577     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
578 {
579     ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
580     ACPI_OPERAND_OBJECT     *NewString;
581     char                    *Source;
582     char                    *Dest;
583 
584 
585     ACPI_FUNCTION_NAME (NsRepair_HID);
586 
587 
588     /* We only care about string _HID objects (not integers) */
589 
590     if (ReturnObject->Common.Type != ACPI_TYPE_STRING)
591     {
592         return (AE_OK);
593     }
594 
595     if (ReturnObject->String.Length == 0)
596     {
597         ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
598             "Invalid zero-length _HID or _CID string"));
599 
600         /* Return AE_OK anyway, let driver handle it */
601 
602         Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
603         return (AE_OK);
604     }
605 
606     /* It is simplest to always create a new string object */
607 
608     NewString = AcpiUtCreateStringObject (ReturnObject->String.Length);
609     if (!NewString)
610     {
611         return (AE_NO_MEMORY);
612     }
613 
614     /*
615      * Remove a leading asterisk if present. For some unknown reason, there
616      * are many machines in the field that contains IDs like this.
617      *
618      * Examples: "*PNP0C03", "*ACPI0003"
619      */
620     Source = ReturnObject->String.Pointer;
621     if (*Source == '*')
622     {
623         Source++;
624         NewString->String.Length--;
625 
626         ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
627             "%s: Removed invalid leading asterisk\n", Info->FullPathname));
628     }
629 
630     /*
631      * Copy and uppercase the string. From the ACPI 5.0 specification:
632      *
633      * A valid PNP ID must be of the form "AAA####" where A is an uppercase
634      * letter and # is a hex digit. A valid ACPI ID must be of the form
635      * "NNNN####" where N is an uppercase letter or decimal digit, and
636      * # is a hex digit.
637      */
638     for (Dest = NewString->String.Pointer; *Source; Dest++, Source++)
639     {
640         *Dest = (char) toupper ((int) *Source);
641     }
642 
643     AcpiUtRemoveReference (ReturnObject);
644     *ReturnObjectPtr = NewString;
645     return (AE_OK);
646 }
647 
648 
649 /******************************************************************************
650  *
651  * FUNCTION:    AcpiNsRepair_PRT
652  *
653  * PARAMETERS:  Info                - Method execution information block
654  *              ReturnObjectPtr     - Pointer to the object returned from the
655  *                                    evaluation of a method or object
656  *
657  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
658  *
659  * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed
660  *              SourceName and SourceIndex field, a common BIOS bug.
661  *
662  *****************************************************************************/
663 
664 static ACPI_STATUS
665 AcpiNsRepair_PRT (
666     ACPI_EVALUATE_INFO      *Info,
667     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
668 {
669     ACPI_OPERAND_OBJECT     *PackageObject = *ReturnObjectPtr;
670     ACPI_OPERAND_OBJECT     **TopObjectList;
671     ACPI_OPERAND_OBJECT     **SubObjectList;
672     ACPI_OPERAND_OBJECT     *ObjDesc;
673     ACPI_OPERAND_OBJECT     *SubPackage;
674     UINT32                  ElementCount;
675     UINT32                  Index;
676 
677 
678     /* Each element in the _PRT package is a subpackage */
679 
680     TopObjectList = PackageObject->Package.Elements;
681     ElementCount = PackageObject->Package.Count;
682 
683     /* Examine each subpackage */
684 
685     for (Index = 0; Index < ElementCount; Index++, TopObjectList++)
686     {
687         SubPackage = *TopObjectList;
688         SubObjectList = SubPackage->Package.Elements;
689 
690         /* Check for minimum required element count */
691 
692         if (SubPackage->Package.Count < 4)
693         {
694             continue;
695         }
696 
697         /*
698          * If the BIOS has erroneously reversed the _PRT SourceName (index 2)
699          * and the SourceIndex (index 3), fix it. _PRT is important enough to
700          * workaround this BIOS error. This also provides compatibility with
701          * other ACPI implementations.
702          */
703         ObjDesc = SubObjectList[3];
704         if (!ObjDesc || (ObjDesc->Common.Type != ACPI_TYPE_INTEGER))
705         {
706             SubObjectList[3] = SubObjectList[2];
707             SubObjectList[2] = ObjDesc;
708             Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
709 
710             ACPI_WARN_PREDEFINED ((AE_INFO,
711                 Info->FullPathname, Info->NodeFlags,
712                 "PRT[%X]: Fixed reversed SourceName and SourceIndex",
713                 Index));
714         }
715     }
716 
717     return (AE_OK);
718 }
719 
720 
721 /******************************************************************************
722  *
723  * FUNCTION:    AcpiNsRepair_PSS
724  *
725  * PARAMETERS:  Info                - Method execution information block
726  *              ReturnObjectPtr     - Pointer to the object returned from the
727  *                                    evaluation of a method or object
728  *
729  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
730  *
731  * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list
732  *              by the CPU frequencies. Check that the power dissipation values
733  *              are all proportional to CPU frequency (i.e., sorting by
734  *              frequency should be the same as sorting by power.)
735  *
736  *****************************************************************************/
737 
738 static ACPI_STATUS
739 AcpiNsRepair_PSS (
740     ACPI_EVALUATE_INFO      *Info,
741     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
742 {
743     ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
744     ACPI_OPERAND_OBJECT     **OuterElements;
745     UINT32                  OuterElementCount;
746     ACPI_OPERAND_OBJECT     **Elements;
747     ACPI_OPERAND_OBJECT     *ObjDesc;
748     UINT32                  PreviousValue;
749     ACPI_STATUS             Status;
750     UINT32                  i;
751 
752 
753     /*
754      * Entries (subpackages) in the _PSS Package must be sorted by power
755      * dissipation, in descending order. If it appears that the list is
756      * incorrectly sorted, sort it. We sort by CpuFrequency, since this
757      * should be proportional to the power.
758      */
759     Status =AcpiNsCheckSortedList (Info, ReturnObject, 0, 6, 0,
760                 ACPI_SORT_DESCENDING, "CpuFrequency");
761     if (ACPI_FAILURE (Status))
762     {
763         return (Status);
764     }
765 
766     /*
767      * We now know the list is correctly sorted by CPU frequency. Check if
768      * the power dissipation values are proportional.
769      */
770     PreviousValue = ACPI_UINT32_MAX;
771     OuterElements = ReturnObject->Package.Elements;
772     OuterElementCount = ReturnObject->Package.Count;
773 
774     for (i = 0; i < OuterElementCount; i++)
775     {
776         Elements = (*OuterElements)->Package.Elements;
777         ObjDesc = Elements[1]; /* Index1 = PowerDissipation */
778 
779         if ((UINT32) ObjDesc->Integer.Value > PreviousValue)
780         {
781             ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
782                 "SubPackage[%u,%u] - suspicious power dissipation values",
783                 i-1, i));
784         }
785 
786         PreviousValue = (UINT32) ObjDesc->Integer.Value;
787         OuterElements++;
788     }
789 
790     return (AE_OK);
791 }
792 
793 
794 /******************************************************************************
795  *
796  * FUNCTION:    AcpiNsRepair_TSS
797  *
798  * PARAMETERS:  Info                - Method execution information block
799  *              ReturnObjectPtr     - Pointer to the object returned from the
800  *                                    evaluation of a method or object
801  *
802  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
803  *
804  * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
805  *              descending by the power dissipation values.
806  *
807  *****************************************************************************/
808 
809 static ACPI_STATUS
810 AcpiNsRepair_TSS (
811     ACPI_EVALUATE_INFO      *Info,
812     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
813 {
814     ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
815     ACPI_STATUS             Status;
816     ACPI_NAMESPACE_NODE     *Node;
817 
818 
819     /*
820      * We can only sort the _TSS return package if there is no _PSS in the
821      * same scope. This is because if _PSS is present, the ACPI specification
822      * dictates that the _TSS Power Dissipation field is to be ignored, and
823      * therefore some BIOSs leave garbage values in the _TSS Power field(s).
824      * In this case, it is best to just return the _TSS package as-is.
825      * (May, 2011)
826      */
827     Status = AcpiNsGetNode (Info->Node, "^_PSS",
828         ACPI_NS_NO_UPSEARCH, &Node);
829     if (ACPI_SUCCESS (Status))
830     {
831         return (AE_OK);
832     }
833 
834     Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 5, 1,
835                 ACPI_SORT_DESCENDING, "PowerDissipation");
836 
837     return (Status);
838 }
839 
840 
841 /******************************************************************************
842  *
843  * FUNCTION:    AcpiNsCheckSortedList
844  *
845  * PARAMETERS:  Info                - Method execution information block
846  *              ReturnObject        - Pointer to the top-level returned object
847  *              StartIndex          - Index of the first subpackage
848  *              ExpectedCount       - Minimum length of each subpackage
849  *              SortIndex           - Subpackage entry to sort on
850  *              SortDirection       - Ascending or descending
851  *              SortKeyName         - Name of the SortIndex field
852  *
853  * RETURN:      Status. AE_OK if the list is valid and is sorted correctly or
854  *              has been repaired by sorting the list.
855  *
856  * DESCRIPTION: Check if the package list is valid and sorted correctly by the
857  *              SortIndex. If not, then sort the list.
858  *
859  *****************************************************************************/
860 
861 static ACPI_STATUS
862 AcpiNsCheckSortedList (
863     ACPI_EVALUATE_INFO      *Info,
864     ACPI_OPERAND_OBJECT     *ReturnObject,
865     UINT32                  StartIndex,
866     UINT32                  ExpectedCount,
867     UINT32                  SortIndex,
868     UINT8                   SortDirection,
869     char                    *SortKeyName)
870 {
871     UINT32                  OuterElementCount;
872     ACPI_OPERAND_OBJECT     **OuterElements;
873     ACPI_OPERAND_OBJECT     **Elements;
874     ACPI_OPERAND_OBJECT     *ObjDesc;
875     UINT32                  i;
876     UINT32                  PreviousValue;
877 
878 
879     ACPI_FUNCTION_NAME (NsCheckSortedList);
880 
881 
882     /* The top-level object must be a package */
883 
884     if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE)
885     {
886         return (AE_AML_OPERAND_TYPE);
887     }
888 
889     /*
890      * NOTE: assumes list of subpackages contains no NULL elements.
891      * Any NULL elements should have been removed by earlier call
892      * to AcpiNsRemoveNullElements.
893      */
894     OuterElementCount = ReturnObject->Package.Count;
895     if (!OuterElementCount || StartIndex >= OuterElementCount)
896     {
897         return (AE_AML_PACKAGE_LIMIT);
898     }
899 
900     OuterElements = &ReturnObject->Package.Elements[StartIndex];
901     OuterElementCount -= StartIndex;
902 
903     PreviousValue = 0;
904     if (SortDirection == ACPI_SORT_DESCENDING)
905     {
906         PreviousValue = ACPI_UINT32_MAX;
907     }
908 
909     /* Examine each subpackage */
910 
911     for (i = 0; i < OuterElementCount; i++)
912     {
913         /* Each element of the top-level package must also be a package */
914 
915         if ((*OuterElements)->Common.Type != ACPI_TYPE_PACKAGE)
916         {
917             return (AE_AML_OPERAND_TYPE);
918         }
919 
920         /* Each subpackage must have the minimum length */
921 
922         if ((*OuterElements)->Package.Count < ExpectedCount)
923         {
924             return (AE_AML_PACKAGE_LIMIT);
925         }
926 
927         Elements = (*OuterElements)->Package.Elements;
928         ObjDesc = Elements[SortIndex];
929 
930         if (ObjDesc->Common.Type != ACPI_TYPE_INTEGER)
931         {
932             return (AE_AML_OPERAND_TYPE);
933         }
934 
935         /*
936          * The list must be sorted in the specified order. If we detect a
937          * discrepancy, sort the entire list.
938          */
939         if (((SortDirection == ACPI_SORT_ASCENDING) &&
940                 (ObjDesc->Integer.Value < PreviousValue)) ||
941             ((SortDirection == ACPI_SORT_DESCENDING) &&
942                 (ObjDesc->Integer.Value > PreviousValue)))
943         {
944             AcpiNsSortList (&ReturnObject->Package.Elements[StartIndex],
945                 OuterElementCount, SortIndex, SortDirection);
946 
947             Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
948 
949             ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
950                 "%s: Repaired unsorted list - now sorted by %s\n",
951                 Info->FullPathname, SortKeyName));
952             return (AE_OK);
953         }
954 
955         PreviousValue = (UINT32) ObjDesc->Integer.Value;
956         OuterElements++;
957     }
958 
959     return (AE_OK);
960 }
961 
962 
963 /******************************************************************************
964  *
965  * FUNCTION:    AcpiNsSortList
966  *
967  * PARAMETERS:  Elements            - Package object element list
968  *              Count               - Element count for above
969  *              Index               - Sort by which package element
970  *              SortDirection       - Ascending or Descending sort
971  *
972  * RETURN:      None
973  *
974  * DESCRIPTION: Sort the objects that are in a package element list.
975  *
976  * NOTE: Assumes that all NULL elements have been removed from the package,
977  *       and that all elements have been verified to be of type Integer.
978  *
979  *****************************************************************************/
980 
981 static void
982 AcpiNsSortList (
983     ACPI_OPERAND_OBJECT     **Elements,
984     UINT32                  Count,
985     UINT32                  Index,
986     UINT8                   SortDirection)
987 {
988     ACPI_OPERAND_OBJECT     *ObjDesc1;
989     ACPI_OPERAND_OBJECT     *ObjDesc2;
990     ACPI_OPERAND_OBJECT     *TempObj;
991     UINT32                  i;
992     UINT32                  j;
993 
994 
995     /* Simple bubble sort */
996 
997     for (i = 1; i < Count; i++)
998     {
999         for (j = (Count - 1); j >= i; j--)
1000         {
1001             ObjDesc1 = Elements[j-1]->Package.Elements[Index];
1002             ObjDesc2 = Elements[j]->Package.Elements[Index];
1003 
1004             if (((SortDirection == ACPI_SORT_ASCENDING) &&
1005                     (ObjDesc1->Integer.Value > ObjDesc2->Integer.Value)) ||
1006 
1007                 ((SortDirection == ACPI_SORT_DESCENDING) &&
1008                     (ObjDesc1->Integer.Value < ObjDesc2->Integer.Value)))
1009             {
1010                 TempObj = Elements[j-1];
1011                 Elements[j-1] = Elements[j];
1012                 Elements[j] = TempObj;
1013             }
1014         }
1015     }
1016 }
1017 
1018 
1019 /******************************************************************************
1020  *
1021  * FUNCTION:    AcpiNsRemoveElement
1022  *
1023  * PARAMETERS:  ObjDesc             - Package object element list
1024  *              Index               - Index of element to remove
1025  *
1026  * RETURN:      None
1027  *
1028  * DESCRIPTION: Remove the requested element of a package and delete it.
1029  *
1030  *****************************************************************************/
1031 
1032 static void
1033 AcpiNsRemoveElement (
1034     ACPI_OPERAND_OBJECT     *ObjDesc,
1035     UINT32                  Index)
1036 {
1037     ACPI_OPERAND_OBJECT     **Source;
1038     ACPI_OPERAND_OBJECT     **Dest;
1039     UINT32                  Count;
1040     UINT32                  NewCount;
1041     UINT32                  i;
1042 
1043 
1044     ACPI_FUNCTION_NAME (NsRemoveElement);
1045 
1046 
1047     Count = ObjDesc->Package.Count;
1048     NewCount = Count - 1;
1049 
1050     Source = ObjDesc->Package.Elements;
1051     Dest = Source;
1052 
1053     /* Examine all elements of the package object, remove matched index */
1054 
1055     for (i = 0; i < Count; i++)
1056     {
1057         if (i == Index)
1058         {
1059             AcpiUtRemoveReference (*Source); /* Remove one ref for being in pkg */
1060             AcpiUtRemoveReference (*Source);
1061         }
1062         else
1063         {
1064             *Dest = *Source;
1065             Dest++;
1066         }
1067         Source++;
1068     }
1069 
1070     /* NULL terminate list and update the package count */
1071 
1072     *Dest = NULL;
1073     ObjDesc->Package.Count = NewCount;
1074 }
1075