aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorLin Ming <ming.m.lin@intel.com>2010-03-31 22:47:56 -0400
committerLen Brown <len.brown@intel.com>2010-04-20 10:43:16 -0400
commit729df0f848daf2f17d02107199fa92efe909d995 (patch)
treed4ece34a277019368999fd36a0bf15a39eeaa742 /drivers/acpi
parentc1637e9c649a0eb72c467041d78275aabdd48a41 (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>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/acpica/acglobal.h5
-rw-r--r--drivers/acpi/acpica/actables.h2
-rw-r--r--drivers/acpi/acpica/psxface.c4
-rw-r--r--drivers/acpi/acpica/tbutils.c38
-rw-r--r--drivers/acpi/acpica/tbxface.c32
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;
165ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_status; 165ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_status;
166ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; 166ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;
167 167
168/* DSDT information. Used to check for DSDT corruption */
169
170ACPI_EXTERN struct acpi_table_desc *acpi_gbl_DSDT;
171ACPI_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);
107acpi_status 107acpi_status
108acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length); 108acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length);
109 109
110void acpi_tb_check_dsdt_header(void);
111
110void 112void
111acpi_tb_install_table(acpi_physical_address address, 113acpi_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
364void 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