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); }
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); }