nsrepair2.c revision 1.13 1 /******************************************************************************
2 *
3 * Module Name: nsrepair2 - Repair for objects returned by specific
4 * predefined methods
5 *
6 *****************************************************************************/
7
8 /*
9 * Copyright (C) 2000 - 2019, 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_NAMESEG_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 const 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_NAMESEG (Node->Name.Ascii, ThisName->Name))
254 {
255 return (ThisName);
256 }
257
258 ThisName++;
259 }
260
261 return (NULL); /* Not found */
262 }
263
264
265 /******************************************************************************
266 *
267 * FUNCTION: AcpiNsRepair_ALR
268 *
269 * PARAMETERS: Info - Method execution information block
270 * ReturnObjectPtr - Pointer to the object returned from the
271 * evaluation of a method or object
272 *
273 * RETURN: Status. AE_OK if object is OK or was repaired successfully
274 *
275 * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list
276 * ascending by the ambient illuminance values.
277 *
278 *****************************************************************************/
279
280 static ACPI_STATUS
281 AcpiNsRepair_ALR (
282 ACPI_EVALUATE_INFO *Info,
283 ACPI_OPERAND_OBJECT **ReturnObjectPtr)
284 {
285 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr;
286 ACPI_STATUS Status;
287
288
289 Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 2, 1,
290 ACPI_SORT_ASCENDING, "AmbientIlluminance");
291
292 return (Status);
293 }
294
295
296 /******************************************************************************
297 *
298 * FUNCTION: AcpiNsRepair_FDE
299 *
300 * PARAMETERS: Info - Method execution information block
301 * ReturnObjectPtr - Pointer to the object returned from the
302 * evaluation of a method or object
303 *
304 * RETURN: Status. AE_OK if object is OK or was repaired successfully
305 *
306 * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return
307 * value is a Buffer of 5 DWORDs. This function repairs a common
308 * problem where the return value is a Buffer of BYTEs, not
309 * DWORDs.
310 *
311 *****************************************************************************/
312
313 static ACPI_STATUS
314 AcpiNsRepair_FDE (
315 ACPI_EVALUATE_INFO *Info,
316 ACPI_OPERAND_OBJECT **ReturnObjectPtr)
317 {
318 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr;
319 ACPI_OPERAND_OBJECT *BufferObject;
320 UINT8 *ByteBuffer;
321 UINT32 *DwordBuffer;
322 UINT32 i;
323
324
325 ACPI_FUNCTION_NAME (NsRepair_FDE);
326
327
328 switch (ReturnObject->Common.Type)
329 {
330 case ACPI_TYPE_BUFFER:
331
332 /* This is the expected type. Length should be (at least) 5 DWORDs */
333
334 if (ReturnObject->Buffer.Length >= ACPI_FDE_DWORD_BUFFER_SIZE)
335 {
336 return (AE_OK);
337 }
338
339 /* We can only repair if we have exactly 5 BYTEs */
340
341 if (ReturnObject->Buffer.Length != ACPI_FDE_BYTE_BUFFER_SIZE)
342 {
343 ACPI_WARN_PREDEFINED ((AE_INFO,
344 Info->FullPathname, Info->NodeFlags,
345 "Incorrect return buffer length %u, expected %u",
346 ReturnObject->Buffer.Length, ACPI_FDE_DWORD_BUFFER_SIZE));
347
348 return (AE_AML_OPERAND_TYPE);
349 }
350
351 /* Create the new (larger) buffer object */
352
353 BufferObject = AcpiUtCreateBufferObject (
354 ACPI_FDE_DWORD_BUFFER_SIZE);
355 if (!BufferObject)
356 {
357 return (AE_NO_MEMORY);
358 }
359
360 /* Expand each byte to a DWORD */
361
362 ByteBuffer = ReturnObject->Buffer.Pointer;
363 DwordBuffer = ACPI_CAST_PTR (UINT32,
364 BufferObject->Buffer.Pointer);
365
366 for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++)
367 {
368 *DwordBuffer = (UINT32) *ByteBuffer;
369 DwordBuffer++;
370 ByteBuffer++;
371 }
372
373 ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
374 "%s Expanded Byte Buffer to expected DWord Buffer\n",
375 Info->FullPathname));
376 break;
377
378 default:
379
380 return (AE_AML_OPERAND_TYPE);
381 }
382
383 /* Delete the original return object, return the new buffer object */
384
385 AcpiUtRemoveReference (ReturnObject);
386 *ReturnObjectPtr = BufferObject;
387
388 Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
389 return (AE_OK);
390 }
391
392
393 /******************************************************************************
394 *
395 * FUNCTION: AcpiNsRepair_CID
396 *
397 * PARAMETERS: Info - Method execution information block
398 * ReturnObjectPtr - Pointer to the object returned from the
399 * evaluation of a method or object
400 *
401 * RETURN: Status. AE_OK if object is OK or was repaired successfully
402 *
403 * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
404 * letters are uppercase and that there is no leading asterisk.
405 * If a Package, ensure same for all string elements.
406 *
407 *****************************************************************************/
408
409 static ACPI_STATUS
410 AcpiNsRepair_CID (
411 ACPI_EVALUATE_INFO *Info,
412 ACPI_OPERAND_OBJECT **ReturnObjectPtr)
413 {
414 ACPI_STATUS Status;
415 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr;
416 ACPI_OPERAND_OBJECT **ElementPtr;
417 ACPI_OPERAND_OBJECT *OriginalElement;
418 UINT16 OriginalRefCount;
419 UINT32 i;
420
421
422 /* Check for _CID as a simple string */
423
424 if (ReturnObject->Common.Type == ACPI_TYPE_STRING)
425 {
426 Status = AcpiNsRepair_HID (Info, ReturnObjectPtr);
427 return (Status);
428 }
429
430 /* Exit if not a Package */
431
432 if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE)
433 {
434 return (AE_OK);
435 }
436
437 /* Examine each element of the _CID package */
438
439 ElementPtr = ReturnObject->Package.Elements;
440 for (i = 0; i < ReturnObject->Package.Count; i++)
441 {
442 OriginalElement = *ElementPtr;
443 OriginalRefCount = OriginalElement->Common.ReferenceCount;
444
445 Status = AcpiNsRepair_HID (Info, ElementPtr);
446 if (ACPI_FAILURE (Status))
447 {
448 return (Status);
449 }
450
451 if (OriginalElement != *ElementPtr)
452 {
453 /* Update reference count of new object */
454
455 (*ElementPtr)->Common.ReferenceCount =
456 OriginalRefCount;
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,
514 Info->FullPathname, Info->NodeFlags,
515 "SubPackage[%u] - removing entry due to zero count", i));
516 Removing = TRUE;
517 goto RemoveElement;
518 }
519
520 ObjDesc = (*OuterElements)->Package.Elements[1]; /* Index1 = Type */
521 if ((UINT32) ObjDesc->Integer.Value == 0)
522 {
523 ACPI_WARN_PREDEFINED ((AE_INFO,
524 Info->FullPathname, Info->NodeFlags,
525 "SubPackage[%u] - removing entry due to invalid Type(0)", i));
526 Removing = TRUE;
527 }
528
529 RemoveElement:
530 if (Removing)
531 {
532 AcpiNsRemoveElement (ReturnObject, i + 1);
533 OuterElementCount--;
534 }
535 else
536 {
537 i++;
538 }
539 }
540
541 /* Update top-level package count, Type "Integer" checked elsewhere */
542
543 ObjDesc = ReturnObject->Package.Elements[0];
544 ObjDesc->Integer.Value = OuterElementCount;
545
546 /*
547 * Entries (subpackages) in the _CST Package must be sorted by the
548 * C-state type, in ascending order.
549 */
550 Status = AcpiNsCheckSortedList (Info, ReturnObject, 1, 4, 1,
551 ACPI_SORT_ASCENDING, "C-State Type");
552 if (ACPI_FAILURE (Status))
553 {
554 return (Status);
555 }
556
557 return (AE_OK);
558 }
559
560
561 /******************************************************************************
562 *
563 * FUNCTION: AcpiNsRepair_HID
564 *
565 * PARAMETERS: Info - Method execution information block
566 * ReturnObjectPtr - Pointer to the object returned from the
567 * evaluation of a method or object
568 *
569 * RETURN: Status. AE_OK if object is OK or was repaired successfully
570 *
571 * DESCRIPTION: Repair for the _HID object. If a string, ensure that all
572 * letters are uppercase and that there is no leading asterisk.
573 *
574 *****************************************************************************/
575
576 static ACPI_STATUS
577 AcpiNsRepair_HID (
578 ACPI_EVALUATE_INFO *Info,
579 ACPI_OPERAND_OBJECT **ReturnObjectPtr)
580 {
581 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr;
582 ACPI_OPERAND_OBJECT *NewString;
583 char *Source;
584 char *Dest;
585
586
587 ACPI_FUNCTION_NAME (NsRepair_HID);
588
589
590 /* We only care about string _HID objects (not integers) */
591
592 if (ReturnObject->Common.Type != ACPI_TYPE_STRING)
593 {
594 return (AE_OK);
595 }
596
597 if (ReturnObject->String.Length == 0)
598 {
599 ACPI_WARN_PREDEFINED ((AE_INFO,
600 Info->FullPathname, Info->NodeFlags,
601 "Invalid zero-length _HID or _CID string"));
602
603 /* Return AE_OK anyway, let driver handle it */
604
605 Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
606 return (AE_OK);
607 }
608
609 /* It is simplest to always create a new string object */
610
611 NewString = AcpiUtCreateStringObject (ReturnObject->String.Length);
612 if (!NewString)
613 {
614 return (AE_NO_MEMORY);
615 }
616
617 /*
618 * Remove a leading asterisk if present. For some unknown reason, there
619 * are many machines in the field that contains IDs like this.
620 *
621 * Examples: "*PNP0C03", "*ACPI0003"
622 */
623 Source = ReturnObject->String.Pointer;
624 if (*Source == '*')
625 {
626 Source++;
627 NewString->String.Length--;
628
629 ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
630 "%s: Removed invalid leading asterisk\n", Info->FullPathname));
631 }
632
633 /*
634 * Copy and uppercase the string. From the ACPI 5.0 specification:
635 *
636 * A valid PNP ID must be of the form "AAA####" where A is an uppercase
637 * letter and # is a hex digit. A valid ACPI ID must be of the form
638 * "NNNN####" where N is an uppercase letter or decimal digit, and
639 * # is a hex digit.
640 */
641 for (Dest = NewString->String.Pointer; *Source; Dest++, Source++)
642 {
643 *Dest = (char) toupper ((int) *Source);
644 }
645
646 AcpiUtRemoveReference (ReturnObject);
647 *ReturnObjectPtr = NewString;
648 return (AE_OK);
649 }
650
651
652 /******************************************************************************
653 *
654 * FUNCTION: AcpiNsRepair_PRT
655 *
656 * PARAMETERS: Info - Method execution information block
657 * ReturnObjectPtr - Pointer to the object returned from the
658 * evaluation of a method or object
659 *
660 * RETURN: Status. AE_OK if object is OK or was repaired successfully
661 *
662 * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed
663 * SourceName and SourceIndex field, a common BIOS bug.
664 *
665 *****************************************************************************/
666
667 static ACPI_STATUS
668 AcpiNsRepair_PRT (
669 ACPI_EVALUATE_INFO *Info,
670 ACPI_OPERAND_OBJECT **ReturnObjectPtr)
671 {
672 ACPI_OPERAND_OBJECT *PackageObject = *ReturnObjectPtr;
673 ACPI_OPERAND_OBJECT **TopObjectList;
674 ACPI_OPERAND_OBJECT **SubObjectList;
675 ACPI_OPERAND_OBJECT *ObjDesc;
676 ACPI_OPERAND_OBJECT *SubPackage;
677 UINT32 ElementCount;
678 UINT32 Index;
679
680
681 /* Each element in the _PRT package is a subpackage */
682
683 TopObjectList = PackageObject->Package.Elements;
684 ElementCount = PackageObject->Package.Count;
685
686 /* Examine each subpackage */
687
688 for (Index = 0; Index < ElementCount; Index++, TopObjectList++)
689 {
690 SubPackage = *TopObjectList;
691 SubObjectList = SubPackage->Package.Elements;
692
693 /* Check for minimum required element count */
694
695 if (SubPackage->Package.Count < 4)
696 {
697 continue;
698 }
699
700 /*
701 * If the BIOS has erroneously reversed the _PRT SourceName (index 2)
702 * and the SourceIndex (index 3), fix it. _PRT is important enough to
703 * workaround this BIOS error. This also provides compatibility with
704 * other ACPI implementations.
705 */
706 ObjDesc = SubObjectList[3];
707 if (!ObjDesc || (ObjDesc->Common.Type != ACPI_TYPE_INTEGER))
708 {
709 SubObjectList[3] = SubObjectList[2];
710 SubObjectList[2] = ObjDesc;
711 Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
712
713 ACPI_WARN_PREDEFINED ((AE_INFO,
714 Info->FullPathname, Info->NodeFlags,
715 "PRT[%X]: Fixed reversed SourceName and SourceIndex",
716 Index));
717 }
718 }
719
720 return (AE_OK);
721 }
722
723
724 /******************************************************************************
725 *
726 * FUNCTION: AcpiNsRepair_PSS
727 *
728 * PARAMETERS: Info - Method execution information block
729 * ReturnObjectPtr - Pointer to the object returned from the
730 * evaluation of a method or object
731 *
732 * RETURN: Status. AE_OK if object is OK or was repaired successfully
733 *
734 * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list
735 * by the CPU frequencies. Check that the power dissipation values
736 * are all proportional to CPU frequency (i.e., sorting by
737 * frequency should be the same as sorting by power.)
738 *
739 *****************************************************************************/
740
741 static ACPI_STATUS
742 AcpiNsRepair_PSS (
743 ACPI_EVALUATE_INFO *Info,
744 ACPI_OPERAND_OBJECT **ReturnObjectPtr)
745 {
746 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr;
747 ACPI_OPERAND_OBJECT **OuterElements;
748 UINT32 OuterElementCount;
749 ACPI_OPERAND_OBJECT **Elements;
750 ACPI_OPERAND_OBJECT *ObjDesc;
751 UINT32 PreviousValue;
752 ACPI_STATUS Status;
753 UINT32 i;
754
755
756 /*
757 * Entries (subpackages) in the _PSS Package must be sorted by power
758 * dissipation, in descending order. If it appears that the list is
759 * incorrectly sorted, sort it. We sort by CpuFrequency, since this
760 * should be proportional to the power.
761 */
762 Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 6, 0,
763 ACPI_SORT_DESCENDING, "CpuFrequency");
764 if (ACPI_FAILURE (Status))
765 {
766 return (Status);
767 }
768
769 /*
770 * We now know the list is correctly sorted by CPU frequency. Check if
771 * the power dissipation values are proportional.
772 */
773 PreviousValue = ACPI_UINT32_MAX;
774 OuterElements = ReturnObject->Package.Elements;
775 OuterElementCount = ReturnObject->Package.Count;
776
777 for (i = 0; i < OuterElementCount; i++)
778 {
779 Elements = (*OuterElements)->Package.Elements;
780 ObjDesc = Elements[1]; /* Index1 = PowerDissipation */
781
782 if ((UINT32) ObjDesc->Integer.Value > PreviousValue)
783 {
784 ACPI_WARN_PREDEFINED ((AE_INFO,
785 Info->FullPathname, Info->NodeFlags,
786 "SubPackage[%u,%u] - suspicious power dissipation values",
787 i-1, i));
788 }
789
790 PreviousValue = (UINT32) ObjDesc->Integer.Value;
791 OuterElements++;
792 }
793
794 return (AE_OK);
795 }
796
797
798 /******************************************************************************
799 *
800 * FUNCTION: AcpiNsRepair_TSS
801 *
802 * PARAMETERS: Info - Method execution information block
803 * ReturnObjectPtr - Pointer to the object returned from the
804 * evaluation of a method or object
805 *
806 * RETURN: Status. AE_OK if object is OK or was repaired successfully
807 *
808 * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
809 * descending by the power dissipation values.
810 *
811 *****************************************************************************/
812
813 static ACPI_STATUS
814 AcpiNsRepair_TSS (
815 ACPI_EVALUATE_INFO *Info,
816 ACPI_OPERAND_OBJECT **ReturnObjectPtr)
817 {
818 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr;
819 ACPI_STATUS Status;
820 ACPI_NAMESPACE_NODE *Node;
821
822
823 /*
824 * We can only sort the _TSS return package if there is no _PSS in the
825 * same scope. This is because if _PSS is present, the ACPI specification
826 * dictates that the _TSS Power Dissipation field is to be ignored, and
827 * therefore some BIOSs leave garbage values in the _TSS Power field(s).
828 * In this case, it is best to just return the _TSS package as-is.
829 * (May, 2011)
830 */
831 Status = AcpiNsGetNode (Info->Node, "^_PSS",
832 ACPI_NS_NO_UPSEARCH, &Node);
833 if (ACPI_SUCCESS (Status))
834 {
835 return (AE_OK);
836 }
837
838 Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 5, 1,
839 ACPI_SORT_DESCENDING, "PowerDissipation");
840
841 return (Status);
842 }
843
844
845 /******************************************************************************
846 *
847 * FUNCTION: AcpiNsCheckSortedList
848 *
849 * PARAMETERS: Info - Method execution information block
850 * ReturnObject - Pointer to the top-level returned object
851 * StartIndex - Index of the first subpackage
852 * ExpectedCount - Minimum length of each subpackage
853 * SortIndex - Subpackage entry to sort on
854 * SortDirection - Ascending or descending
855 * SortKeyName - Name of the SortIndex field
856 *
857 * RETURN: Status. AE_OK if the list is valid and is sorted correctly or
858 * has been repaired by sorting the list.
859 *
860 * DESCRIPTION: Check if the package list is valid and sorted correctly by the
861 * SortIndex. If not, then sort the list.
862 *
863 *****************************************************************************/
864
865 static ACPI_STATUS
866 AcpiNsCheckSortedList (
867 ACPI_EVALUATE_INFO *Info,
868 ACPI_OPERAND_OBJECT *ReturnObject,
869 UINT32 StartIndex,
870 UINT32 ExpectedCount,
871 UINT32 SortIndex,
872 UINT8 SortDirection,
873 const char *SortKeyName)
874 {
875 UINT32 OuterElementCount;
876 ACPI_OPERAND_OBJECT **OuterElements;
877 ACPI_OPERAND_OBJECT **Elements;
878 ACPI_OPERAND_OBJECT *ObjDesc;
879 UINT32 i;
880 UINT32 PreviousValue;
881
882
883 ACPI_FUNCTION_NAME (NsCheckSortedList);
884
885
886 /* The top-level object must be a package */
887
888 if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE)
889 {
890 return (AE_AML_OPERAND_TYPE);
891 }
892
893 /*
894 * NOTE: assumes list of subpackages contains no NULL elements.
895 * Any NULL elements should have been removed by earlier call
896 * to AcpiNsRemoveNullElements.
897 */
898 OuterElementCount = ReturnObject->Package.Count;
899 if (!OuterElementCount || StartIndex >= OuterElementCount)
900 {
901 return (AE_AML_PACKAGE_LIMIT);
902 }
903
904 OuterElements = &ReturnObject->Package.Elements[StartIndex];
905 OuterElementCount -= StartIndex;
906
907 PreviousValue = 0;
908 if (SortDirection == ACPI_SORT_DESCENDING)
909 {
910 PreviousValue = ACPI_UINT32_MAX;
911 }
912
913 /* Examine each subpackage */
914
915 for (i = 0; i < OuterElementCount; i++)
916 {
917 /* Each element of the top-level package must also be a package */
918
919 if ((*OuterElements)->Common.Type != ACPI_TYPE_PACKAGE)
920 {
921 return (AE_AML_OPERAND_TYPE);
922 }
923
924 /* Each subpackage must have the minimum length */
925
926 if ((*OuterElements)->Package.Count < ExpectedCount)
927 {
928 return (AE_AML_PACKAGE_LIMIT);
929 }
930
931 Elements = (*OuterElements)->Package.Elements;
932 ObjDesc = Elements[SortIndex];
933
934 if (ObjDesc->Common.Type != ACPI_TYPE_INTEGER)
935 {
936 return (AE_AML_OPERAND_TYPE);
937 }
938
939 /*
940 * The list must be sorted in the specified order. If we detect a
941 * discrepancy, sort the entire list.
942 */
943 if (((SortDirection == ACPI_SORT_ASCENDING) &&
944 (ObjDesc->Integer.Value < PreviousValue)) ||
945 ((SortDirection == ACPI_SORT_DESCENDING) &&
946 (ObjDesc->Integer.Value > PreviousValue)))
947 {
948 AcpiNsSortList (&ReturnObject->Package.Elements[StartIndex],
949 OuterElementCount, SortIndex, SortDirection);
950
951 Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
952
953 ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
954 "%s: Repaired unsorted list - now sorted by %s\n",
955 Info->FullPathname, SortKeyName));
956 return (AE_OK);
957 }
958
959 PreviousValue = (UINT32) ObjDesc->Integer.Value;
960 OuterElements++;
961 }
962
963 return (AE_OK);
964 }
965
966
967 /******************************************************************************
968 *
969 * FUNCTION: AcpiNsSortList
970 *
971 * PARAMETERS: Elements - Package object element list
972 * Count - Element count for above
973 * Index - Sort by which package element
974 * SortDirection - Ascending or Descending sort
975 *
976 * RETURN: None
977 *
978 * DESCRIPTION: Sort the objects that are in a package element list.
979 *
980 * NOTE: Assumes that all NULL elements have been removed from the package,
981 * and that all elements have been verified to be of type Integer.
982 *
983 *****************************************************************************/
984
985 static void
986 AcpiNsSortList (
987 ACPI_OPERAND_OBJECT **Elements,
988 UINT32 Count,
989 UINT32 Index,
990 UINT8 SortDirection)
991 {
992 ACPI_OPERAND_OBJECT *ObjDesc1;
993 ACPI_OPERAND_OBJECT *ObjDesc2;
994 ACPI_OPERAND_OBJECT *TempObj;
995 UINT32 i;
996 UINT32 j;
997
998
999 /* Simple bubble sort */
1000
1001 for (i = 1; i < Count; i++)
1002 {
1003 for (j = (Count - 1); j >= i; j--)
1004 {
1005 ObjDesc1 = Elements[j-1]->Package.Elements[Index];
1006 ObjDesc2 = Elements[j]->Package.Elements[Index];
1007
1008 if (((SortDirection == ACPI_SORT_ASCENDING) &&
1009 (ObjDesc1->Integer.Value > ObjDesc2->Integer.Value)) ||
1010
1011 ((SortDirection == ACPI_SORT_DESCENDING) &&
1012 (ObjDesc1->Integer.Value < ObjDesc2->Integer.Value)))
1013 {
1014 TempObj = Elements[j-1];
1015 Elements[j-1] = Elements[j];
1016 Elements[j] = TempObj;
1017 }
1018 }
1019 }
1020 }
1021
1022
1023 /******************************************************************************
1024 *
1025 * FUNCTION: AcpiNsRemoveElement
1026 *
1027 * PARAMETERS: ObjDesc - Package object element list
1028 * Index - Index of element to remove
1029 *
1030 * RETURN: None
1031 *
1032 * DESCRIPTION: Remove the requested element of a package and delete it.
1033 *
1034 *****************************************************************************/
1035
1036 static void
1037 AcpiNsRemoveElement (
1038 ACPI_OPERAND_OBJECT *ObjDesc,
1039 UINT32 Index)
1040 {
1041 ACPI_OPERAND_OBJECT **Source;
1042 ACPI_OPERAND_OBJECT **Dest;
1043 UINT32 Count;
1044 UINT32 NewCount;
1045 UINT32 i;
1046
1047
1048 ACPI_FUNCTION_NAME (NsRemoveElement);
1049
1050
1051 Count = ObjDesc->Package.Count;
1052 NewCount = Count - 1;
1053
1054 Source = ObjDesc->Package.Elements;
1055 Dest = Source;
1056
1057 /* Examine all elements of the package object, remove matched index */
1058
1059 for (i = 0; i < Count; i++)
1060 {
1061 if (i == Index)
1062 {
1063 AcpiUtRemoveReference (*Source); /* Remove one ref for being in pkg */
1064 AcpiUtRemoveReference (*Source);
1065 }
1066 else
1067 {
1068 *Dest = *Source;
1069 Dest++;
1070 }
1071
1072 Source++;
1073 }
1074
1075 /* NULL terminate list and update the package count */
1076
1077 *Dest = NULL;
1078 ObjDesc->Package.Count = NewCount;
1079 }
1080