* acpi_scan_rsdp() breaks some PCs by not honouring ACPI specification
@ 2007-09-25 7:37 TJ
2007-11-24 1:06 ` Len Brown
0 siblings, 1 reply; 2+ messages in thread
From: TJ @ 2007-09-25 7:37 UTC (permalink / raw)
To: linux-acpi
I've been debugging an ACPI-disabled-at-boot failure on an Acer
Travelmate C104TCi (C100) with a Wistron BIOS.
[ 0.000000] DMI 2.3 present.
[ 0.000000] ACPI: RSDP 000EC2D0, 0014 (r0 Acer )
[ 0.000000] ACPI: \x01 00000000, F000FF5A (r195 Zÿ F000FF57 Zÿ F000FEA5)
[ 27.751333] ACPI: Core revision 20070126
[ 27.751501] ACPI Exception (tbxface-0618): AE_NO_ACPI_TABLES, While
loading namespace from ACPI tables [20070126]
[ 27.751654] ACPI: Unable to load the System Description Tables
[ 27.783596] ACPI: Interpreter disabled.
There are several references to this problem around the net and a couple
of invasive kernel patches that don't address the cause.
I wrote a user-space application that scans memory using the method
described in the ACPI specifications. It reports:
$ sudo ./find-RSDP
find-RSDP version 0.1 © 2007 TJ
Licensed on the terms of GPL version 3
Finds ACPI Root System Descriptor Pointer (for supported BIOS's only).
0x00000000FFFFFFFF Memory size
0x00000000000EC2D0 "RSD PTR "
0x00000000000FE030 "RSD PTR " RSDT @ 0FFE0000 OEM: "Acer " sum: 0
0x0000000005FBFE10 "RSD PTR "
Unfortunately the kernel function
arch/i386/kernel/acpi/boot.c::acpi_scan_rsdp()
doesn't fully implement the ACPI specification - it simply looks for the
first "RSD PTR " signature but doesn't check it has found a valid table
by calculating the checksum.
Because this series of BIOSs happen to have multiple instances of "RSD
PTR " and an invalid instance appears first in memory, the kernel tries
to use an invalid pointer to the RSDT, leading to the problems.
I've prepared a simple patch that calculates the checksum and only
returns an RSDT pointer if the checksum == 0.
Regards,
TJ.
Ubuntu Kernel ACPI Team
== Results With Patch Applied ==
[ 0.000000] BIOS-e820: 000000000ffe0000 - 000000000ffe8000 (ACPI data)
[ 0.000000] BIOS-e820: 000000000ffe8000 - 0000000010000000 (ACPI NVS)
[ 0.000000] ACPI: RSDP signature @ 0xC00EC2D0 checksum 218
[ 0.000000] ACPI: RSDP signature @ 0xC00FE030 checksum 0
[ 0.000000] ACPI: RSDP 000FE030, 0014 (r0 Acer )
[ 0.000000] ACPI: RSDT 0FFE0000, 002C (r1 Acer TM100 1 MSFT 1)
[ 0.000000] ACPI: FACP 0FFE0054, 0074 (r1 Acer TM100 1 MSFT 1)
[ 0.000000] ACPI: DSDT 0FFE00CC, 3E26 (r1 Acer AN100 1000 MSFT 100000E)
[ 0.000000] ACPI: FACS 0FFE8000, 0040
[ 0.000000] ACPI: BOOT 0FFE002C, 0028 (r1 Acer TM100 1 MSFT 1)
[ 0.000000] ACPI: PM-Timer IO Port: 0xf008
[ 18.351112] ACPI: Core revision 20070126
[ 18.351387] ACPI: Looking for DSDT in initramfs... successfully read 13997 bytes from /DSDT.aml.
[ 18.351656] ACPI: Table DSDT replaced by host OS
[ 18.351784] ACPI: DSDT 00000000, 36AD (r1 Acer AN100 1000 INTL 20061109)
[ 18.355337] ACPI: setting ELCR to 0200 (from 0c00)
[ 18.407892] ACPI: bus type pci registered
[ 18.438953] ACPI: EC: Look up EC in DSDT
[ 18.445067] ACPI: EC: GPE=0x18, ports=0x66, 0x62
[ 18.451387] ACPI: Interpreter enabled
[ 18.451446] ACPI: (supports S0 S3 S4 S5)
[ 18.451694] ACPI: Using PIC for interrupt routing
[ 18.472224] ACPI: EC: GPE=0x18, ports=0x66, 0x62
[ 18.472379] ACPI: PCI Root Bridge [PCI0] (0000:00)
[ 18.473052] PCI quirk: region f000-f03f claimed by PIIX4 ACPI
[ 18.473388] ACPI: PCI Interrupt Routing Table [\_SB_.PCI0._PRT]
[ 18.476877] ACPI: PCI Interrupt Link [PILA] (IRQs *10 15)
[ 18.477341] ACPI: PCI Interrupt Link [PILB] (IRQs *11 15)
[ 18.477796] ACPI: PCI Interrupt Link [PILD] (IRQs *10 15)
[ 18.478266] pnp: PnP ACPI init
[ 18.478338] ACPI: bus type pnp registered
[ 18.489473] pnp: PnP ACPI: found 10 devices
[ 18.489535] ACPI: ACPI bus type pnp unregistered
[ 18.489597] PnPBIOS: Disabled by ACPI PNP
[ 18.489773] PCI: Using ACPI for IRQ routing
[ 18.534358] ACPI: PCI Interrupt Link [PILA] enabled at IRQ 10
[ 18.534429] ACPI: PCI Interrupt 0000:00:03.0[A] -> Link [PILA] -> GSI 10 (level, low) -> IRQ 10
[ 18.534590] ACPI: PCI Interrupt 0000:00:03.1[A] -> Link [PILA] -> GSI 10 (level, low) -> IRQ 10
[ 20.334950] ACPI: PCI Interrupt Link [PILB] enabled at IRQ 11
[ 20.335025] ACPI: PCI Interrupt 0000:00:00.2[B] -> Link [PILB] -> GSI 11 (level, low) -> IRQ 11
[ 20.335180] ACPI: PCI interrupt for device 0000:00:00.2 disabled
[ 20.794419] ACPI: CPU0 (power states: C1[C1] C2[C2] C3[C3] C4[C3])
[ 20.807239] ACPI: Thermal Zone [THR1] (32 C)
[ 20.817398] ACPI: Thermal Zone [THR2] (30 C)
[ 22.067049] ACPI: PCI Interrupt Link [PILD] enabled at IRQ 10
[ 22.068169] ACPI: PCI Interrupt 0000:00:05.0[A] -> Link [PILD] -> GSI 10 (level, low) -> IRQ 10
[ 22.173209] ACPI: PCI Interrupt 0000:00:04.0[A] -> Link [PILD] -> GSI 10 (level, low) -> IRQ 10
[ 22.474602] ACPI: PCI Interrupt 0000:00:07.2[D] -> Link [PILD] -> GSI 10 (level, low) -> IRQ 10
[ 23.608000] ACPI: PCI Interrupt 0000:00:00.1[B] -> Link [PILB] -> GSI 11 (level, low) -> IRQ 11
== Patch ==
--- arch/i386/kernel/acpi/boot.c.orig 2007-09-25 02:17:12.000000000 +0100
+++ arch/i386/kernel/acpi/boot.c 2007-09-25 08:31:05.000000000 +0100
@@ -592,9 +592,25 @@
* RSDP signature.
*/
for (offset = 0; offset < length; offset += 16) {
- if (strncmp((char *)(phys_to_virt(start) + offset), "RSD PTR ", sig_len))
- continue;
- return (start + offset);
+ if (strncmp((char *)(phys_to_virt(start) + offset), "RSD PTR ", sig_len) == 0) {
+ /* 2007-09-24 TJ <linux@tjworld.net>
+ * The ACPI specification states the first 20 bytes of the RSDP table
+ * must have a checksum of 0 (ACPI 1.0b RSDP table is 20 bytes long).
+ * The signature can appear in multiple memory locations so don't rely
+ * on it as the sole proof of a valid table.
+ * This fixes broken/disabled ACPI problems with Acer Travelmate C100
+ * (and others) where the first signature match is accepted without
+ * confirming the checksum.
+ */
+ unsigned int i;
+ unsigned char checksum;
+ unsigned char *table = (unsigned char *)(phys_to_virt(start) + offset);
+ for (checksum = 0, i = 0; i < 20; i++)
+ checksum += table[i];
+
+ printk(KERN_WARNING PREFIX "RSDP signature @ 0x%0.8lX checksum %d\n", table, checksum);
+ if (checksum == 0) return (start + offset);
+ }
}
return 0;
-
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: acpi_scan_rsdp() breaks some PCs by not honouring ACPI specification
2007-09-25 7:37 acpi_scan_rsdp() breaks some PCs by not honouring ACPI specification TJ
@ 2007-11-24 1:06 ` Len Brown
0 siblings, 0 replies; 2+ messages in thread
From: Len Brown @ 2007-11-24 1:06 UTC (permalink / raw)
To: TJ; +Cc: linux-acpi
TJ,
Please try this patch.
thanks,
-Len
ACPI: tables: complete searching upon RSDP w/ bad checksum.
From: Len Brown <len.brown@intel.com>
ACPI tables follow a tree structure in memory.
The root of the tree is the RSDP (Root System Description Pointer).
To find the RSDP, the OS searches for the signature "RSD PTR "
in well known physical memory locations. Then the OS computes
a table checksum to verify that the signature is really part
of a valid table header.
Some systems have a proper signature but an invalid checksum;
followed elsewhere by a proper signature with valid checksum.
http://bugzilla.kernel.org/show_bug.cgi?id=9444
The Linux RSDP scanning code bailed out on those systems
and as a result they booted with ACPI disabled.
Fix this by deleting the Linux RSDP scanning code and
plugging in the ACPICA RSDP scanning code.
Signed-off-by: Len Brown <len.brown@intel.com>
---
arch/x86/kernel/acpi/boot.c | 40 -----------------------------
arch/x86/kernel/srat_32.c | 2 -
drivers/acpi/osl.c | 8 ++++-
drivers/acpi/tables/Makefile | 2 -
drivers/acpi/tables/tbxfroot.c | 4 --
include/linux/acpi.h | 1
6 files changed, 9 insertions(+), 48 deletions(-)
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 0ca27c7..719c74b 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -581,25 +581,6 @@ int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
EXPORT_SYMBOL(acpi_unregister_ioapic);
-static unsigned long __init
-acpi_scan_rsdp(unsigned long start, unsigned long length)
-{
- unsigned long offset = 0;
- unsigned long sig_len = sizeof("RSD PTR ") - 1;
-
- /*
- * Scan all 16-byte boundaries of the physical memory region for the
- * RSDP signature.
- */
- for (offset = 0; offset < length; offset += 16) {
- if (strncmp((char *)(phys_to_virt(start) + offset), "RSD PTR ", sig_len))
- continue;
- return (start + offset);
- }
-
- return 0;
-}
-
static int __init acpi_parse_sbf(struct acpi_table_header *table)
{
struct acpi_table_boot *sb;
@@ -742,27 +723,6 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table)
return 0;
}
-unsigned long __init acpi_find_rsdp(void)
-{
- unsigned long rsdp_phys = 0;
-
- if (efi_enabled) {
- if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
- return efi.acpi20;
- else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
- return efi.acpi;
- }
- /*
- * Scan memory looking for the RSDP signature. First search EBDA (low
- * memory) paragraphs and then search upper memory (E0000-FFFFF).
- */
- rsdp_phys = acpi_scan_rsdp(0, 0x400);
- if (!rsdp_phys)
- rsdp_phys = acpi_scan_rsdp(0xE0000, 0x20000);
-
- return rsdp_phys;
-}
-
#ifdef CONFIG_X86_LOCAL_APIC
/*
* Parse LAPIC entries in MADT
diff --git a/arch/x86/kernel/srat_32.c b/arch/x86/kernel/srat_32.c
index 2a8713e..b3b2c95 100644
--- a/arch/x86/kernel/srat_32.c
+++ b/arch/x86/kernel/srat_32.c
@@ -276,7 +276,7 @@ int __init get_memcfg_from_srat(void)
int tables = 0;
int i = 0;
- rsdp_address = acpi_find_rsdp();
+ rsdp_address = acpi_os_get_root_pointer();
if (!rsdp_address) {
printk("%s: System description tables not found\n",
__FUNCTION__);
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index aabc6ca..101691e 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -207,8 +207,12 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
"System description tables not found\n");
return 0;
}
- } else
- return acpi_find_rsdp();
+ } else {
+ acpi_physical_address pa = 0;
+
+ acpi_find_root_pointer(&pa);
+ return pa;
+ }
}
void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
diff --git a/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile
index 0a7d7af..7385efa 100644
--- a/drivers/acpi/tables/Makefile
+++ b/drivers/acpi/tables/Makefile
@@ -2,6 +2,6 @@
# Makefile for all Linux ACPI interpreter subdirectories
#
-obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o
+obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o
EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
index cf8fa51..9ecb4b6 100644
--- a/drivers/acpi/tables/tbxfroot.c
+++ b/drivers/acpi/tables/tbxfroot.c
@@ -100,7 +100,7 @@ static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
/*******************************************************************************
*
- * FUNCTION: acpi_tb_find_rsdp
+ * FUNCTION: acpi_find_root_pointer
*
* PARAMETERS: table_address - Where the table pointer is returned
*
@@ -219,8 +219,6 @@ acpi_status acpi_find_root_pointer(acpi_native_uint * table_address)
return_ACPI_STATUS(AE_NOT_FOUND);
}
-ACPI_EXPORT_SYMBOL(acpi_find_root_pointer)
-
/*******************************************************************************
*
* FUNCTION: acpi_tb_scan_memory_for_rsdp
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 8ccedf7..8deb611 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -79,7 +79,6 @@ typedef int (*acpi_table_handler) (struct acpi_table_header *table);
typedef int (*acpi_table_entry_handler) (struct acpi_subtable_header *header, const unsigned long end);
char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
-unsigned long acpi_find_rsdp (void);
int acpi_boot_init (void);
int acpi_boot_table_init (void);
int acpi_numa_init (void);
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2007-11-24 1:07 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-09-25 7:37 acpi_scan_rsdp() breaks some PCs by not honouring ACPI specification TJ
2007-11-24 1:06 ` Len Brown
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.