diff options
Diffstat (limited to 'drivers/acpi/acpica/tbutils.c')
-rw-r--r-- | drivers/acpi/acpica/tbutils.c | 101 |
1 files changed, 90 insertions, 11 deletions
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 02723a9fb10..34f9c2bc5e1 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -158,7 +158,7 @@ acpi_status acpi_tb_initialize_facs(void) u8 acpi_tb_tables_loaded(void) { - if (acpi_gbl_root_table_list.count >= 3) { + if (acpi_gbl_root_table_list.current_table_count >= 3) { return (TRUE); } @@ -309,7 +309,7 @@ acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length) if (checksum) { ACPI_WARNING((AE_INFO, - "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X", + "Incorrect checksum in table [%4.4s] - 0x%2.2X, should be 0x%2.2X", table->signature, table->checksum, (u8) (table->checksum - checksum))); @@ -349,6 +349,84 @@ u8 acpi_tb_checksum(u8 *buffer, u32 length) /******************************************************************************* * + * FUNCTION: acpi_tb_check_dsdt_header + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Quick compare to check validity of the DSDT. This will detect + * if the DSDT has been replaced from outside the OS and/or if + * the DSDT header has been corrupted. + * + ******************************************************************************/ + +void acpi_tb_check_dsdt_header(void) +{ + + /* Compare original length and checksum to current values */ + + if (acpi_gbl_original_dsdt_header.length != acpi_gbl_DSDT->length || + acpi_gbl_original_dsdt_header.checksum != acpi_gbl_DSDT->checksum) { + ACPI_ERROR((AE_INFO, + "The DSDT has been corrupted or replaced - old, new headers below")); + acpi_tb_print_table_header(0, &acpi_gbl_original_dsdt_header); + acpi_tb_print_table_header(0, acpi_gbl_DSDT); + + ACPI_ERROR((AE_INFO, + "Please send DMI info to linux-acpi@vger.kernel.org\n" + "If system does not work as expected, please boot with acpi=copy_dsdt")); + + /* Disable further error messages */ + + acpi_gbl_original_dsdt_header.length = acpi_gbl_DSDT->length; + acpi_gbl_original_dsdt_header.checksum = + acpi_gbl_DSDT->checksum; + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_copy_dsdt + * + * PARAMETERS: table_desc - Installed table to copy + * + * RETURN: None + * + * DESCRIPTION: Implements a subsystem option to copy the DSDT to local memory. + * Some very bad BIOSs are known to either corrupt the DSDT or + * install a new, bad DSDT. This copy works around the problem. + * + ******************************************************************************/ + +struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index) +{ + struct acpi_table_header *new_table; + struct acpi_table_desc *table_desc; + + table_desc = &acpi_gbl_root_table_list.tables[table_index]; + + new_table = ACPI_ALLOCATE(table_desc->length); + if (!new_table) { + ACPI_ERROR((AE_INFO, "Could not copy DSDT of length 0x%X", + table_desc->length)); + return (NULL); + } + + ACPI_MEMCPY(new_table, table_desc->pointer, table_desc->length); + acpi_tb_delete_table(table_desc); + table_desc->pointer = new_table; + table_desc->flags = ACPI_TABLE_ORIGIN_ALLOCATED; + + ACPI_INFO((AE_INFO, + "Forced DSDT copy: length 0x%05X copied locally, original unmapped", + new_table->length)); + + return (new_table); +} + +/******************************************************************************* + * * FUNCTION: acpi_tb_install_table * * PARAMETERS: Address - Physical address of DSDT or FACS @@ -496,7 +574,7 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size) /* Will truncate 64-bit address to 32 bits, issue warning */ ACPI_WARNING((AE_INFO, - "64-bit Physical Address in XSDT is too large (%8.8X%8.8X)," + "64-bit Physical Address in XSDT is too large (0x%8.8X%8.8X)," " truncating", ACPI_FORMAT_UINT64(address64))); } @@ -629,14 +707,14 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address) */ table_entry = ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header); - acpi_gbl_root_table_list.count = 2; + acpi_gbl_root_table_list.current_table_count = 2; /* * Initialize the root table array from the RSDT/XSDT */ for (i = 0; i < table_count; i++) { - if (acpi_gbl_root_table_list.count >= - acpi_gbl_root_table_list.size) { + if (acpi_gbl_root_table_list.current_table_count >= + acpi_gbl_root_table_list.max_table_count) { /* There is no more room in the root table array, attempt resize */ @@ -646,19 +724,20 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address) "Truncating %u table entries!", (unsigned) (table_count - (acpi_gbl_root_table_list. - count - 2)))); + current_table_count - + 2)))); break; } } /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */ - acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count]. - address = + acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list. + current_table_count].address = acpi_tb_get_root_table_entry(table_entry, table_entry_size); table_entry += table_entry_size; - acpi_gbl_root_table_list.count++; + acpi_gbl_root_table_list.current_table_count++; } /* @@ -671,7 +750,7 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address) * Complete the initialization of the root table array by examining * the header of each table */ - for (i = 2; i < acpi_gbl_root_table_list.count; i++) { + for (i = 2; i < acpi_gbl_root_table_list.current_table_count; i++) { acpi_tb_install_table(acpi_gbl_root_table_list.tables[i]. address, NULL, i); |