diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index a419fe98a5fc..e3813d290b4f 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -117,6 +117,14 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE); */ u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE); +/* + * Optionally copy the entire DSDT to local memory (instead of simply + * mapping it.) There are some BIOSs that corrupt or replace the original + * DSDT, creating the need for this option. Default is FALSE, do not copy + * the DSDT. + */ +u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE); + /* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */ struct acpi_table_fadt acpi_gbl_FADT; diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index fc52b6f2d69c..b7197bf4af0b 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -109,6 +109,8 @@ acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length); void acpi_tb_check_dsdt_header(void); +void acpi_tb_copy_dsdt(struct acpi_table_desc *table_desc); + void acpi_tb_install_table(acpi_physical_address address, char *signature, u32 table_index); diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index 67e7ad517051..c42f067cff9d 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -46,6 +46,7 @@ #include "acparser.h" #include "acdispat.h" #include "acinterp.h" +#include "actables.h" #include "amlcode.h" #define _COMPONENT ACPI_PARSER diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 07bc7437f82b..1efb0940e8b2 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -385,6 +385,41 @@ void acpi_tb_check_dsdt_header(void) } } +/******************************************************************************* + * + * 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. + * + ******************************************************************************/ + +void acpi_tb_copy_dsdt(struct acpi_table_desc *table_desc) +{ + struct acpi_table_header *new_table; + + 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; + } + + 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)); +} + /******************************************************************************* * * FUNCTION: acpi_tb_install_table diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 30565100b94c..f5378fc302b3 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -531,6 +531,16 @@ static acpi_status acpi_tb_load_namespace(void) goto unlock_and_exit; } + /* + * Optionally copy the entire DSDT to local memory (instead of simply + * mapping it.) There are some BIOSs that corrupt or replace the original + * DSDT, creating the need for this option. Default is FALSE, do not copy + * the DSDT. + */ + if (acpi_gbl_copy_dsdt_locally) { + acpi_tb_copy_dsdt(acpi_gbl_DSDT); + } + /* * Save the original DSDT header for detection of table corruption * and/or replacement of the DSDT from outside the OS. diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index f753222d5cfa..fd815f605426 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -68,6 +68,7 @@ extern u8 acpi_gbl_use_default_register_widths; extern acpi_name acpi_gbl_trace_method_name; extern u32 acpi_gbl_trace_flags; extern u8 acpi_gbl_enable_aml_debug_object; +extern u8 acpi_gbl_copy_dsdt_locally; extern u32 acpi_current_gpe_count; extern struct acpi_table_fadt acpi_gbl_FADT;