952 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: nsrepair2 - Repair for objects returned by specific5 * predefined methods6 *7 * Copyright (C) 2000 - 2023, Intel Corp.8 *9 *****************************************************************************/10 11#include <acpi/acpi.h>12#include "accommon.h"13#include "acnamesp.h"14 15#define _COMPONENT ACPI_NAMESPACE16ACPI_MODULE_NAME("nsrepair2")17 18/*19 * Information structure and handler for ACPI predefined names that can20 * be repaired on a per-name basis.21 */22typedef23acpi_status (*acpi_repair_function) (struct acpi_evaluate_info * info,24 union acpi_operand_object **25 return_object_ptr);26 27typedef struct acpi_repair_info {28 char name[ACPI_NAMESEG_SIZE];29 acpi_repair_function repair_function;30 31} acpi_repair_info;32 33/* Local prototypes */34 35static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct36 acpi_namespace_node37 *node);38 39static acpi_status40acpi_ns_repair_ALR(struct acpi_evaluate_info *info,41 union acpi_operand_object **return_object_ptr);42 43static acpi_status44acpi_ns_repair_CID(struct acpi_evaluate_info *info,45 union acpi_operand_object **return_object_ptr);46 47static acpi_status48acpi_ns_repair_CST(struct acpi_evaluate_info *info,49 union acpi_operand_object **return_object_ptr);50 51static acpi_status52acpi_ns_repair_FDE(struct acpi_evaluate_info *info,53 union acpi_operand_object **return_object_ptr);54 55static acpi_status56acpi_ns_repair_HID(struct acpi_evaluate_info *info,57 union acpi_operand_object **return_object_ptr);58 59static acpi_status60acpi_ns_repair_PRT(struct acpi_evaluate_info *info,61 union acpi_operand_object **return_object_ptr);62 63static acpi_status64acpi_ns_repair_PSS(struct acpi_evaluate_info *info,65 union acpi_operand_object **return_object_ptr);66 67static acpi_status68acpi_ns_repair_TSS(struct acpi_evaluate_info *info,69 union acpi_operand_object **return_object_ptr);70 71static acpi_status72acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,73 union acpi_operand_object *return_object,74 u32 start_index,75 u32 expected_count,76 u32 sort_index,77 u8 sort_direction, char *sort_key_name);78 79/* Values for sort_direction above */80 81#define ACPI_SORT_ASCENDING 082#define ACPI_SORT_DESCENDING 183 84static void85acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index);86 87static void88acpi_ns_sort_list(union acpi_operand_object **elements,89 u32 count, u32 index, u8 sort_direction);90 91/*92 * This table contains the names of the predefined methods for which we can93 * perform more complex repairs.94 *95 * As necessary:96 *97 * _ALR: Sort the list ascending by ambient_illuminance98 * _CID: Strings: uppercase all, remove any leading asterisk99 * _CST: Sort the list ascending by C state type100 * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs101 * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs102 * _HID: Strings: uppercase all, remove any leading asterisk103 * _PRT: Fix reversed source_name and source_index104 * _PSS: Sort the list descending by Power105 * _TSS: Sort the list descending by Power106 *107 * Names that must be packages, but cannot be sorted:108 *109 * _BCL: Values are tied to the Package index where they appear, and cannot110 * be moved or sorted. These index values are used for _BQC and _BCM.111 * However, we can fix the case where a buffer is returned, by converting112 * it to a Package of integers.113 */114static const struct acpi_repair_info acpi_ns_repairable_names[] = {115 {"_ALR", acpi_ns_repair_ALR},116 {"_CID", acpi_ns_repair_CID},117 {"_CST", acpi_ns_repair_CST},118 {"_FDE", acpi_ns_repair_FDE},119 {"_GTM", acpi_ns_repair_FDE}, /* _GTM has same repair as _FDE */120 {"_HID", acpi_ns_repair_HID},121 {"_PRT", acpi_ns_repair_PRT},122 {"_PSS", acpi_ns_repair_PSS},123 {"_TSS", acpi_ns_repair_TSS},124 {{0, 0, 0, 0}, NULL} /* Table terminator */125};126 127#define ACPI_FDE_FIELD_COUNT 5128#define ACPI_FDE_BYTE_BUFFER_SIZE 5129#define ACPI_FDE_DWORD_BUFFER_SIZE (ACPI_FDE_FIELD_COUNT * (u32) sizeof (u32))130 131/******************************************************************************132 *133 * FUNCTION: acpi_ns_complex_repairs134 *135 * PARAMETERS: info - Method execution information block136 * node - Namespace node for the method/object137 * validate_status - Original status of earlier validation138 * return_object_ptr - Pointer to the object returned from the139 * evaluation of a method or object140 *141 * RETURN: Status. AE_OK if repair was successful. If name is not142 * matched, validate_status is returned.143 *144 * DESCRIPTION: Attempt to repair/convert a return object of a type that was145 * not expected.146 *147 *****************************************************************************/148 149acpi_status150acpi_ns_complex_repairs(struct acpi_evaluate_info *info,151 struct acpi_namespace_node *node,152 acpi_status validate_status,153 union acpi_operand_object **return_object_ptr)154{155 const struct acpi_repair_info *predefined;156 acpi_status status;157 158 ACPI_FUNCTION_TRACE(ns_complex_repairs);159 160 /* Check if this name is in the list of repairable names */161 162 predefined = acpi_ns_match_complex_repair(node);163 if (!predefined) {164 return_ACPI_STATUS(validate_status);165 }166 167 status = predefined->repair_function(info, return_object_ptr);168 return_ACPI_STATUS(status);169}170 171/******************************************************************************172 *173 * FUNCTION: acpi_ns_match_complex_repair174 *175 * PARAMETERS: node - Namespace node for the method/object176 *177 * RETURN: Pointer to entry in repair table. NULL indicates not found.178 *179 * DESCRIPTION: Check an object name against the repairable object list.180 *181 *****************************************************************************/182 183static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct184 acpi_namespace_node185 *node)186{187 const struct acpi_repair_info *this_name;188 189 /* Search info table for a repairable predefined method/object name */190 191 this_name = acpi_ns_repairable_names;192 while (this_name->repair_function) {193 if (ACPI_COMPARE_NAMESEG(node->name.ascii, this_name->name)) {194 return (this_name);195 }196 197 this_name++;198 }199 200 return (NULL); /* Not found */201}202 203/******************************************************************************204 *205 * FUNCTION: acpi_ns_repair_ALR206 *207 * PARAMETERS: info - Method execution information block208 * return_object_ptr - Pointer to the object returned from the209 * evaluation of a method or object210 *211 * RETURN: Status. AE_OK if object is OK or was repaired successfully212 *213 * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list214 * ascending by the ambient illuminance values.215 *216 *****************************************************************************/217 218static acpi_status219acpi_ns_repair_ALR(struct acpi_evaluate_info *info,220 union acpi_operand_object **return_object_ptr)221{222 union acpi_operand_object *return_object = *return_object_ptr;223 acpi_status status;224 225 status = acpi_ns_check_sorted_list(info, return_object, 0, 2, 1,226 ACPI_SORT_ASCENDING,227 "AmbientIlluminance");228 229 return (status);230}231 232/******************************************************************************233 *234 * FUNCTION: acpi_ns_repair_FDE235 *236 * PARAMETERS: info - Method execution information block237 * return_object_ptr - Pointer to the object returned from the238 * evaluation of a method or object239 *240 * RETURN: Status. AE_OK if object is OK or was repaired successfully241 *242 * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return243 * value is a Buffer of 5 DWORDs. This function repairs a common244 * problem where the return value is a Buffer of BYTEs, not245 * DWORDs.246 *247 *****************************************************************************/248 249static acpi_status250acpi_ns_repair_FDE(struct acpi_evaluate_info *info,251 union acpi_operand_object **return_object_ptr)252{253 union acpi_operand_object *return_object = *return_object_ptr;254 union acpi_operand_object *buffer_object;255 u8 *byte_buffer;256 u32 *dword_buffer;257 u32 i;258 259 ACPI_FUNCTION_NAME(ns_repair_FDE);260 261 switch (return_object->common.type) {262 case ACPI_TYPE_BUFFER:263 264 /* This is the expected type. Length should be (at least) 5 DWORDs */265 266 if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) {267 return (AE_OK);268 }269 270 /* We can only repair if we have exactly 5 BYTEs */271 272 if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) {273 ACPI_WARN_PREDEFINED((AE_INFO,274 info->full_pathname,275 info->node_flags,276 "Incorrect return buffer length %u, expected %u",277 return_object->buffer.length,278 ACPI_FDE_DWORD_BUFFER_SIZE));279 280 return (AE_AML_OPERAND_TYPE);281 }282 283 /* Create the new (larger) buffer object */284 285 buffer_object =286 acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE);287 if (!buffer_object) {288 return (AE_NO_MEMORY);289 }290 291 /* Expand each byte to a DWORD */292 293 byte_buffer = return_object->buffer.pointer;294 dword_buffer = ACPI_CAST_PTR(u32,295 buffer_object->buffer.pointer);296 297 for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) {298 *dword_buffer = (u32) *byte_buffer;299 dword_buffer++;300 byte_buffer++;301 }302 303 ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,304 "%s Expanded Byte Buffer to expected DWord Buffer\n",305 info->full_pathname));306 break;307 308 default:309 310 return (AE_AML_OPERAND_TYPE);311 }312 313 /* Delete the original return object, return the new buffer object */314 315 acpi_ut_remove_reference(return_object);316 *return_object_ptr = buffer_object;317 318 info->return_flags |= ACPI_OBJECT_REPAIRED;319 return (AE_OK);320}321 322/******************************************************************************323 *324 * FUNCTION: acpi_ns_repair_CID325 *326 * PARAMETERS: info - Method execution information block327 * return_object_ptr - Pointer to the object returned from the328 * evaluation of a method or object329 *330 * RETURN: Status. AE_OK if object is OK or was repaired successfully331 *332 * DESCRIPTION: Repair for the _CID object. If a string, ensure that all333 * letters are uppercase and that there is no leading asterisk.334 * If a Package, ensure same for all string elements.335 *336 *****************************************************************************/337 338static acpi_status339acpi_ns_repair_CID(struct acpi_evaluate_info *info,340 union acpi_operand_object **return_object_ptr)341{342 acpi_status status;343 union acpi_operand_object *return_object = *return_object_ptr;344 union acpi_operand_object **element_ptr;345 union acpi_operand_object *original_element;346 u16 original_ref_count;347 u32 i;348 349 ACPI_FUNCTION_TRACE(ns_repair_CID);350 351 /* Check for _CID as a simple string */352 353 if (return_object->common.type == ACPI_TYPE_STRING) {354 status = acpi_ns_repair_HID(info, return_object_ptr);355 return_ACPI_STATUS(status);356 }357 358 /* Exit if not a Package */359 360 if (return_object->common.type != ACPI_TYPE_PACKAGE) {361 return_ACPI_STATUS(AE_OK);362 }363 364 /* Examine each element of the _CID package */365 366 element_ptr = return_object->package.elements;367 for (i = 0; i < return_object->package.count; i++) {368 original_element = *element_ptr;369 original_ref_count = original_element->common.reference_count;370 371 status = acpi_ns_repair_HID(info, element_ptr);372 if (ACPI_FAILURE(status)) {373 return_ACPI_STATUS(status);374 }375 376 if (original_element != *element_ptr) {377 378 /* Update reference count of new object */379 380 (*element_ptr)->common.reference_count =381 original_ref_count;382 }383 384 element_ptr++;385 }386 387 return_ACPI_STATUS(AE_OK);388}389 390/******************************************************************************391 *392 * FUNCTION: acpi_ns_repair_CST393 *394 * PARAMETERS: info - Method execution information block395 * return_object_ptr - Pointer to the object returned from the396 * evaluation of a method or object397 *398 * RETURN: Status. AE_OK if object is OK or was repaired successfully399 *400 * DESCRIPTION: Repair for the _CST object:401 * 1. Sort the list ascending by C state type402 * 2. Ensure type cannot be zero403 * 3. A subpackage count of zero means _CST is meaningless404 * 4. Count must match the number of C state subpackages405 *406 *****************************************************************************/407 408static acpi_status409acpi_ns_repair_CST(struct acpi_evaluate_info *info,410 union acpi_operand_object **return_object_ptr)411{412 union acpi_operand_object *return_object = *return_object_ptr;413 union acpi_operand_object **outer_elements;414 u32 outer_element_count;415 union acpi_operand_object *obj_desc;416 acpi_status status;417 u8 removing;418 u32 i;419 420 ACPI_FUNCTION_NAME(ns_repair_CST);421 422 /*423 * Check if the C-state type values are proportional.424 */425 outer_element_count = return_object->package.count - 1;426 i = 0;427 while (i < outer_element_count) {428 outer_elements = &return_object->package.elements[i + 1];429 removing = FALSE;430 431 if ((*outer_elements)->package.count == 0) {432 ACPI_WARN_PREDEFINED((AE_INFO,433 info->full_pathname,434 info->node_flags,435 "SubPackage[%u] - removing entry due to zero count",436 i));437 removing = TRUE;438 goto remove_element;439 }440 441 obj_desc = (*outer_elements)->package.elements[1]; /* Index1 = Type */442 if ((u32)obj_desc->integer.value == 0) {443 ACPI_WARN_PREDEFINED((AE_INFO,444 info->full_pathname,445 info->node_flags,446 "SubPackage[%u] - removing entry due to invalid Type(0)",447 i));448 removing = TRUE;449 }450 451remove_element:452 if (removing) {453 acpi_ns_remove_element(return_object, i + 1);454 outer_element_count--;455 } else {456 i++;457 }458 }459 460 /* Update top-level package count, Type "Integer" checked elsewhere */461 462 obj_desc = return_object->package.elements[0];463 obj_desc->integer.value = outer_element_count;464 465 /*466 * Entries (subpackages) in the _CST Package must be sorted by the467 * C-state type, in ascending order.468 */469 status = acpi_ns_check_sorted_list(info, return_object, 1, 4, 1,470 ACPI_SORT_ASCENDING, "C-State Type");471 if (ACPI_FAILURE(status)) {472 return (status);473 }474 475 return (AE_OK);476}477 478/******************************************************************************479 *480 * FUNCTION: acpi_ns_repair_HID481 *482 * PARAMETERS: info - Method execution information block483 * return_object_ptr - Pointer to the object returned from the484 * evaluation of a method or object485 *486 * RETURN: Status. AE_OK if object is OK or was repaired successfully487 *488 * DESCRIPTION: Repair for the _HID object. If a string, ensure that all489 * letters are uppercase and that there is no leading asterisk.490 *491 *****************************************************************************/492 493static acpi_status494acpi_ns_repair_HID(struct acpi_evaluate_info *info,495 union acpi_operand_object **return_object_ptr)496{497 union acpi_operand_object *return_object = *return_object_ptr;498 union acpi_operand_object *new_string;499 char *source;500 char *dest;501 502 ACPI_FUNCTION_TRACE(ns_repair_HID);503 504 /* We only care about string _HID objects (not integers) */505 506 if (return_object->common.type != ACPI_TYPE_STRING) {507 return_ACPI_STATUS(AE_OK);508 }509 510 if (return_object->string.length == 0) {511 ACPI_WARN_PREDEFINED((AE_INFO,512 info->full_pathname, info->node_flags,513 "Invalid zero-length _HID or _CID string"));514 515 /* Return AE_OK anyway, let driver handle it */516 517 info->return_flags |= ACPI_OBJECT_REPAIRED;518 return_ACPI_STATUS(AE_OK);519 }520 521 /* It is simplest to always create a new string object */522 523 new_string = acpi_ut_create_string_object(return_object->string.length);524 if (!new_string) {525 return_ACPI_STATUS(AE_NO_MEMORY);526 }527 528 /*529 * Remove a leading asterisk if present. For some unknown reason, there530 * are many machines in the field that contains IDs like this.531 *532 * Examples: "*PNP0C03", "*ACPI0003"533 */534 source = return_object->string.pointer;535 if (*source == '*') {536 source++;537 new_string->string.length--;538 539 ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,540 "%s: Removed invalid leading asterisk\n",541 info->full_pathname));542 }543 544 /*545 * Copy and uppercase the string. From the ACPI 5.0 specification:546 *547 * A valid PNP ID must be of the form "AAA####" where A is an uppercase548 * letter and # is a hex digit. A valid ACPI ID must be of the form549 * "NNNN####" where N is an uppercase letter or decimal digit, and550 * # is a hex digit.551 */552 for (dest = new_string->string.pointer; *source; dest++, source++) {553 *dest = (char)toupper((int)*source);554 }555 556 acpi_ut_remove_reference(return_object);557 *return_object_ptr = new_string;558 return_ACPI_STATUS(AE_OK);559}560 561/******************************************************************************562 *563 * FUNCTION: acpi_ns_repair_PRT564 *565 * PARAMETERS: info - Method execution information block566 * return_object_ptr - Pointer to the object returned from the567 * evaluation of a method or object568 *569 * RETURN: Status. AE_OK if object is OK or was repaired successfully570 *571 * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed572 * source_name and source_index field, a common BIOS bug.573 *574 *****************************************************************************/575 576static acpi_status577acpi_ns_repair_PRT(struct acpi_evaluate_info *info,578 union acpi_operand_object **return_object_ptr)579{580 union acpi_operand_object *package_object = *return_object_ptr;581 union acpi_operand_object **top_object_list;582 union acpi_operand_object **sub_object_list;583 union acpi_operand_object *obj_desc;584 union acpi_operand_object *sub_package;585 u32 element_count;586 u32 index;587 588 /* Each element in the _PRT package is a subpackage */589 590 top_object_list = package_object->package.elements;591 element_count = package_object->package.count;592 593 /* Examine each subpackage */594 595 for (index = 0; index < element_count; index++, top_object_list++) {596 sub_package = *top_object_list;597 sub_object_list = sub_package->package.elements;598 599 /* Check for minimum required element count */600 601 if (sub_package->package.count < 4) {602 continue;603 }604 605 /*606 * If the BIOS has erroneously reversed the _PRT source_name (index 2)607 * and the source_index (index 3), fix it. _PRT is important enough to608 * workaround this BIOS error. This also provides compatibility with609 * other ACPI implementations.610 */611 obj_desc = sub_object_list[3];612 if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) {613 sub_object_list[3] = sub_object_list[2];614 sub_object_list[2] = obj_desc;615 info->return_flags |= ACPI_OBJECT_REPAIRED;616 617 ACPI_WARN_PREDEFINED((AE_INFO,618 info->full_pathname,619 info->node_flags,620 "PRT[%X]: Fixed reversed SourceName and SourceIndex",621 index));622 }623 }624 625 return (AE_OK);626}627 628/******************************************************************************629 *630 * FUNCTION: acpi_ns_repair_PSS631 *632 * PARAMETERS: info - Method execution information block633 * return_object_ptr - Pointer to the object returned from the634 * evaluation of a method or object635 *636 * RETURN: Status. AE_OK if object is OK or was repaired successfully637 *638 * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list639 * by the CPU frequencies. Check that the power dissipation values640 * are all proportional to CPU frequency (i.e., sorting by641 * frequency should be the same as sorting by power.)642 *643 *****************************************************************************/644 645static acpi_status646acpi_ns_repair_PSS(struct acpi_evaluate_info *info,647 union acpi_operand_object **return_object_ptr)648{649 union acpi_operand_object *return_object = *return_object_ptr;650 union acpi_operand_object **outer_elements;651 u32 outer_element_count;652 union acpi_operand_object **elements;653 union acpi_operand_object *obj_desc;654 u32 previous_value;655 acpi_status status;656 u32 i;657 658 /*659 * Entries (subpackages) in the _PSS Package must be sorted by power660 * dissipation, in descending order. If it appears that the list is661 * incorrectly sorted, sort it. We sort by cpu_frequency, since this662 * should be proportional to the power.663 */664 status = acpi_ns_check_sorted_list(info, return_object, 0, 6, 0,665 ACPI_SORT_DESCENDING,666 "CpuFrequency");667 if (ACPI_FAILURE(status)) {668 return (status);669 }670 671 /*672 * We now know the list is correctly sorted by CPU frequency. Check if673 * the power dissipation values are proportional.674 */675 previous_value = ACPI_UINT32_MAX;676 outer_elements = return_object->package.elements;677 outer_element_count = return_object->package.count;678 679 for (i = 0; i < outer_element_count; i++) {680 elements = (*outer_elements)->package.elements;681 obj_desc = elements[1]; /* Index1 = power_dissipation */682 683 if ((u32)obj_desc->integer.value > previous_value) {684 ACPI_WARN_PREDEFINED((AE_INFO,685 info->full_pathname,686 info->node_flags,687 "SubPackage[%u,%u] - suspicious power dissipation values",688 i - 1, i));689 }690 691 previous_value = (u32) obj_desc->integer.value;692 outer_elements++;693 }694 695 return (AE_OK);696}697 698/******************************************************************************699 *700 * FUNCTION: acpi_ns_repair_TSS701 *702 * PARAMETERS: info - Method execution information block703 * return_object_ptr - Pointer to the object returned from the704 * evaluation of a method or object705 *706 * RETURN: Status. AE_OK if object is OK or was repaired successfully707 *708 * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list709 * descending by the power dissipation values.710 *711 *****************************************************************************/712 713static acpi_status714acpi_ns_repair_TSS(struct acpi_evaluate_info *info,715 union acpi_operand_object **return_object_ptr)716{717 union acpi_operand_object *return_object = *return_object_ptr;718 acpi_status status;719 struct acpi_namespace_node *node;720 721 /*722 * We can only sort the _TSS return package if there is no _PSS in the723 * same scope. This is because if _PSS is present, the ACPI specification724 * dictates that the _TSS Power Dissipation field is to be ignored, and725 * therefore some BIOSs leave garbage values in the _TSS Power field(s).726 * In this case, it is best to just return the _TSS package as-is.727 * (May, 2011)728 */729 status = acpi_ns_get_node(info->node, "^_PSS",730 ACPI_NS_NO_UPSEARCH, &node);731 if (ACPI_SUCCESS(status)) {732 return (AE_OK);733 }734 735 status = acpi_ns_check_sorted_list(info, return_object, 0, 5, 1,736 ACPI_SORT_DESCENDING,737 "PowerDissipation");738 739 return (status);740}741 742/******************************************************************************743 *744 * FUNCTION: acpi_ns_check_sorted_list745 *746 * PARAMETERS: info - Method execution information block747 * return_object - Pointer to the top-level returned object748 * start_index - Index of the first subpackage749 * expected_count - Minimum length of each subpackage750 * sort_index - Subpackage entry to sort on751 * sort_direction - Ascending or descending752 * sort_key_name - Name of the sort_index field753 *754 * RETURN: Status. AE_OK if the list is valid and is sorted correctly or755 * has been repaired by sorting the list.756 *757 * DESCRIPTION: Check if the package list is valid and sorted correctly by the758 * sort_index. If not, then sort the list.759 *760 *****************************************************************************/761 762static acpi_status763acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,764 union acpi_operand_object *return_object,765 u32 start_index,766 u32 expected_count,767 u32 sort_index,768 u8 sort_direction, char *sort_key_name)769{770 u32 outer_element_count;771 union acpi_operand_object **outer_elements;772 union acpi_operand_object **elements;773 union acpi_operand_object *obj_desc;774 u32 i;775 u32 previous_value;776 777 ACPI_FUNCTION_NAME(ns_check_sorted_list);778 779 /* The top-level object must be a package */780 781 if (return_object->common.type != ACPI_TYPE_PACKAGE) {782 return (AE_AML_OPERAND_TYPE);783 }784 785 /*786 * NOTE: assumes list of subpackages contains no NULL elements.787 * Any NULL elements should have been removed by earlier call788 * to acpi_ns_remove_null_elements.789 */790 outer_element_count = return_object->package.count;791 if (!outer_element_count || start_index >= outer_element_count) {792 return (AE_AML_PACKAGE_LIMIT);793 }794 795 outer_elements = &return_object->package.elements[start_index];796 outer_element_count -= start_index;797 798 previous_value = 0;799 if (sort_direction == ACPI_SORT_DESCENDING) {800 previous_value = ACPI_UINT32_MAX;801 }802 803 /* Examine each subpackage */804 805 for (i = 0; i < outer_element_count; i++) {806 807 /* Each element of the top-level package must also be a package */808 809 if ((*outer_elements)->common.type != ACPI_TYPE_PACKAGE) {810 return (AE_AML_OPERAND_TYPE);811 }812 813 /* Each subpackage must have the minimum length */814 815 if ((*outer_elements)->package.count < expected_count) {816 return (AE_AML_PACKAGE_LIMIT);817 }818 819 elements = (*outer_elements)->package.elements;820 obj_desc = elements[sort_index];821 822 if (obj_desc->common.type != ACPI_TYPE_INTEGER) {823 return (AE_AML_OPERAND_TYPE);824 }825 826 /*827 * The list must be sorted in the specified order. If we detect a828 * discrepancy, sort the entire list.829 */830 if (((sort_direction == ACPI_SORT_ASCENDING) &&831 (obj_desc->integer.value < previous_value)) ||832 ((sort_direction == ACPI_SORT_DESCENDING) &&833 (obj_desc->integer.value > previous_value))) {834 acpi_ns_sort_list(&return_object->package.835 elements[start_index],836 outer_element_count, sort_index,837 sort_direction);838 839 info->return_flags |= ACPI_OBJECT_REPAIRED;840 841 ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,842 "%s: Repaired unsorted list - now sorted by %s\n",843 info->full_pathname, sort_key_name));844 return (AE_OK);845 }846 847 previous_value = (u32) obj_desc->integer.value;848 outer_elements++;849 }850 851 return (AE_OK);852}853 854/******************************************************************************855 *856 * FUNCTION: acpi_ns_sort_list857 *858 * PARAMETERS: elements - Package object element list859 * count - Element count for above860 * index - Sort by which package element861 * sort_direction - Ascending or Descending sort862 *863 * RETURN: None864 *865 * DESCRIPTION: Sort the objects that are in a package element list.866 *867 * NOTE: Assumes that all NULL elements have been removed from the package,868 * and that all elements have been verified to be of type Integer.869 *870 *****************************************************************************/871 872static void873acpi_ns_sort_list(union acpi_operand_object **elements,874 u32 count, u32 index, u8 sort_direction)875{876 union acpi_operand_object *obj_desc1;877 union acpi_operand_object *obj_desc2;878 union acpi_operand_object *temp_obj;879 u32 i;880 u32 j;881 882 /* Simple bubble sort */883 884 for (i = 1; i < count; i++) {885 for (j = (count - 1); j >= i; j--) {886 obj_desc1 = elements[j - 1]->package.elements[index];887 obj_desc2 = elements[j]->package.elements[index];888 889 if (((sort_direction == ACPI_SORT_ASCENDING) &&890 (obj_desc1->integer.value >891 obj_desc2->integer.value))892 || ((sort_direction == ACPI_SORT_DESCENDING)893 && (obj_desc1->integer.value <894 obj_desc2->integer.value))) {895 temp_obj = elements[j - 1];896 elements[j - 1] = elements[j];897 elements[j] = temp_obj;898 }899 }900 }901}902 903/******************************************************************************904 *905 * FUNCTION: acpi_ns_remove_element906 *907 * PARAMETERS: obj_desc - Package object element list908 * index - Index of element to remove909 *910 * RETURN: None911 *912 * DESCRIPTION: Remove the requested element of a package and delete it.913 *914 *****************************************************************************/915 916static void917acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index)918{919 union acpi_operand_object **source;920 union acpi_operand_object **dest;921 u32 count;922 u32 new_count;923 u32 i;924 925 ACPI_FUNCTION_NAME(ns_remove_element);926 927 count = obj_desc->package.count;928 new_count = count - 1;929 930 source = obj_desc->package.elements;931 dest = source;932 933 /* Examine all elements of the package object, remove matched index */934 935 for (i = 0; i < count; i++) {936 if (i == index) {937 acpi_ut_remove_reference(*source); /* Remove one ref for being in pkg */938 acpi_ut_remove_reference(*source);939 } else {940 *dest = *source;941 dest++;942 }943 944 source++;945 }946 947 /* NULL terminate list and update the package count */948 949 *dest = NULL;950 obj_desc->package.count = new_count;951}952