Commit 729df0f8 authored by Lin Ming's avatar Lin Ming Committed by Len Brown

ACPICA: Add detection of corrupted/replaced DSDT

This change adds support to detect a DSDT that has been corrupted
and/or replaced from outside the OS (by firmware). This is
typically catastrophic for the system, but has been seen on
some machines.

https://bugzilla.kernel.org/show_bug.cgi?id=14679Signed-off-by: default avatarLin Ming <ming.m.lin@intel.com>
Signed-off-by: default avatarBob Moore <robert.moore@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent c1637e9c
...@@ -165,6 +165,11 @@ ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; ...@@ -165,6 +165,11 @@ ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable;
ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_status; ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_status;
ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;
/* DSDT information. Used to check for DSDT corruption */
ACPI_EXTERN struct acpi_table_desc *acpi_gbl_DSDT;
ACPI_EXTERN struct acpi_table_header acpi_gbl_original_dsdt_header;
/* /*
* Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is * Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is
* determined by the revision of the DSDT: If the DSDT revision is less than * determined by the revision of the DSDT: If the DSDT revision is less than
......
...@@ -107,6 +107,8 @@ u8 acpi_tb_checksum(u8 *buffer, u32 length); ...@@ -107,6 +107,8 @@ u8 acpi_tb_checksum(u8 *buffer, u32 length);
acpi_status acpi_status
acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length); acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length);
void acpi_tb_check_dsdt_header(void);
void void
acpi_tb_install_table(acpi_physical_address address, acpi_tb_install_table(acpi_physical_address address,
char *signature, u32 table_index); char *signature, u32 table_index);
......
...@@ -220,6 +220,10 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) ...@@ -220,6 +220,10 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
ACPI_FUNCTION_TRACE(ps_execute_method); ACPI_FUNCTION_TRACE(ps_execute_method);
/* Quick validation of DSDT header */
acpi_tb_check_dsdt_header();
/* Validate the Info and method Node */ /* Validate the Info and method Node */
if (!info || !info->resolved_node) { if (!info || !info->resolved_node) {
......
...@@ -347,6 +347,44 @@ u8 acpi_tb_checksum(u8 *buffer, u32 length) ...@@ -347,6 +347,44 @@ u8 acpi_tb_checksum(u8 *buffer, u32 length)
return sum; return sum;
} }
/*******************************************************************************
*
* 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->pointer->length
|| acpi_gbl_original_dsdt_header.checksum !=
acpi_gbl_DSDT->pointer->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(acpi_gbl_DSDT->address,
acpi_gbl_DSDT->pointer);
/* Disable further error messages */
acpi_gbl_original_dsdt_header.length =
acpi_gbl_DSDT->pointer->length;
acpi_gbl_original_dsdt_header.checksum =
acpi_gbl_DSDT->pointer->checksum;
}
}
/******************************************************************************* /*******************************************************************************
* *
* FUNCTION: acpi_tb_install_table * FUNCTION: acpi_tb_install_table
......
...@@ -518,33 +518,25 @@ static acpi_status acpi_tb_load_namespace(void) ...@@ -518,33 +518,25 @@ static acpi_status acpi_tb_load_namespace(void)
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
acpi_gbl_DSDT = &acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT];
/* /*
* Load the namespace. The DSDT is required, but any SSDT and PSDT tables * Load the namespace. The DSDT is required, but any SSDT and
* are optional. * PSDT tables are optional. Verify the DSDT.
*/ */
if (!acpi_gbl_root_table_list.count || if (!acpi_gbl_root_table_list.count ||
!ACPI_COMPARE_NAME(& !ACPI_COMPARE_NAME(&acpi_gbl_DSDT->signature, ACPI_SIG_DSDT) ||
(acpi_gbl_root_table_list. ACPI_FAILURE(acpi_tb_verify_table(acpi_gbl_DSDT))) {
tables[ACPI_TABLE_INDEX_DSDT].signature),
ACPI_SIG_DSDT)
||
ACPI_FAILURE(acpi_tb_verify_table
(&acpi_gbl_root_table_list.
tables[ACPI_TABLE_INDEX_DSDT]))) {
status = AE_NO_ACPI_TABLES; status = AE_NO_ACPI_TABLES;
goto unlock_and_exit; goto unlock_and_exit;
} }
/* A valid DSDT is required */ /*
* Save the original DSDT header for detection of table corruption
status = * and/or replacement of the DSDT from outside the OS.
acpi_tb_verify_table(&acpi_gbl_root_table_list. */
tables[ACPI_TABLE_INDEX_DSDT]); ACPI_MEMCPY(&acpi_gbl_original_dsdt_header, acpi_gbl_DSDT->pointer,
if (ACPI_FAILURE(status)) { sizeof(struct acpi_table_header));
status = AE_NO_ACPI_TABLES;
goto unlock_and_exit;
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment