aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhao Yakui <yakui.zhao@intel.com>2007-08-24 04:18:16 -0400
committerLen Brown <len.brown@intel.com>2007-08-24 18:46:25 -0400
commit9f3119b70cf189530f1b46a006a052e171a1622f (patch)
treeb6585a7f8421e7410cb4dd6fbb3770d2fdc800a7
parentb377fd3982ad957c796758a90e2988401a884241 (diff)
ACPI: Validate XSDT, use RSDT if XSDT fails
ACPI 1.0 used an RSDT with 32-bit physical addresses. ACPI 2.0 adds an XSDT with 32-bit physical addresses. An ACPI 2.0 aware OS is supposed to use the XSDT (when present) instead of the RSDT. However, several systems have failed because the XSDT contains NULL entries -- while it is missing pointers to needed tables, such as SSDTs. When we find an XSDT with NULL entries, discard it and use the ACPI 1.0 RSDT instead. http://bugzilla.kernel.org/show_bug.cgi?id=8630 Signed-off-by: Zhao Yakui <yakui.zhao@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/acpi/tables/tbutils.c71
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")
51static acpi_physical_address 51static acpi_physical_address
52acpi_tb_get_root_table_entry(u8 * table_entry, 52acpi_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
69static acpi_status
70acpi_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));