diff options
| author | Lin Ming <ming.m.lin@intel.com> | 2010-03-31 22:47:56 -0400 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2010-04-20 10:43:16 -0400 |
| commit | 729df0f848daf2f17d02107199fa92efe909d995 (patch) | |
| tree | d4ece34a277019368999fd36a0bf15a39eeaa742 | |
| parent | c1637e9c649a0eb72c467041d78275aabdd48a41 (diff) | |
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>
| -rw-r--r-- | drivers/acpi/acpica/acglobal.h | 5 | ||||
| -rw-r--r-- | drivers/acpi/acpica/actables.h | 2 | ||||
| -rw-r--r-- | drivers/acpi/acpica/psxface.c | 4 | ||||
| -rw-r--r-- | drivers/acpi/acpica/tbutils.c | 38 | ||||
| -rw-r--r-- | drivers/acpi/acpica/tbxface.c | 32 |
5 files changed, 61 insertions, 20 deletions
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 2b2e61ed373e..a419fe98a5fc 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h | |||
| @@ -165,6 +165,11 @@ ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; | |||
| 165 | ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_status; | 165 | ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_status; |
| 166 | ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; | 166 | ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; |
| 167 | 167 | ||
| 168 | /* DSDT information. Used to check for DSDT corruption */ | ||
| 169 | |||
| 170 | ACPI_EXTERN struct acpi_table_desc *acpi_gbl_DSDT; | ||
| 171 | ACPI_EXTERN struct acpi_table_header acpi_gbl_original_dsdt_header; | ||
| 172 | |||
| 168 | /* | 173 | /* |
| 169 | * Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is | 174 | * Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is |
| 170 | * determined by the revision of the DSDT: If the DSDT revision is less than | 175 | * determined by the revision of the DSDT: If the DSDT revision is less than |
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 8ff3b741df28..fc52b6f2d69c 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h | |||
| @@ -107,6 +107,8 @@ u8 acpi_tb_checksum(u8 *buffer, u32 length); | |||
| 107 | acpi_status | 107 | acpi_status |
| 108 | acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length); | 108 | acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length); |
| 109 | 109 | ||
| 110 | void acpi_tb_check_dsdt_header(void); | ||
| 111 | |||
| 110 | void | 112 | void |
| 111 | acpi_tb_install_table(acpi_physical_address address, | 113 | acpi_tb_install_table(acpi_physical_address address, |
| 112 | char *signature, u32 table_index); | 114 | char *signature, u32 table_index); |
diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index 6064dd4e94c2..67e7ad517051 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c | |||
| @@ -220,6 +220,10 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) | |||
| 220 | 220 | ||
| 221 | ACPI_FUNCTION_TRACE(ps_execute_method); | 221 | ACPI_FUNCTION_TRACE(ps_execute_method); |
| 222 | 222 | ||
| 223 | /* Quick validation of DSDT header */ | ||
| 224 | |||
| 225 | acpi_tb_check_dsdt_header(); | ||
| 226 | |||
| 223 | /* Validate the Info and method Node */ | 227 | /* Validate the Info and method Node */ |
| 224 | 228 | ||
| 225 | if (!info || !info->resolved_node) { | 229 | if (!info || !info->resolved_node) { |
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index f47a70e20063..07bc7437f82b 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c | |||
| @@ -349,6 +349,44 @@ u8 acpi_tb_checksum(u8 *buffer, u32 length) | |||
| 349 | 349 | ||
| 350 | /******************************************************************************* | 350 | /******************************************************************************* |
| 351 | * | 351 | * |
| 352 | * FUNCTION: acpi_tb_check_dsdt_header | ||
| 353 | * | ||
| 354 | * PARAMETERS: None | ||
| 355 | * | ||
| 356 | * RETURN: None | ||
| 357 | * | ||
| 358 | * DESCRIPTION: Quick compare to check validity of the DSDT. This will detect | ||
| 359 | * if the DSDT has been replaced from outside the OS and/or if | ||
| 360 | * the DSDT header has been corrupted. | ||
| 361 | * | ||
| 362 | ******************************************************************************/ | ||
| 363 | |||
| 364 | void acpi_tb_check_dsdt_header(void) | ||
| 365 | { | ||
| 366 | |||
| 367 | /* Compare original length and checksum to current values */ | ||
| 368 | |||
| 369 | if (acpi_gbl_original_dsdt_header.length != | ||
| 370 | acpi_gbl_DSDT->pointer->length | ||
| 371 | || acpi_gbl_original_dsdt_header.checksum != | ||
| 372 | acpi_gbl_DSDT->pointer->checksum) { | ||
| 373 | ACPI_ERROR((AE_INFO, | ||
| 374 | "The DSDT has been corrupted or replaced - old, new headers below")); | ||
| 375 | acpi_tb_print_table_header(0, &acpi_gbl_original_dsdt_header); | ||
| 376 | acpi_tb_print_table_header(acpi_gbl_DSDT->address, | ||
| 377 | acpi_gbl_DSDT->pointer); | ||
| 378 | |||
| 379 | /* Disable further error messages */ | ||
| 380 | |||
| 381 | acpi_gbl_original_dsdt_header.length = | ||
| 382 | acpi_gbl_DSDT->pointer->length; | ||
| 383 | acpi_gbl_original_dsdt_header.checksum = | ||
| 384 | acpi_gbl_DSDT->pointer->checksum; | ||
| 385 | } | ||
| 386 | } | ||
| 387 | |||
| 388 | /******************************************************************************* | ||
| 389 | * | ||
| 352 | * FUNCTION: acpi_tb_install_table | 390 | * FUNCTION: acpi_tb_install_table |
| 353 | * | 391 | * |
| 354 | * PARAMETERS: Address - Physical address of DSDT or FACS | 392 | * PARAMETERS: Address - Physical address of DSDT or FACS |
diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 684614d0d327..30565100b94c 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c | |||
| @@ -518,33 +518,25 @@ static acpi_status acpi_tb_load_namespace(void) | |||
| 518 | 518 | ||
| 519 | (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); | 519 | (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
| 520 | 520 | ||
| 521 | acpi_gbl_DSDT = &acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT]; | ||
| 522 | |||
| 521 | /* | 523 | /* |
| 522 | * Load the namespace. The DSDT is required, but any SSDT and PSDT tables | 524 | * Load the namespace. The DSDT is required, but any SSDT and |
| 523 | * are optional. | 525 | * PSDT tables are optional. Verify the DSDT. |
| 524 | */ | 526 | */ |
| 525 | if (!acpi_gbl_root_table_list.count || | 527 | if (!acpi_gbl_root_table_list.count || |
| 526 | !ACPI_COMPARE_NAME(& | 528 | !ACPI_COMPARE_NAME(&acpi_gbl_DSDT->signature, ACPI_SIG_DSDT) || |
| 527 | (acpi_gbl_root_table_list. | 529 | ACPI_FAILURE(acpi_tb_verify_table(acpi_gbl_DSDT))) { |
| 528 | tables[ACPI_TABLE_INDEX_DSDT].signature), | ||
| 529 | ACPI_SIG_DSDT) | ||
| 530 | || | ||
| 531 | ACPI_FAILURE(acpi_tb_verify_table | ||
| 532 | (&acpi_gbl_root_table_list. | ||
| 533 | tables[ACPI_TABLE_INDEX_DSDT]))) { | ||
| 534 | status = AE_NO_ACPI_TABLES; | 530 | status = AE_NO_ACPI_TABLES; |
| 535 | goto unlock_and_exit; | 531 | goto unlock_and_exit; |
| 536 | } | 532 | } |
| 537 | 533 | ||
| 538 | /* A valid DSDT is required */ | 534 | /* |
| 539 | 535 | * Save the original DSDT header for detection of table corruption | |
| 540 | status = | 536 | * and/or replacement of the DSDT from outside the OS. |
| 541 | acpi_tb_verify_table(&acpi_gbl_root_table_list. | 537 | */ |
| 542 | tables[ACPI_TABLE_INDEX_DSDT]); | 538 | ACPI_MEMCPY(&acpi_gbl_original_dsdt_header, acpi_gbl_DSDT->pointer, |
| 543 | if (ACPI_FAILURE(status)) { | 539 | sizeof(struct acpi_table_header)); |
| 544 | |||
| 545 | status = AE_NO_ACPI_TABLES; | ||
| 546 | goto unlock_and_exit; | ||
| 547 | } | ||
| 548 | 540 | ||
| 549 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); | 541 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
| 550 | 542 | ||
