aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpica
diff options
context:
space:
mode:
authorLv Zheng <lv.zheng@intel.com>2014-01-08 00:43:34 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-01-08 09:31:36 -0500
commit671cc68dc61f029d44b43a681356078e02d8dab8 (patch)
tree1f349e17ae952e874df16770e3e25bf86008df9b /drivers/acpi/acpica
parentb1c1029d72730bd18cee3518965cf699af708322 (diff)
ACPICA: Back port and refine validation of the XSDT root table.
Some platforms contain an XSDT that is ill-formed or otherwise invalid (such as containing some or all entries that are NULL pointers). This change adds a new function to validate the XSDT before actually using it. If the XSDT is found to be invalid, ACPICA will now fall back to using the RSDT instead. This feature is already in the Linux kernel. When it is back ported to ACPICA, code is refined to follow ACPICA coding style and this patch is the generation of the integration. Original-by: Zhao Yakui <yakui.zhao@intel.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Bob Moore <robert.moore@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/acpica')
-rw-r--r--drivers/acpi/acpica/tbutils.c210
1 files changed, 120 insertions, 90 deletions
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 3d6bb83aa7e7..ee6067062cdc 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -49,69 +49,11 @@
49ACPI_MODULE_NAME("tbutils") 49ACPI_MODULE_NAME("tbutils")
50 50
51/* Local prototypes */ 51/* Local prototypes */
52static acpi_status acpi_tb_validate_xsdt(acpi_physical_address address);
53
52static acpi_physical_address 54static acpi_physical_address
53acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); 55acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
54 56
55/*******************************************************************************
56 *
57 * FUNCTION: acpi_tb_check_xsdt
58 *
59 * PARAMETERS: address - Pointer to the XSDT
60 *
61 * RETURN: status
62 * AE_OK - XSDT is okay
63 * AE_NO_MEMORY - can't map XSDT
64 * AE_INVALID_TABLE_LENGTH - invalid table length
65 * AE_NULL_ENTRY - XSDT has NULL entry
66 *
67 * DESCRIPTION: validate XSDT
68******************************************************************************/
69
70static acpi_status
71acpi_tb_check_xsdt(acpi_physical_address address)
72{
73 struct acpi_table_header *table;
74 u32 length;
75 u64 xsdt_entry_address;
76 u8 *table_entry;
77 u32 table_count;
78 int i;
79
80 table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
81 if (!table)
82 return AE_NO_MEMORY;
83
84 length = table->length;
85 acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
86 if (length < sizeof(struct acpi_table_header))
87 return AE_INVALID_TABLE_LENGTH;
88
89 table = acpi_os_map_memory(address, length);
90 if (!table)
91 return AE_NO_MEMORY;
92
93 /* Calculate the number of tables described in XSDT */
94 table_count =
95 (u32) ((table->length -
96 sizeof(struct acpi_table_header)) / sizeof(u64));
97 table_entry =
98 ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
99 for (i = 0; i < table_count; i++) {
100 ACPI_MOVE_64_TO_64(&xsdt_entry_address, table_entry);
101 if (!xsdt_entry_address) {
102 /* XSDT has NULL entry */
103 break;
104 }
105 table_entry += sizeof(u64);
106 }
107 acpi_os_unmap_memory(table, length);
108
109 if (i < table_count)
110 return AE_NULL_ENTRY;
111 else
112 return AE_OK;
113}
114
115#if (!ACPI_REDUCED_HARDWARE) 57#if (!ACPI_REDUCED_HARDWARE)
116/******************************************************************************* 58/*******************************************************************************
117 * 59 *
@@ -383,7 +325,7 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size)
383 * Get the table physical address (32-bit for RSDT, 64-bit for XSDT): 325 * Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
384 * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT 326 * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
385 */ 327 */
386 if (table_entry_size == sizeof(u32)) { 328 if (table_entry_size == ACPI_RSDT_ENTRY_SIZE) {
387 /* 329 /*
388 * 32-bit platform, RSDT: Return 32-bit table entry 330 * 32-bit platform, RSDT: Return 32-bit table entry
389 * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return 331 * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
@@ -415,6 +357,87 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size)
415 357
416/******************************************************************************* 358/*******************************************************************************
417 * 359 *
360 * FUNCTION: acpi_tb_validate_xsdt
361 *
362 * PARAMETERS: address - Physical address of the XSDT (from RSDP)
363 *
364 * RETURN: Status. AE_OK if the table appears to be valid.
365 *
366 * DESCRIPTION: Validate an XSDT to ensure that it is of minimum size and does
367 * not contain any NULL entries. A problem that is seen in the
368 * field is that the XSDT exists, but is actually useless because
369 * of one or more (or all) NULL entries.
370 *
371 ******************************************************************************/
372
373static acpi_status acpi_tb_validate_xsdt(acpi_physical_address xsdt_address)
374{
375 struct acpi_table_header *table;
376 u8 *next_entry;
377 acpi_physical_address address;
378 u32 length;
379 u32 entry_count;
380 acpi_status status;
381 u32 i;
382
383 /* Get the XSDT length */
384
385 table =
386 acpi_os_map_memory(xsdt_address, sizeof(struct acpi_table_header));
387 if (!table) {
388 return (AE_NO_MEMORY);
389 }
390
391 length = table->length;
392 acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
393
394 /*
395 * Minimum XSDT length is the size of the standard ACPI header
396 * plus one physical address entry
397 */
398 if (length < (sizeof(struct acpi_table_header) + ACPI_XSDT_ENTRY_SIZE)) {
399 return (AE_INVALID_TABLE_LENGTH);
400 }
401
402 /* Map the entire XSDT */
403
404 table = acpi_os_map_memory(xsdt_address, length);
405 if (!table) {
406 return (AE_NO_MEMORY);
407 }
408
409 /* Get the number of entries and pointer to first entry */
410
411 status = AE_OK;
412 next_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header));
413 entry_count = (u32)((table->length - sizeof(struct acpi_table_header)) /
414 ACPI_XSDT_ENTRY_SIZE);
415
416 /* Validate each entry (physical address) within the XSDT */
417
418 for (i = 0; i < entry_count; i++) {
419 address =
420 acpi_tb_get_root_table_entry(next_entry,
421 ACPI_XSDT_ENTRY_SIZE);
422 if (!address) {
423
424 /* Detected a NULL entry, XSDT is invalid */
425
426 status = AE_NULL_ENTRY;
427 break;
428 }
429
430 next_entry += ACPI_XSDT_ENTRY_SIZE;
431 }
432
433 /* Unmap table */
434
435 acpi_os_unmap_memory(table, length);
436 return (status);
437}
438
439/*******************************************************************************
440 *
418 * FUNCTION: acpi_tb_parse_root_table 441 * FUNCTION: acpi_tb_parse_root_table
419 * 442 *
420 * PARAMETERS: rsdp - Pointer to the RSDP 443 * PARAMETERS: rsdp - Pointer to the RSDP
@@ -438,16 +461,14 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
438 u32 table_count; 461 u32 table_count;
439 struct acpi_table_header *table; 462 struct acpi_table_header *table;
440 acpi_physical_address address; 463 acpi_physical_address address;
441 acpi_physical_address uninitialized_var(rsdt_address);
442 u32 length; 464 u32 length;
443 u8 *table_entry; 465 u8 *table_entry;
444 acpi_status status; 466 acpi_status status;
445 467
446 ACPI_FUNCTION_TRACE(tb_parse_root_table); 468 ACPI_FUNCTION_TRACE(tb_parse_root_table);
447 469
448 /* 470 /* Map the entire RSDP and extract the address of the RSDT or XSDT */
449 * Map the entire RSDP and extract the address of the RSDT or XSDT 471
450 */
451 rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp)); 472 rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp));
452 if (!rsdp) { 473 if (!rsdp) {
453 return_ACPI_STATUS(AE_NO_MEMORY); 474 return_ACPI_STATUS(AE_NO_MEMORY);
@@ -459,22 +480,20 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
459 480
460 /* Differentiate between RSDT and XSDT root tables */ 481 /* Differentiate between RSDT and XSDT root tables */
461 482
462 if (rsdp->revision > 1 && rsdp->xsdt_physical_address 483 if ((rsdp->revision > 1) && rsdp->xsdt_physical_address
463 && !acpi_rsdt_forced) { 484 && !acpi_rsdt_forced) {
464 /* 485 /*
465 * Root table is an XSDT (64-bit physical addresses). We must use the 486 * RSDP contains an XSDT (64-bit physical addresses). We must use
466 * XSDT if the revision is > 1 and the XSDT pointer is present, as per 487 * the XSDT if the revision is > 1 and the XSDT pointer is present,
467 * the ACPI specification. 488 * as per the ACPI specification.
468 */ 489 */
469 address = (acpi_physical_address) rsdp->xsdt_physical_address; 490 address = (acpi_physical_address) rsdp->xsdt_physical_address;
470 table_entry_size = sizeof(u64); 491 table_entry_size = ACPI_XSDT_ENTRY_SIZE;
471 rsdt_address = (acpi_physical_address)
472 rsdp->rsdt_physical_address;
473 } else { 492 } else {
474 /* Root table is an RSDT (32-bit physical addresses) */ 493 /* Root table is an RSDT (32-bit physical addresses) */
475 494
476 address = (acpi_physical_address) rsdp->rsdt_physical_address; 495 address = (acpi_physical_address) rsdp->rsdt_physical_address;
477 table_entry_size = sizeof(u32); 496 table_entry_size = ACPI_RSDT_ENTRY_SIZE;
478 } 497 }
479 498
480 /* 499 /*
@@ -483,15 +502,25 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
483 */ 502 */
484 acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp)); 503 acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
485 504
486 if (table_entry_size == sizeof(u64)) { 505 /*
487 if (acpi_tb_check_xsdt(address) == AE_NULL_ENTRY) { 506 * If it is present, validate the XSDT for access/size and ensure
488 /* XSDT has NULL entry, RSDT is used */ 507 * that all table entries are at least non-NULL
489 address = rsdt_address; 508 */
490 table_entry_size = sizeof(u32); 509 if (table_entry_size == ACPI_XSDT_ENTRY_SIZE) {
491 ACPI_WARNING((AE_INFO, "BIOS XSDT has NULL entry, " 510 status = acpi_tb_validate_xsdt(address);
492 "using RSDT")); 511 if (ACPI_FAILURE(status)) {
512 ACPI_BIOS_WARNING((AE_INFO,
513 "XSDT is invalid (%s), using RSDT",
514 acpi_format_exception(status)));
515
516 /* Fall back to the RSDT */
517
518 address =
519 (acpi_physical_address) rsdp->rsdt_physical_address;
520 table_entry_size = ACPI_RSDT_ENTRY_SIZE;
493 } 521 }
494 } 522 }
523
495 /* Map the RSDT/XSDT table header to get the full table length */ 524 /* Map the RSDT/XSDT table header to get the full table length */
496 525
497 table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); 526 table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
@@ -501,12 +530,14 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
501 530
502 acpi_tb_print_table_header(address, table); 531 acpi_tb_print_table_header(address, table);
503 532
504 /* Get the length of the full table, verify length and map entire table */ 533 /*
505 534 * Validate length of the table, and map entire table.
535 * Minimum length table must contain at least one entry.
536 */
506 length = table->length; 537 length = table->length;
507 acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); 538 acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
508 539
509 if (length < sizeof(struct acpi_table_header)) { 540 if (length < (sizeof(struct acpi_table_header) + table_entry_size)) {
510 ACPI_BIOS_ERROR((AE_INFO, 541 ACPI_BIOS_ERROR((AE_INFO,
511 "Invalid table length 0x%X in RSDT/XSDT", 542 "Invalid table length 0x%X in RSDT/XSDT",
512 length)); 543 length));
@@ -526,22 +557,21 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
526 return_ACPI_STATUS(status); 557 return_ACPI_STATUS(status);
527 } 558 }
528 559
529 /* Calculate the number of tables described in the root table */ 560 /* Get the number of entries and pointer to first entry */
530 561
531 table_count = (u32)((table->length - sizeof(struct acpi_table_header)) / 562 table_count = (u32)((table->length - sizeof(struct acpi_table_header)) /
532 table_entry_size); 563 table_entry_size);
564 table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header));
565
533 /* 566 /*
534 * First two entries in the table array are reserved for the DSDT 567 * First two entries in the table array are reserved for the DSDT
535 * and FACS, which are not actually present in the RSDT/XSDT - they 568 * and FACS, which are not actually present in the RSDT/XSDT - they
536 * come from the FADT 569 * come from the FADT
537 */ 570 */
538 table_entry =
539 ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
540 acpi_gbl_root_table_list.current_table_count = 2; 571 acpi_gbl_root_table_list.current_table_count = 2;
541 572
542 /* 573 /* Initialize the root table array from the RSDT/XSDT */
543 * Initialize the root table array from the RSDT/XSDT 574
544 */
545 for (i = 0; i < table_count; i++) { 575 for (i = 0; i < table_count; i++) {
546 if (acpi_gbl_root_table_list.current_table_count >= 576 if (acpi_gbl_root_table_list.current_table_count >=
547 acpi_gbl_root_table_list.max_table_count) { 577 acpi_gbl_root_table_list.max_table_count) {
@@ -584,7 +614,7 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
584 acpi_tb_install_table(acpi_gbl_root_table_list.tables[i]. 614 acpi_tb_install_table(acpi_gbl_root_table_list.tables[i].
585 address, NULL, i); 615 address, NULL, i);
586 616
587 /* Special case for FADT - get the DSDT and FACS */ 617 /* Special case for FADT - validate it then get the DSDT and FACS */
588 618
589 if (ACPI_COMPARE_NAME 619 if (ACPI_COMPARE_NAME
590 (&acpi_gbl_root_table_list.tables[i].signature, 620 (&acpi_gbl_root_table_list.tables[i].signature,