summaryrefslogtreecommitdiff
path: root/source/components/tables/tbutils.c
diff options
context:
space:
mode:
authorJung-uk Kim <jkim@FreeBSD.org>2013-12-19 05:51:01 +0000
committerJung-uk Kim <jkim@FreeBSD.org>2013-12-19 05:51:01 +0000
commit86e94f4ac956e0aed23de30c7a458d215f54749a (patch)
tree7fcfdcc62c3319ffd669b18b080d40c9c5897210 /source/components/tables/tbutils.c
parentde06c6b7e0851b337ee530b0ab8818f4216b06b2 (diff)
downloadsrc-test2-86e94f4ac956e0aed23de30c7a458d215f54749a.tar.gz
src-test2-86e94f4ac956e0aed23de30c7a458d215f54749a.zip
Notes
Diffstat (limited to 'source/components/tables/tbutils.c')
-rw-r--r--source/components/tables/tbutils.c150
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))