diff options
| -rw-r--r-- | drivers/acpi/tables/tbutils.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c index 1da64b4518c0..8cc9492ffbf2 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/tables/tbutils.c | |||
| @@ -51,6 +51,65 @@ ACPI_MODULE_NAME("tbutils") | |||
| 51 | static acpi_physical_address | 51 | static acpi_physical_address |
| 52 | acpi_tb_get_root_table_entry(u8 * table_entry, | 52 | acpi_tb_get_root_table_entry(u8 * table_entry, |
| 53 | acpi_native_uint table_entry_size); | 53 | acpi_native_uint table_entry_size); |
| 54 | /******************************************************************************* | ||
| 55 | * | ||
| 56 | * FUNCTION: acpi_tb_check_xsdt | ||
| 57 | * | ||
| 58 | * PARAMETERS: address - Pointer to the XSDT | ||
| 59 | * | ||
| 60 | * RETURN: status | ||
| 61 | * AE_OK - XSDT is okay | ||
| 62 | * AE_NO_MEMORY - can't map XSDT | ||
| 63 | * AE_INVALID_TABLE_LENGTH - invalid table length | ||
| 64 | * AE_NULL_ENTRY - XSDT has NULL entry | ||
| 65 | * | ||
| 66 | * DESCRIPTION: validate XSDT | ||
| 67 | ******************************************************************************/ | ||
| 68 | |||
| 69 | static acpi_status | ||
| 70 | acpi_tb_check_xsdt(acpi_physical_address address) | ||
| 71 | { | ||
| 72 | struct acpi_table_header *table; | ||
| 73 | u32 length; | ||
| 74 | u64 xsdt_entry_address; | ||
| 75 | u8 *table_entry; | ||
| 76 | u32 table_count; | ||
| 77 | int i; | ||
| 78 | |||
| 79 | table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); | ||
| 80 | if (!table) | ||
| 81 | return AE_NO_MEMORY; | ||
| 82 | |||
| 83 | length = table->length; | ||
| 84 | acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); | ||
| 85 | if (length < sizeof(struct acpi_table_header)) | ||
| 86 | return AE_INVALID_TABLE_LENGTH; | ||
| 87 | |||
| 88 | table = acpi_os_map_memory(address, length); | ||
| 89 | if (!table) | ||
| 90 | return AE_NO_MEMORY; | ||
| 91 | |||
| 92 | /* Calculate the number of tables described in XSDT */ | ||
| 93 | table_count = | ||
| 94 | (u32) ((table->length - | ||
| 95 | sizeof(struct acpi_table_header)) / sizeof(u64)); | ||
| 96 | table_entry = | ||
| 97 | ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header); | ||
| 98 | for (i = 0; i < table_count; i++) { | ||
| 99 | ACPI_MOVE_64_TO_64(&xsdt_entry_address, table_entry); | ||
| 100 | if (!xsdt_entry_address) { | ||
| 101 | /* XSDT has NULL entry */ | ||
| 102 | break; | ||
| 103 | } | ||
| 104 | table_entry += sizeof(u64); | ||
| 105 | } | ||
| 106 | acpi_os_unmap_memory(table, length); | ||
| 107 | |||
| 108 | if (i < table_count) | ||
| 109 | return AE_NULL_ENTRY; | ||
| 110 | else | ||
| 111 | return AE_OK; | ||
| 112 | } | ||
| 54 | 113 | ||
| 55 | /******************************************************************************* | 114 | /******************************************************************************* |
| 56 | * | 115 | * |
| @@ -341,6 +400,7 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags) | |||
| 341 | u32 table_count; | 400 | u32 table_count; |
| 342 | struct acpi_table_header *table; | 401 | struct acpi_table_header *table; |
| 343 | acpi_physical_address address; | 402 | acpi_physical_address address; |
| 403 | acpi_physical_address rsdt_address; | ||
| 344 | u32 length; | 404 | u32 length; |
| 345 | u8 *table_entry; | 405 | u8 *table_entry; |
| 346 | acpi_status status; | 406 | acpi_status status; |
| @@ -369,6 +429,8 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags) | |||
| 369 | */ | 429 | */ |
| 370 | address = (acpi_physical_address) rsdp->xsdt_physical_address; | 430 | address = (acpi_physical_address) rsdp->xsdt_physical_address; |
| 371 | table_entry_size = sizeof(u64); | 431 | table_entry_size = sizeof(u64); |
| 432 | rsdt_address = (acpi_physical_address) | ||
| 433 | rsdp->rsdt_physical_address; | ||
| 372 | } else { | 434 | } else { |
| 373 | /* Root table is an RSDT (32-bit physical addresses) */ | 435 | /* Root table is an RSDT (32-bit physical addresses) */ |
| 374 | 436 | ||
| @@ -382,6 +444,15 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags) | |||
| 382 | */ | 444 | */ |
| 383 | acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp)); | 445 | acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp)); |
| 384 | 446 | ||
| 447 | if (table_entry_size == sizeof(u64)) { | ||
| 448 | if (acpi_tb_check_xsdt(address) == AE_NULL_ENTRY) { | ||
| 449 | /* XSDT has NULL entry, RSDT is used */ | ||
| 450 | address = rsdt_address; | ||
| 451 | table_entry_size = sizeof(u32); | ||
| 452 | ACPI_WARNING((AE_INFO, "BIOS XSDT has NULL entry," | ||
| 453 | "using RSDT")); | ||
| 454 | } | ||
| 455 | } | ||
| 385 | /* Map the RSDT/XSDT table header to get the full table length */ | 456 | /* Map the RSDT/XSDT table header to get the full table length */ |
| 386 | 457 | ||
| 387 | table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); | 458 | table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); |
