From 7d26cbe165bc22d933c810af59346255216abe69 Mon Sep 17 00:00:00 2001 From: Lv Zheng Data: Thu, 17 Apr 2014 19:54:02 +0800 Subject: [PATCH 0] ACPICA: Tables: Skip NULL entries in RSDT and XSDT. It is reported that there are buggy BIOSes in the world. They will export XSDT with NULL entries. Original solution on Linux is to use an alternative heathy root table instead of the ill one. But according to the bug report, we should just simply ignore the NULL entries. This patch deletes XSDT validation logics and adds code to skip NULL entries that can be found in RSDT or XSDT. Lv Zheng. This patch can only be used for v3.14. An upstream kernel that has merged 20130325 ACPICA release should use a different commit. Buglink: https://bugzilla.kernel.org/show_bug.cgi?id=73911 Signed-off-by: Lv Zheng --- drivers/acpi/acpica/tbutils.c | 122 +-------------- tools/power/acpi/os_specific/service_layers/oslinuxtbl.c | 12 + 2 files changed, 26 insertions(+), 108 deletions(-) Index: linux-acpica/drivers/acpi/acpica/tbutils.c =================================================================== --- linux-acpica.orig/drivers/acpi/acpica/tbutils.c +++ linux-acpica/drivers/acpi/acpica/tbutils.c @@ -49,8 +49,6 @@ ACPI_MODULE_NAME("tbutils") /* Local prototypes */ -static acpi_status acpi_tb_validate_xsdt(acpi_physical_address address); - static acpi_physical_address acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); @@ -357,87 +355,6 @@ acpi_tb_get_root_table_entry(u8 *table_e /******************************************************************************* * - * FUNCTION: acpi_tb_validate_xsdt - * - * 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 acpi_tb_validate_xsdt(acpi_physical_address xsdt_address) -{ - struct acpi_table_header *table; - u8 *next_entry; - acpi_physical_address address; - u32 length; - u32 entry_count; - acpi_status status; - u32 i; - - /* Get the XSDT length */ - - table = - acpi_os_map_memory(xsdt_address, sizeof(struct acpi_table_header)); - if (!table) { - return (AE_NO_MEMORY); - } - - length = table->length; - acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); - - /* - * Minimum XSDT length is the size of the standard ACPI header - * plus one physical address entry - */ - if (length < (sizeof(struct acpi_table_header) + ACPI_XSDT_ENTRY_SIZE)) { - return (AE_INVALID_TABLE_LENGTH); - } - - /* Map the entire XSDT */ - - table = acpi_os_map_memory(xsdt_address, length); - if (!table) { - return (AE_NO_MEMORY); - } - - /* Get the number of entries and pointer to first entry */ - - status = AE_OK; - next_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header)); - entry_count = (u32)((table->length - sizeof(struct acpi_table_header)) / - ACPI_XSDT_ENTRY_SIZE); - - /* Validate each entry (physical address) within the XSDT */ - - for (i = 0; i < entry_count; i++) { - address = - acpi_tb_get_root_table_entry(next_entry, - ACPI_XSDT_ENTRY_SIZE); - if (!address) { - - /* Detected a NULL entry, XSDT is invalid */ - - status = AE_NULL_ENTRY; - break; - } - - next_entry += ACPI_XSDT_ENTRY_SIZE; - } - - /* Unmap table */ - - acpi_os_unmap_memory(table, length); - return (status); -} - -/******************************************************************************* - * * FUNCTION: acpi_tb_parse_root_table * * PARAMETERS: rsdp - Pointer to the RSDP @@ -502,25 +419,6 @@ acpi_status __init acpi_tb_parse_root_ta */ acpi_os_unmap_memory(rsdp, sizeof(struct 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 (table_entry_size == ACPI_XSDT_ENTRY_SIZE) { - status = acpi_tb_validate_xsdt(address); - if (ACPI_FAILURE(status)) { - ACPI_BIOS_WARNING((AE_INFO, - "XSDT is invalid (%s), using RSDT", - acpi_format_exception(status))); - - /* Fall back to the RSDT */ - - address = - (acpi_physical_address) rsdp->rsdt_physical_address; - table_entry_size = ACPI_RSDT_ENTRY_SIZE; - } - } - /* Map the RSDT/XSDT table header to get the full table length */ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); @@ -592,12 +490,20 @@ acpi_status __init acpi_tb_parse_root_ta /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */ + address = acpi_tb_get_root_table_entry(table_entry, table_entry_size); + + /* Skip NULL entry in RSDT/XSDT */ + + if (!address) { + goto next_table; + } + 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); + current_table_count].address = address; + acpi_gbl_root_table_list.current_table_count++; +next_table: table_entry += table_entry_size; - acpi_gbl_root_table_list.current_table_count++; } /*