root/drivers/acpi/acpica/nsrepair2.c
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/******************************************************************************
 *
 * Module Name: nsrepair2 - Repair for objects returned by specific
 *                          predefined methods
 *
 * Copyright (C) 2000 - 2026, Intel Corp.
 *
 *****************************************************************************/

#include <acpi/acpi.h>
#include "accommon.h"
#include "acnamesp.h"

#define _COMPONENT          ACPI_NAMESPACE
ACPI_MODULE_NAME("nsrepair2")

/*
 * Information structure and handler for ACPI predefined names that can
 * be repaired on a per-name basis.
 */
typedef
acpi_status (*acpi_repair_function) (struct acpi_evaluate_info * info,
                                     union acpi_operand_object **
                                     return_object_ptr);

typedef struct acpi_repair_info {
        char name[ACPI_NAMESEG_SIZE] ACPI_NONSTRING;
        acpi_repair_function repair_function;

} acpi_repair_info;

/* Local prototypes */

static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
                                                                   acpi_namespace_node
                                                                   *node);

static acpi_status
acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr);

static acpi_status
acpi_ns_repair_CID(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr);

static acpi_status
acpi_ns_repair_CST(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr);

static acpi_status
acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr);

static acpi_status
acpi_ns_repair_HID(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr);

static acpi_status
acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr);

static acpi_status
acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr);

static acpi_status
acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr);

static acpi_status
acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
                          union acpi_operand_object *return_object,
                          u32 start_index,
                          u32 expected_count,
                          u32 sort_index,
                          u8 sort_direction, char *sort_key_name);

/* Values for sort_direction above */

#define ACPI_SORT_ASCENDING     0
#define ACPI_SORT_DESCENDING    1

static void
acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index);

static void
acpi_ns_sort_list(union acpi_operand_object **elements,
                  u32 count, u32 index, u8 sort_direction);

/*
 * This table contains the names of the predefined methods for which we can
 * perform more complex repairs.
 *
 * As necessary:
 *
 * _ALR: Sort the list ascending by ambient_illuminance
 * _CID: Strings: uppercase all, remove any leading asterisk
 * _CST: Sort the list ascending by C state type
 * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
 * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
 * _HID: Strings: uppercase all, remove any leading asterisk
 * _PRT: Fix reversed source_name and source_index
 * _PSS: Sort the list descending by Power
 * _TSS: Sort the list descending by Power
 *
 * Names that must be packages, but cannot be sorted:
 *
 * _BCL: Values are tied to the Package index where they appear, and cannot
 * be moved or sorted. These index values are used for _BQC and _BCM.
 * However, we can fix the case where a buffer is returned, by converting
 * it to a Package of integers.
 */
static const struct acpi_repair_info acpi_ns_repairable_names[] = {
        {"_ALR", acpi_ns_repair_ALR},
        {"_CID", acpi_ns_repair_CID},
        {"_CST", acpi_ns_repair_CST},
        {"_FDE", acpi_ns_repair_FDE},
        {"_GTM", acpi_ns_repair_FDE},   /* _GTM has same repair as _FDE */
        {"_HID", acpi_ns_repair_HID},
        {"_PRT", acpi_ns_repair_PRT},
        {"_PSS", acpi_ns_repair_PSS},
        {"_TSS", acpi_ns_repair_TSS},
        {{0, 0, 0, 0}, NULL}    /* Table terminator */
};

#define ACPI_FDE_FIELD_COUNT        5
#define ACPI_FDE_BYTE_BUFFER_SIZE   5
#define ACPI_FDE_DWORD_BUFFER_SIZE  (ACPI_FDE_FIELD_COUNT * (u32) sizeof (u32))

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_complex_repairs
 *
 * PARAMETERS:  info                - Method execution information block
 *              node                - Namespace node for the method/object
 *              validate_status     - Original status of earlier validation
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if repair was successful. If name is not
 *              matched, validate_status is returned.
 *
 * DESCRIPTION: Attempt to repair/convert a return object of a type that was
 *              not expected.
 *
 *****************************************************************************/

acpi_status
acpi_ns_complex_repairs(struct acpi_evaluate_info *info,
                        struct acpi_namespace_node *node,
                        acpi_status validate_status,
                        union acpi_operand_object **return_object_ptr)
{
        const struct acpi_repair_info *predefined;
        acpi_status status;

        ACPI_FUNCTION_TRACE(ns_complex_repairs);

        /* Check if this name is in the list of repairable names */

        predefined = acpi_ns_match_complex_repair(node);
        if (!predefined) {
                return_ACPI_STATUS(validate_status);
        }

        status = predefined->repair_function(info, return_object_ptr);
        return_ACPI_STATUS(status);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_match_complex_repair
 *
 * PARAMETERS:  node                - Namespace node for the method/object
 *
 * RETURN:      Pointer to entry in repair table. NULL indicates not found.
 *
 * DESCRIPTION: Check an object name against the repairable object list.
 *
 *****************************************************************************/

static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
                                                                   acpi_namespace_node
                                                                   *node)
{
        const struct acpi_repair_info *this_name;

        /* Search info table for a repairable predefined method/object name */

        this_name = acpi_ns_repairable_names;
        while (this_name->repair_function) {
                if (ACPI_COMPARE_NAMESEG(node->name.ascii, this_name->name)) {
                        return (this_name);
                }

                this_name++;
        }

        return (NULL);          /* Not found */
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_ALR
 *
 * PARAMETERS:  info                - Method execution information block
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list
 *              ascending by the ambient illuminance values.
 *
 *****************************************************************************/

static acpi_status
acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr)
{
        union acpi_operand_object *return_object = *return_object_ptr;
        acpi_status status;

        status = acpi_ns_check_sorted_list(info, return_object, 0, 2, 1,
                                           ACPI_SORT_ASCENDING,
                                           "AmbientIlluminance");

        return (status);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_FDE
 *
 * PARAMETERS:  info                - Method execution information block
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return
 *              value is a Buffer of 5 DWORDs. This function repairs a common
 *              problem where the return value is a Buffer of BYTEs, not
 *              DWORDs.
 *
 *****************************************************************************/

static acpi_status
acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr)
{
        union acpi_operand_object *return_object = *return_object_ptr;
        union acpi_operand_object *buffer_object;
        u8 *byte_buffer;
        u32 *dword_buffer;
        u32 i;

        ACPI_FUNCTION_NAME(ns_repair_FDE);

        switch (return_object->common.type) {
        case ACPI_TYPE_BUFFER:

                /* This is the expected type. Length should be (at least) 5 DWORDs */

                if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) {
                        return (AE_OK);
                }

                /* We can only repair if we have exactly 5 BYTEs */

                if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) {
                        ACPI_WARN_PREDEFINED((AE_INFO,
                                              info->full_pathname,
                                              info->node_flags,
                                              "Incorrect return buffer length %u, expected %u",
                                              return_object->buffer.length,
                                              ACPI_FDE_DWORD_BUFFER_SIZE));

                        return (AE_AML_OPERAND_TYPE);
                }

                /* Create the new (larger) buffer object */

                buffer_object =
                    acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE);
                if (!buffer_object) {
                        return (AE_NO_MEMORY);
                }

                /* Expand each byte to a DWORD */

                byte_buffer = return_object->buffer.pointer;
                dword_buffer = ACPI_CAST_PTR(u32,
                                             buffer_object->buffer.pointer);

                for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) {
                        *dword_buffer = (u32) *byte_buffer;
                        dword_buffer++;
                        byte_buffer++;
                }

                ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
                                  "%s Expanded Byte Buffer to expected DWord Buffer\n",
                                  info->full_pathname));
                break;

        default:

                return (AE_AML_OPERAND_TYPE);
        }

        /* Delete the original return object, return the new buffer object */

        acpi_ut_remove_reference(return_object);
        *return_object_ptr = buffer_object;

        info->return_flags |= ACPI_OBJECT_REPAIRED;
        return (AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_CID
 *
 * PARAMETERS:  info                - Method execution information block
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
 *              letters are uppercase and that there is no leading asterisk.
 *              If a Package, ensure same for all string elements.
 *
 *****************************************************************************/

static acpi_status
acpi_ns_repair_CID(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr)
{
        acpi_status status;
        union acpi_operand_object *return_object = *return_object_ptr;
        union acpi_operand_object **element_ptr;
        union acpi_operand_object *original_element;
        u16 original_ref_count;
        u32 i;

        ACPI_FUNCTION_TRACE(ns_repair_CID);

        /* Check for _CID as a simple string */

        if (return_object->common.type == ACPI_TYPE_STRING) {
                status = acpi_ns_repair_HID(info, return_object_ptr);
                return_ACPI_STATUS(status);
        }

        /* Exit if not a Package */

        if (return_object->common.type != ACPI_TYPE_PACKAGE) {
                return_ACPI_STATUS(AE_OK);
        }

        /* Examine each element of the _CID package */

        element_ptr = return_object->package.elements;
        for (i = 0; i < return_object->package.count; i++) {
                original_element = *element_ptr;
                original_ref_count = original_element->common.reference_count;

                status = acpi_ns_repair_HID(info, element_ptr);
                if (ACPI_FAILURE(status)) {
                        return_ACPI_STATUS(status);
                }

                if (original_element != *element_ptr) {

                        /* Update reference count of new object */

                        (*element_ptr)->common.reference_count =
                            original_ref_count;
                }

                element_ptr++;
        }

        return_ACPI_STATUS(AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_CST
 *
 * PARAMETERS:  info                - Method execution information block
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _CST object:
 *              1. Sort the list ascending by C state type
 *              2. Ensure type cannot be zero
 *              3. A subpackage count of zero means _CST is meaningless
 *              4. Count must match the number of C state subpackages
 *
 *****************************************************************************/

static acpi_status
acpi_ns_repair_CST(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr)
{
        union acpi_operand_object *return_object = *return_object_ptr;
        union acpi_operand_object **outer_elements;
        u32 outer_element_count;
        union acpi_operand_object *obj_desc;
        acpi_status status;
        u8 removing;
        u32 i;

        ACPI_FUNCTION_NAME(ns_repair_CST);

        /*
         * Check if the C-state type values are proportional.
         */
        outer_element_count = return_object->package.count - 1;
        i = 0;
        while (i < outer_element_count) {
                outer_elements = &return_object->package.elements[i + 1];
                removing = FALSE;

                if ((*outer_elements)->package.count == 0) {
                        ACPI_WARN_PREDEFINED((AE_INFO,
                                              info->full_pathname,
                                              info->node_flags,
                                              "SubPackage[%u] - removing entry due to zero count",
                                              i));
                        removing = TRUE;
                        goto remove_element;
                }

                obj_desc = (*outer_elements)->package.elements[1];      /* Index1 = Type */
                if ((u32)obj_desc->integer.value == 0) {
                        ACPI_WARN_PREDEFINED((AE_INFO,
                                              info->full_pathname,
                                              info->node_flags,
                                              "SubPackage[%u] - removing entry due to invalid Type(0)",
                                              i));
                        removing = TRUE;
                }

remove_element:
                if (removing) {
                        acpi_ns_remove_element(return_object, i + 1);
                        outer_element_count--;
                } else {
                        i++;
                }
        }

        /* Update top-level package count, Type "Integer" checked elsewhere */

        obj_desc = return_object->package.elements[0];
        obj_desc->integer.value = outer_element_count;

        /*
         * Entries (subpackages) in the _CST Package must be sorted by the
         * C-state type, in ascending order.
         */
        status = acpi_ns_check_sorted_list(info, return_object, 1, 4, 1,
                                           ACPI_SORT_ASCENDING, "C-State Type");
        if (ACPI_FAILURE(status)) {
                return (status);
        }

        return (AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_HID
 *
 * PARAMETERS:  info                - Method execution information block
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _HID object. If a string, ensure that all
 *              letters are uppercase and that there is no leading asterisk.
 *
 *****************************************************************************/

static acpi_status
acpi_ns_repair_HID(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr)
{
        union acpi_operand_object *return_object = *return_object_ptr;
        union acpi_operand_object *new_string;
        char *source;
        char *dest;

        ACPI_FUNCTION_TRACE(ns_repair_HID);

        /* We only care about string _HID objects (not integers) */

        if (return_object->common.type != ACPI_TYPE_STRING) {
                return_ACPI_STATUS(AE_OK);
        }

        if (return_object->string.length == 0) {
                ACPI_WARN_PREDEFINED((AE_INFO,
                                      info->full_pathname, info->node_flags,
                                      "Invalid zero-length _HID or _CID string"));

                /* Return AE_OK anyway, let driver handle it */

                info->return_flags |= ACPI_OBJECT_REPAIRED;
                return_ACPI_STATUS(AE_OK);
        }

        /* It is simplest to always create a new string object */

        new_string = acpi_ut_create_string_object(return_object->string.length);
        if (!new_string) {
                return_ACPI_STATUS(AE_NO_MEMORY);
        }

        /*
         * Remove a leading asterisk if present. For some unknown reason, there
         * are many machines in the field that contains IDs like this.
         *
         * Examples: "*PNP0C03", "*ACPI0003"
         */
        source = return_object->string.pointer;
        if (*source == '*') {
                source++;
                new_string->string.length--;

                ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
                                  "%s: Removed invalid leading asterisk\n",
                                  info->full_pathname));
        }

        /*
         * Copy and uppercase the string. From the ACPI 5.0 specification:
         *
         * A valid PNP ID must be of the form "AAA####" where A is an uppercase
         * letter and # is a hex digit. A valid ACPI ID must be of the form
         * "NNNN####" where N is an uppercase letter or decimal digit, and
         * # is a hex digit.
         */
        for (dest = new_string->string.pointer; *source; dest++, source++) {
                *dest = (char)toupper((int)*source);
        }

        acpi_ut_remove_reference(return_object);
        *return_object_ptr = new_string;
        return_ACPI_STATUS(AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_PRT
 *
 * PARAMETERS:  info                - Method execution information block
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed
 *              source_name and source_index field, a common BIOS bug.
 *
 *****************************************************************************/

static acpi_status
acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr)
{
        union acpi_operand_object *package_object = *return_object_ptr;
        union acpi_operand_object **top_object_list;
        union acpi_operand_object **sub_object_list;
        union acpi_operand_object *obj_desc;
        union acpi_operand_object *sub_package;
        u32 element_count;
        u32 index;

        /* Each element in the _PRT package is a subpackage */

        top_object_list = package_object->package.elements;
        element_count = package_object->package.count;

        /* Examine each subpackage */

        for (index = 0; index < element_count; index++, top_object_list++) {
                sub_package = *top_object_list;
                sub_object_list = sub_package->package.elements;

                /* Check for minimum required element count */

                if (sub_package->package.count < 4) {
                        continue;
                }

                /*
                 * If the BIOS has erroneously reversed the _PRT source_name (index 2)
                 * and the source_index (index 3), fix it. _PRT is important enough to
                 * workaround this BIOS error. This also provides compatibility with
                 * other ACPI implementations.
                 */
                obj_desc = sub_object_list[3];
                if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) {
                        sub_object_list[3] = sub_object_list[2];
                        sub_object_list[2] = obj_desc;
                        info->return_flags |= ACPI_OBJECT_REPAIRED;

                        ACPI_WARN_PREDEFINED((AE_INFO,
                                              info->full_pathname,
                                              info->node_flags,
                                              "PRT[%X]: Fixed reversed SourceName and SourceIndex",
                                              index));
                }
        }

        return (AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_PSS
 *
 * PARAMETERS:  info                - Method execution information block
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list
 *              by the CPU frequencies. Check that the power dissipation values
 *              are all proportional to CPU frequency (i.e., sorting by
 *              frequency should be the same as sorting by power.)
 *
 *****************************************************************************/

static acpi_status
acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr)
{
        union acpi_operand_object *return_object = *return_object_ptr;
        union acpi_operand_object **outer_elements;
        u32 outer_element_count;
        union acpi_operand_object **elements;
        union acpi_operand_object *obj_desc;
        u32 previous_value;
        acpi_status status;
        u32 i;

        /*
         * Entries (subpackages) in the _PSS Package must be sorted by power
         * dissipation, in descending order. If it appears that the list is
         * incorrectly sorted, sort it. We sort by cpu_frequency, since this
         * should be proportional to the power.
         */
        status = acpi_ns_check_sorted_list(info, return_object, 0, 6, 0,
                                           ACPI_SORT_DESCENDING,
                                           "CpuFrequency");
        if (ACPI_FAILURE(status)) {
                return (status);
        }

        /*
         * We now know the list is correctly sorted by CPU frequency. Check if
         * the power dissipation values are proportional.
         */
        previous_value = ACPI_UINT32_MAX;
        outer_elements = return_object->package.elements;
        outer_element_count = return_object->package.count;

        for (i = 0; i < outer_element_count; i++) {
                elements = (*outer_elements)->package.elements;
                obj_desc = elements[1]; /* Index1 = power_dissipation */

                if ((u32)obj_desc->integer.value > previous_value) {
                        ACPI_WARN_PREDEFINED((AE_INFO,
                                              info->full_pathname,
                                              info->node_flags,
                                              "SubPackage[%u,%u] - suspicious power dissipation values",
                                              i - 1, i));
                }

                previous_value = (u32) obj_desc->integer.value;
                outer_elements++;
        }

        return (AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_TSS
 *
 * PARAMETERS:  info                - Method execution information block
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
 *              descending by the power dissipation values.
 *
 *****************************************************************************/

static acpi_status
acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr)
{
        union acpi_operand_object *return_object = *return_object_ptr;
        acpi_status status;
        struct acpi_namespace_node *node;

        /*
         * We can only sort the _TSS return package if there is no _PSS in the
         * same scope. This is because if _PSS is present, the ACPI specification
         * dictates that the _TSS Power Dissipation field is to be ignored, and
         * therefore some BIOSs leave garbage values in the _TSS Power field(s).
         * In this case, it is best to just return the _TSS package as-is.
         * (May, 2011)
         */
        status = acpi_ns_get_node(info->node, "^_PSS",
                                  ACPI_NS_NO_UPSEARCH, &node);
        if (ACPI_SUCCESS(status)) {
                return (AE_OK);
        }

        status = acpi_ns_check_sorted_list(info, return_object, 0, 5, 1,
                                           ACPI_SORT_DESCENDING,
                                           "PowerDissipation");

        return (status);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_check_sorted_list
 *
 * PARAMETERS:  info                - Method execution information block
 *              return_object       - Pointer to the top-level returned object
 *              start_index         - Index of the first subpackage
 *              expected_count      - Minimum length of each subpackage
 *              sort_index          - Subpackage entry to sort on
 *              sort_direction      - Ascending or descending
 *              sort_key_name       - Name of the sort_index field
 *
 * RETURN:      Status. AE_OK if the list is valid and is sorted correctly or
 *              has been repaired by sorting the list.
 *
 * DESCRIPTION: Check if the package list is valid and sorted correctly by the
 *              sort_index. If not, then sort the list.
 *
 *****************************************************************************/

static acpi_status
acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
                          union acpi_operand_object *return_object,
                          u32 start_index,
                          u32 expected_count,
                          u32 sort_index,
                          u8 sort_direction, char *sort_key_name)
{
        u32 outer_element_count;
        union acpi_operand_object **outer_elements;
        union acpi_operand_object **elements;
        union acpi_operand_object *obj_desc;
        u32 i;
        u32 previous_value;

        ACPI_FUNCTION_NAME(ns_check_sorted_list);

        /* The top-level object must be a package */

        if (return_object->common.type != ACPI_TYPE_PACKAGE) {
                return (AE_AML_OPERAND_TYPE);
        }

        /*
         * NOTE: assumes list of subpackages contains no NULL elements.
         * Any NULL elements should have been removed by earlier call
         * to acpi_ns_remove_null_elements.
         */
        outer_element_count = return_object->package.count;
        if (!outer_element_count || start_index >= outer_element_count) {
                return (AE_AML_PACKAGE_LIMIT);
        }

        outer_elements = &return_object->package.elements[start_index];
        outer_element_count -= start_index;

        previous_value = 0;
        if (sort_direction == ACPI_SORT_DESCENDING) {
                previous_value = ACPI_UINT32_MAX;
        }

        /* Examine each subpackage */

        for (i = 0; i < outer_element_count; i++) {

                /* Each element of the top-level package must also be a package */

                if ((*outer_elements)->common.type != ACPI_TYPE_PACKAGE) {
                        return (AE_AML_OPERAND_TYPE);
                }

                /* Each subpackage must have the minimum length */

                if ((*outer_elements)->package.count < expected_count) {
                        return (AE_AML_PACKAGE_LIMIT);
                }

                elements = (*outer_elements)->package.elements;
                obj_desc = elements[sort_index];

                if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
                        return (AE_AML_OPERAND_TYPE);
                }

                /*
                 * The list must be sorted in the specified order. If we detect a
                 * discrepancy, sort the entire list.
                 */
                if (((sort_direction == ACPI_SORT_ASCENDING) &&
                     (obj_desc->integer.value < previous_value)) ||
                    ((sort_direction == ACPI_SORT_DESCENDING) &&
                     (obj_desc->integer.value > previous_value))) {
                        acpi_ns_sort_list(&return_object->package.
                                          elements[start_index],
                                          outer_element_count, sort_index,
                                          sort_direction);

                        info->return_flags |= ACPI_OBJECT_REPAIRED;

                        ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
                                          "%s: Repaired unsorted list - now sorted by %s\n",
                                          info->full_pathname, sort_key_name));
                        return (AE_OK);
                }

                previous_value = (u32) obj_desc->integer.value;
                outer_elements++;
        }

        return (AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_sort_list
 *
 * PARAMETERS:  elements            - Package object element list
 *              count               - Element count for above
 *              index               - Sort by which package element
 *              sort_direction      - Ascending or Descending sort
 *
 * RETURN:      None
 *
 * DESCRIPTION: Sort the objects that are in a package element list.
 *
 * NOTE: Assumes that all NULL elements have been removed from the package,
 *       and that all elements have been verified to be of type Integer.
 *
 *****************************************************************************/

static void
acpi_ns_sort_list(union acpi_operand_object **elements,
                  u32 count, u32 index, u8 sort_direction)
{
        union acpi_operand_object *obj_desc1;
        union acpi_operand_object *obj_desc2;
        union acpi_operand_object *temp_obj;
        u32 i;
        u32 j;

        /* Simple bubble sort */

        for (i = 1; i < count; i++) {
                for (j = (count - 1); j >= i; j--) {
                        obj_desc1 = elements[j - 1]->package.elements[index];
                        obj_desc2 = elements[j]->package.elements[index];

                        if (((sort_direction == ACPI_SORT_ASCENDING) &&
                             (obj_desc1->integer.value >
                              obj_desc2->integer.value))
                            || ((sort_direction == ACPI_SORT_DESCENDING)
                                && (obj_desc1->integer.value <
                                    obj_desc2->integer.value))) {
                                temp_obj = elements[j - 1];
                                elements[j - 1] = elements[j];
                                elements[j] = temp_obj;
                        }
                }
        }
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_remove_element
 *
 * PARAMETERS:  obj_desc            - Package object element list
 *              index               - Index of element to remove
 *
 * RETURN:      None
 *
 * DESCRIPTION: Remove the requested element of a package and delete it.
 *
 *****************************************************************************/

static void
acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index)
{
        union acpi_operand_object **source;
        union acpi_operand_object **dest;
        u32 count;
        u32 new_count;
        u32 i;

        ACPI_FUNCTION_NAME(ns_remove_element);

        count = obj_desc->package.count;
        new_count = count - 1;

        source = obj_desc->package.elements;
        dest = source;

        /* Examine all elements of the package object, remove matched index */

        for (i = 0; i < count; i++) {
                if (i == index) {
                        acpi_ut_remove_reference(*source);      /* Remove one ref for being in pkg */
                        acpi_ut_remove_reference(*source);
                } else {
                        *dest = *source;
                        dest++;
                }

                source++;
        }

        /* NULL terminate list and update the package count */

        *dest = NULL;
        obj_desc->package.count = new_count;
}