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=14679 Signed-off-by: Lin Ming <ming.m.lin@intel.com> Signed-off-by: Bob Moore <robert.moore@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
c1637e9c64
commit
729df0f848
5 changed files with 61 additions and 20 deletions
|
@ -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);
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
(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);
|
||||||
|
|
||||||
|
|
Reference in a new issue