diff options
author | Jung-uk Kim <jkim@FreeBSD.org> | 2013-12-19 05:51:01 +0000 |
---|---|---|
committer | Jung-uk Kim <jkim@FreeBSD.org> | 2013-12-19 05:51:01 +0000 |
commit | 86e94f4ac956e0aed23de30c7a458d215f54749a (patch) | |
tree | 7fcfdcc62c3319ffd669b18b080d40c9c5897210 /source/components/tables/tbutils.c | |
parent | de06c6b7e0851b337ee530b0ab8818f4216b06b2 (diff) | |
download | src-test2-86e94f4ac956e0aed23de30c7a458d215f54749a.tar.gz src-test2-86e94f4ac956e0aed23de30c7a458d215f54749a.zip |
Notes
Diffstat (limited to 'source/components/tables/tbutils.c')
-rw-r--r-- | source/components/tables/tbutils.c | 150 |
1 files changed, 130 insertions, 20 deletions
diff --git a/source/components/tables/tbutils.c b/source/components/tables/tbutils.c index 7c84d5ea427c..159a7d9b0f6f 100644 --- a/source/components/tables/tbutils.c +++ b/source/components/tables/tbutils.c @@ -53,6 +53,10 @@ /* Local prototypes */ +static ACPI_STATUS +AcpiTbValidateXsdt ( + ACPI_PHYSICAL_ADDRESS Address); + static ACPI_PHYSICAL_ADDRESS AcpiTbGetRootTableEntry ( UINT8 *TableEntry, @@ -353,7 +357,7 @@ AcpiTbGetRootTableEntry ( * Get the table physical address (32-bit for RSDT, 64-bit for XSDT): * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT */ - if (TableEntrySize == sizeof (UINT32)) + if (TableEntrySize == ACPI_RSDT_ENTRY_SIZE) { /* * 32-bit platform, RSDT: Return 32-bit table entry @@ -388,6 +392,92 @@ AcpiTbGetRootTableEntry ( /******************************************************************************* * + * FUNCTION: AcpiTbValidateXsdt + * + * PARAMETERS: Address - Physical address of the XSDT (from RSDP) + * + * RETURN: Status. AE_OK if the table appears to be valid. + * + * DESCRIPTION: Validate an XSDT to ensure that it is of minimum size and does + * not contain any NULL entries. A problem that is seen in the + * field is that the XSDT exists, but is actually useless because + * of one or more (or all) NULL entries. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiTbValidateXsdt ( + ACPI_PHYSICAL_ADDRESS XsdtAddress) +{ + ACPI_TABLE_HEADER *Table; + UINT8 *NextEntry; + ACPI_PHYSICAL_ADDRESS Address; + UINT32 Length; + UINT32 EntryCount; + ACPI_STATUS Status; + UINT32 i; + + + /* Get the XSDT length */ + + Table = AcpiOsMapMemory (XsdtAddress, sizeof (ACPI_TABLE_HEADER)); + if (!Table) + { + return (AE_NO_MEMORY); + } + + Length = Table->Length; + AcpiOsUnmapMemory (Table, sizeof (ACPI_TABLE_HEADER)); + + /* + * Minimum XSDT length is the size of the standard ACPI header + * plus one physical address entry + */ + if (Length < (sizeof (ACPI_TABLE_HEADER) + ACPI_XSDT_ENTRY_SIZE)) + { + return (AE_INVALID_TABLE_LENGTH); + } + + /* Map the entire XSDT */ + + Table = AcpiOsMapMemory (XsdtAddress, Length); + if (!Table) + { + return (AE_NO_MEMORY); + } + + /* Get the number of entries and pointer to first entry */ + + Status = AE_OK; + NextEntry = ACPI_ADD_PTR (UINT8, Table, sizeof (ACPI_TABLE_HEADER)); + EntryCount = (UINT32) ((Table->Length - sizeof (ACPI_TABLE_HEADER)) / + ACPI_XSDT_ENTRY_SIZE); + + /* Validate each entry (physical address) within the XSDT */ + + for (i = 0; i < EntryCount; i++) + { + Address = AcpiTbGetRootTableEntry (NextEntry, ACPI_XSDT_ENTRY_SIZE); + if (!Address) + { + /* Detected a NULL entry, XSDT is invalid */ + + Status = AE_NULL_ENTRY; + break; + } + + NextEntry += ACPI_XSDT_ENTRY_SIZE; + } + + /* Unmap table */ + + AcpiOsUnmapMemory (Table, Length); + return (Status); +} + + +/******************************************************************************* + * * FUNCTION: AcpiTbParseRootTable * * PARAMETERS: Rsdp - Pointer to the RSDP @@ -421,9 +511,8 @@ AcpiTbParseRootTable ( ACPI_FUNCTION_TRACE (TbParseRootTable); - /* - * Map the entire RSDP and extract the address of the RSDT or XSDT - */ + /* Map the entire RSDP and extract the address of the RSDT or XSDT */ + Rsdp = AcpiOsMapMemory (RsdpAddress, sizeof (ACPI_TABLE_RSDP)); if (!Rsdp) { @@ -433,24 +522,26 @@ AcpiTbParseRootTable ( AcpiTbPrintTableHeader (RsdpAddress, ACPI_CAST_PTR (ACPI_TABLE_HEADER, Rsdp)); - /* Differentiate between RSDT and XSDT root tables */ + /* Use XSDT if present and not overridden. Otherwise, use RSDT */ - if (Rsdp->Revision > 1 && Rsdp->XsdtPhysicalAddress) + if ((Rsdp->Revision > 1) && + Rsdp->XsdtPhysicalAddress && + !AcpiGbl_DoNotUseXsdt) { /* - * Root table is an XSDT (64-bit physical addresses). We must use the - * XSDT if the revision is > 1 and the XSDT pointer is present, as per - * the ACPI specification. + * RSDP contains an XSDT (64-bit physical addresses). We must use + * the XSDT if the revision is > 1 and the XSDT pointer is present, + * as per the ACPI specification. */ Address = (ACPI_PHYSICAL_ADDRESS) Rsdp->XsdtPhysicalAddress; - TableEntrySize = sizeof (UINT64); + TableEntrySize = ACPI_XSDT_ENTRY_SIZE; } else { /* Root table is an RSDT (32-bit physical addresses) */ Address = (ACPI_PHYSICAL_ADDRESS) Rsdp->RsdtPhysicalAddress; - TableEntrySize = sizeof (UINT32); + TableEntrySize = ACPI_RSDT_ENTRY_SIZE; } /* @@ -459,6 +550,24 @@ AcpiTbParseRootTable ( */ AcpiOsUnmapMemory (Rsdp, sizeof (ACPI_TABLE_RSDP)); + /* + * If it is present and used, validate the XSDT for access/size + * and ensure that all table entries are at least non-NULL + */ + if (TableEntrySize == ACPI_XSDT_ENTRY_SIZE) + { + Status = AcpiTbValidateXsdt (Address); + if (ACPI_FAILURE (Status)) + { + ACPI_BIOS_WARNING ((AE_INFO, "XSDT is invalid (%s), using RSDT", + AcpiFormatException (Status))); + + /* Fall back to the RSDT */ + + Address = (ACPI_PHYSICAL_ADDRESS) Rsdp->RsdtPhysicalAddress; + TableEntrySize = ACPI_RSDT_ENTRY_SIZE; + } + } /* Map the RSDT/XSDT table header to get the full table length */ @@ -470,12 +579,14 @@ AcpiTbParseRootTable ( AcpiTbPrintTableHeader (Address, Table); - /* Get the length of the full table, verify length and map entire table */ - + /* + * Validate length of the table, and map entire table. + * Minimum length table must contain at least one entry. + */ Length = Table->Length; AcpiOsUnmapMemory (Table, sizeof (ACPI_TABLE_HEADER)); - if (Length < sizeof (ACPI_TABLE_HEADER)) + if (Length < (sizeof (ACPI_TABLE_HEADER) + TableEntrySize)) { ACPI_BIOS_ERROR ((AE_INFO, "Invalid table length 0x%X in RSDT/XSDT", Length)); @@ -497,22 +608,21 @@ AcpiTbParseRootTable ( return_ACPI_STATUS (Status); } - /* Calculate the number of tables described in the root table */ + /* Get the number of entries and pointer to first entry */ TableCount = (UINT32) ((Table->Length - sizeof (ACPI_TABLE_HEADER)) / TableEntrySize); + TableEntry = ACPI_ADD_PTR (UINT8, Table, sizeof (ACPI_TABLE_HEADER)); /* * First two entries in the table array are reserved for the DSDT * and FACS, which are not actually present in the RSDT/XSDT - they * come from the FADT */ - TableEntry = ACPI_CAST_PTR (UINT8, Table) + sizeof (ACPI_TABLE_HEADER); AcpiGbl_RootTableList.CurrentTableCount = 2; - /* - * Initialize the root table array from the RSDT/XSDT - */ + /* Initialize the root table array from the RSDT/XSDT */ + for (i = 0; i < TableCount; i++) { if (AcpiGbl_RootTableList.CurrentTableCount >= @@ -554,7 +664,7 @@ AcpiTbParseRootTable ( AcpiTbInstallTable (AcpiGbl_RootTableList.Tables[i].Address, NULL, i); - /* Special case for FADT - get the DSDT and FACS */ + /* Special case for FADT - validate it then get the DSDT and FACS */ if (ACPI_COMPARE_NAME ( &AcpiGbl_RootTableList.Tables[i].Signature, ACPI_SIG_FADT)) |