Beispiel #1
0
static ACPI_STATUS
AcpiNsCheckPackage (
    ACPI_PREDEFINED_DATA        *Data,
    ACPI_OPERAND_OBJECT         **ReturnObjectPtr)
{
    ACPI_OPERAND_OBJECT         *ReturnObject = *ReturnObjectPtr;
    const ACPI_PREDEFINED_INFO  *Package;
    ACPI_OPERAND_OBJECT         **Elements;
    ACPI_STATUS                 Status = AE_OK;
    UINT32                      ExpectedCount;
    UINT32                      Count;
    UINT32                      i;


    ACPI_FUNCTION_NAME (NsCheckPackage);


    /* The package info for this name is in the next table entry */

    Package = Data->Predefined + 1;

    ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
                       "%s Validating return Package of Type %X, Count %X\n",
                       Data->Pathname, Package->RetInfo.Type, ReturnObject->Package.Count));

    /*
     * For variable-length Packages, we can safely remove all embedded
     * and trailing NULL package elements
     */
    AcpiNsRemoveNullElements (Data, Package->RetInfo.Type, ReturnObject);

    /* Extract package count and elements array */

    Elements = ReturnObject->Package.Elements;
    Count = ReturnObject->Package.Count;

    /* The package must have at least one element, else invalid */

    if (!Count)
    {
        ACPI_WARN_PREDEFINED ((AE_INFO, Data->Pathname, Data->NodeFlags,
                               "Return Package has no elements (empty)"));

        return (AE_AML_OPERAND_VALUE);
    }

    /*
     * Decode the type of the expected package contents
     *
     * PTYPE1 packages contain no subpackages
     * PTYPE2 packages contain sub-packages
     */
    switch (Package->RetInfo.Type)
    {
    case ACPI_PTYPE1_FIXED:

        /*
         * The package count is fixed and there are no sub-packages
         *
         * If package is too small, exit.
         * If package is larger than expected, issue warning but continue
         */
        ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2;
        if (Count < ExpectedCount)
        {
            goto PackageTooSmall;
        }
        else if (Count > ExpectedCount)
        {
            ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
                               "%s: Return Package is larger than needed - "
                               "found %u, expected %u\n",
                               Data->Pathname, Count, ExpectedCount));
        }

        /* Validate all elements of the returned package */

        Status = AcpiNsCheckPackageElements (Data, Elements,
                                             Package->RetInfo.ObjectType1, Package->RetInfo.Count1,
                                             Package->RetInfo.ObjectType2, Package->RetInfo.Count2, 0);
        break;


    case ACPI_PTYPE1_VAR:

        /*
         * The package count is variable, there are no sub-packages, and all
         * elements must be of the same type
         */
        for (i = 0; i < Count; i++)
        {
            Status = AcpiNsCheckObjectType (Data, Elements,
                                            Package->RetInfo.ObjectType1, i);
            if (ACPI_FAILURE (Status))
            {
                return (Status);
            }
            Elements++;
        }
        break;


    case ACPI_PTYPE1_OPTION:

        /*
         * The package count is variable, there are no sub-packages. There are
         * a fixed number of required elements, and a variable number of
         * optional elements.
         *
         * Check if package is at least as large as the minimum required
         */
        ExpectedCount = Package->RetInfo3.Count;
        if (Count < ExpectedCount)
        {
            goto PackageTooSmall;
        }

        /* Variable number of sub-objects */

        for (i = 0; i < Count; i++)
        {
            if (i < Package->RetInfo3.Count)
            {
                /* These are the required package elements (0, 1, or 2) */

                Status = AcpiNsCheckObjectType (Data, Elements,
                                                Package->RetInfo3.ObjectType[i], i);
                if (ACPI_FAILURE (Status))
                {
                    return (Status);
                }
            }
            else
            {
                /* These are the optional package elements */

                Status = AcpiNsCheckObjectType (Data, Elements,
                                                Package->RetInfo3.TailObjectType, i);
                if (ACPI_FAILURE (Status))
                {
                    return (Status);
                }
            }
            Elements++;
        }
        break;


    case ACPI_PTYPE2_REV_FIXED:

        /* First element is the (Integer) revision */

        Status = AcpiNsCheckObjectType (Data, Elements,
                                        ACPI_RTYPE_INTEGER, 0);
        if (ACPI_FAILURE (Status))
        {
            return (Status);
        }

        Elements++;
        Count--;

        /* Examine the sub-packages */

        Status = AcpiNsCheckPackageList (Data, Package, Elements, Count);
        break;


    case ACPI_PTYPE2_PKG_COUNT:

        /* First element is the (Integer) count of sub-packages to follow */

        Status = AcpiNsCheckObjectType (Data, Elements,
                                        ACPI_RTYPE_INTEGER, 0);
        if (ACPI_FAILURE (Status))
        {
            return (Status);
        }

        /*
         * Count cannot be larger than the parent package length, but allow it
         * to be smaller. The >= accounts for the Integer above.
         */
        ExpectedCount = (UINT32) (*Elements)->Integer.Value;
        if (ExpectedCount >= Count)
        {
            goto PackageTooSmall;
        }

        Count = ExpectedCount;
        Elements++;

        /* Examine the sub-packages */

        Status = AcpiNsCheckPackageList (Data, Package, Elements, Count);
        break;


    case ACPI_PTYPE2:
    case ACPI_PTYPE2_FIXED:
    case ACPI_PTYPE2_MIN:
    case ACPI_PTYPE2_COUNT:
    case ACPI_PTYPE2_FIX_VAR:

        /*
         * These types all return a single Package that consists of a
         * variable number of sub-Packages.
         *
         * First, ensure that the first element is a sub-Package. If not,
         * the BIOS may have incorrectly returned the object as a single
         * package instead of a Package of Packages (a common error if
         * there is only one entry). We may be able to repair this by
         * wrapping the returned Package with a new outer Package.
         */
        if (*Elements && ((*Elements)->Common.Type != ACPI_TYPE_PACKAGE))
        {
            /* Create the new outer package and populate it */

            Status = AcpiNsRepairPackageList (Data, ReturnObjectPtr);
            if (ACPI_FAILURE (Status))
            {
                return (Status);
            }

            /* Update locals to point to the new package (of 1 element) */

            ReturnObject = *ReturnObjectPtr;
            Elements = ReturnObject->Package.Elements;
            Count = 1;
        }

        /* Examine the sub-packages */

        Status = AcpiNsCheckPackageList (Data, Package, Elements, Count);
        break;


    default:

        /* Should not get here if predefined info table is correct */

        ACPI_WARN_PREDEFINED ((AE_INFO, Data->Pathname, Data->NodeFlags,
                               "Invalid internal return type in table entry: %X",
                               Package->RetInfo.Type));

        return (AE_AML_INTERNAL);
    }

    return (Status);


PackageTooSmall:

    /* Error exit for the case with an incorrect package count */

    ACPI_WARN_PREDEFINED ((AE_INFO, Data->Pathname, Data->NodeFlags,
                           "Return Package is too small - found %u elements, expected %u",
                           Count, ExpectedCount));

    return (AE_AML_OPERAND_VALUE);
}
Beispiel #2
0
static ACPI_STATUS
AcpiNsCheckSortedList (
    ACPI_PREDEFINED_DATA    *Data,
    ACPI_OPERAND_OBJECT     *ReturnObject,
    UINT32                  ExpectedCount,
    UINT32                  SortIndex,
    UINT8                   SortDirection,
    char                    *SortKeyName)
{
    UINT32                  OuterElementCount;
    ACPI_OPERAND_OBJECT     **OuterElements;
    ACPI_OPERAND_OBJECT     **Elements;
    ACPI_OPERAND_OBJECT     *ObjDesc;
    UINT32                  i;
    UINT32                  PreviousValue;
    ACPI_STATUS             Status;


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

    if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE)
    {
        return (AE_AML_OPERAND_TYPE);
    }

    /*
     * Detect any NULL package elements and remove them from the
     * package.
     *
     * TBD: We may want to do this for all predefined names that
     * return a variable-length package of packages.
     */
    Status = AcpiNsRemoveNullElements (ReturnObject);
    if (Status == AE_NULL_ENTRY)
    {
        ACPI_INFO_PREDEFINED ((AE_INFO, Data->Pathname, Data->NodeFlags,
            "NULL elements removed from package"));

        /* Exit if package is now zero length */

        if (!ReturnObject->Package.Count)
        {
            return (AE_NULL_ENTRY);
        }
    }

    OuterElements = ReturnObject->Package.Elements;
    OuterElementCount = ReturnObject->Package.Count;
    if (!OuterElementCount)
    {
        return (AE_AML_PACKAGE_LIMIT);
    }

    PreviousValue = 0;
    if (SortDirection == ACPI_SORT_DESCENDING)
    {
        PreviousValue = ACPI_UINT32_MAX;
    }

    /* Examine each subpackage */

    for (i = 0; i < OuterElementCount; i++)
    {
        /* Each element of the top-level package must also be a package */

        if ((*OuterElements)->Common.Type != ACPI_TYPE_PACKAGE)
        {
            return (AE_AML_OPERAND_TYPE);
        }

        /* Each sub-package must have the minimum length */

        if ((*OuterElements)->Package.Count < ExpectedCount)
        {
            return (AE_AML_PACKAGE_LIMIT);
        }

        Elements = (*OuterElements)->Package.Elements;
        ObjDesc = Elements[SortIndex];

        if (ObjDesc->Common.Type != ACPI_TYPE_INTEGER)
        {
            return (AE_AML_OPERAND_TYPE);
        }

        /*
         * The list must be sorted in the specified order. If we detect a
         * discrepancy, issue a warning and sort the entire list
         */
        if (((SortDirection == ACPI_SORT_ASCENDING) &&
                (ObjDesc->Integer.Value < PreviousValue)) ||
            ((SortDirection == ACPI_SORT_DESCENDING) &&
                (ObjDesc->Integer.Value > PreviousValue)))
        {
            Status = AcpiNsSortList (ReturnObject->Package.Elements,
                        OuterElementCount, SortIndex, SortDirection);
            if (ACPI_FAILURE (Status))
            {
                return (Status);
            }

            Data->Flags |= ACPI_OBJECT_REPAIRED;

            ACPI_INFO_PREDEFINED ((AE_INFO, Data->Pathname, Data->NodeFlags,
                "Repaired unsorted list - now sorted by %s", SortKeyName));
            return (AE_OK);
        }

        PreviousValue = (UINT32) ObjDesc->Integer.Value;
        OuterElements++;
    }

    return (AE_OK);
}