[PATCH] Override DSDT and SSDTs via initramfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

you find some comments inlined and the patch which is shipped in
OpenSUSE at the end.

On Fri, 2008-01-25 at 23:39 -0500, Len Brown wrote:
> > > I am annoyed by this missing (or rejected) feature upstream : DSDT
> > >   http://gaugusch.at/kernel.shtml
> > > 
> > > So to use "custom DSDT loading" I have to patch my laptop buggy BIOS
> > > 
> > > As usual, I reported this issue to the vendor (which goes nowhere so far) :
> > >   http://support.fujitsu-siemens.de/forum/viewtopic.php?p=37001
> > > 
> > > Hopefully many distro already include this patch, but not all of them
> > > such as debian :
> > >   http://bugs.debian.org/251023
> > >   http://wiki.debian.org/DebianKernelPatchAcceptanceGuidelines
> > > 
> > > So as a debian contributor, I keep staying on debian and compile my own
> > > kernel
> > >   and provide it to a "amiloa laptop" community I am managing :
> > >   http://tech.groups.yahoo.com/group/amilo/
> > > 
> > > It's ok for me I can live with this,  but what average users have to do
> > > with their (buggy) hardware ?
> > 
> > Philosophically speaking: we sholdn't be making decisions for other people
> > like this.
> > 
> > Practically speaking: the fact that distros are shipping it is a huge
> > indication that the decision was wrong.
IMO, Vista providing a feature to easily override the DSDT via a simple
registry pointer to a modified DSDT, is an argument you cannot come
around...

The purpose of the feature should definitely not be to provide the
possibility to workaround buggy BIOSes, but as done by Vista for
debugging and testing.
 
> > Len?  I think we goofed here.
> 
> Here is the existing supported DSDT override method:
> 
> http://www.lesswatts.org/projects/acpi/overridingDSDT.php
> 
> and at the bottom of that page I point to the alternate initrd
> method and explain why I've not applied it upstream.
> 
> My goal for the Linux/ACPI project is to make Linux
> work out-of-the-box on any system where Windows works.
> 
> Giving "Joe User", who is incapable of compiling
> a kernel, an easy method to override his BIOS image
> makes him more likely to settle for a workaround.
> And that effort undermines, rather than supports, our goal.
> 
> However, Philippe points out that the FSC Amilo box
> also fails the same way under Windows -- and the
> vendor is unwilling or unable to fix their BIOS.
> While Phillippe could build a kernel from source
> and link in a DSDT via the supported developer method above,
> or he could run SuSE or Ubuntu which include the initrd
> patch, he'd prefer to track Debian w/o re-compiling.
> 
> I'm fine with making it more convenient for
> FSC Amilo ownersr to make their laptops work better
> under Linux than under Windows -- even if it is impossible
> for a Linux distro to support the resulting configuration.
> They're otherwise stuck with junk hardware or extra work.
> 
> Also, Thomas continues to assert that this patch
> makes SuSE easier to debug in the field b/c he can convince
> users who are unable to re-compile their kernel
> go ahead and override their BIOS image for debugging
> (bless their trusting hearts;-)
> 
> So at the risk that we're giving "Joe User" more
> than enough rope to hang themselves, lets do it --
> with some strings attached...
> 
> Thomas,
> Since you've been a big supporter of this patch, perhaps you
> can update it and submit it to the list for review?
> 
> I think it needs the following changes:
> 
> 1. tainted bit needs to be set when a DSDT override is used.
>    (this is common both to the new patch and the current
>     override method)
> 
> 2. upon setting the tainted bit, print a BIG FAT WARNING
>    that this is not a supported configuration.
> 
> 3. cmdline option needs to be available to disable
>    an override.  Otherwise a bad image in the intrd
>    may be a serious pickle for some users.
> 
> 4. get rid of alarming failure message:
> 
> +	printk(KERN_INFO "Looking for DSDT in initrd ...");
> ...
> +	printk(" not found!\n");
> 
> Probably it is best to forward the original patch
> w/ proper credits, and then send updates to address 1-4.

I do not know who initially came up with this, I just modified/adjusted
the patch sometimes. I expect it's Markus, possibly Eric or best both
who should be mentioned as author.

The patch should be against a quite recent vanilla kernel, tell me if
you have problems with patching/merging and tell me against which
kernel/git version/tree you like to have it.

Jeff (Mahony) has adjusted the last bits of it when he updated it to the
latest rcX-gitY version:
Changes:
 We no longer call populate_rootfs() twice. If we want the custom DSDT,
 we load the rootfs before ACPI. Otherwise, it is loaded at the
appropriate
 initcall time. -jeffm
 There is a new version at
http://gaugusch.at/acpi-dsdt-initrd-patches/acpi-dsdt-initrd-v0.8.4-2.6.21.patch,
 but there doesn't seem to be any real changes other than elminating the
file
 name array.

In fact, I added the array some time ago.
Not sure whether the latest Version of Eric/Markus can also load several
DSDT/SSDTs? Maybe you found a more elegant way?
This is a quite useful feature (which is not provided by the current
"override via compile into kernel" method). You can add several SSDTs
and let them load before any other table is loaded. Duplicated tables
will be ignored later. Like this you can also override single and
multiple SSDTs easily.

There just need to be files:
/DSDT.aml, /SSDT[1-9]?.aml
in the initrd fs.

If you take this one, please do not forget to mention Eric and Markus as
authors.

    Thomas

-----------------

Override DSDT and SSDTs via initramfs

Searches and reads in the root of initramfs a DSDT.aml and SSDT[1-9]?.aml files.
The found DSDT and SSDTs are loaded into the ACPI namespace prior any BIOS
provided table. Later (BIOS provided) tables with the same signature are ignored
automatically. Like that the BIOS provided tables can be replaced.

Once a table is loaded via initrd, the kernel gets tainted.

More information can be found here: http://gaugusch.at/kernel.shtml


Signed-off-by: Thomas Renninger <trenn@xxxxxxx>

---

 drivers/acpi/Kconfig    |   17 ++++++
 drivers/acpi/osl.c      |  127 ++++++++++++++++++++++++++++++++++++++++++++++--
 include/acpi/acpiosxf.h |    4 +
 init/initramfs.c        |    4 +
 init/main.c             |    9 +++
 5 files changed, 156 insertions(+), 5 deletions(-)

Signed-off-by: Thomas Renninger <trenn@xxxxxxx>
Signed-off-by: Jeff Mahoney <jeffm@xxxxxxxx>

--- linux-2.6.24.orig/drivers/acpi/Kconfig
+++ linux-2.6.24/drivers/acpi/Kconfig
@@ -274,6 +274,23 @@ config ACPI_CUSTOM_DSDT_FILE
 	  Enter the full path name to the file which includes the AmlCode
 	  declaration.
 
+config ACPI_CUSTOM_DSDT_INITRD
+	bool "Read Custom DSDT from initramfs"
+	depends on BLK_DEV_INITRD
+	default y
+	help
+	  The DSDT (Differentiated System Description Table) often needs to be
+	  overridden because of broken BIOS implementations. If this feature is
+	  activated you will be able to provide a customized DSDT by adding it
+	  to your initramfs.  For now you need to use a special mkinitrd tool.
+	  For more details see <file:Documentation/dsdt-initrd.txt> or
+	  <http://gaugusch.at/kernel.shtml>. If there is no table found, it
+	  will fallback to the custom DSDT in-kernel (if activated) or to the
+	  DSDT from the BIOS.
+
+	  Even if you do not need a new one at the moment, you may want to use a
+	  better implemented DSDT later. It is safe to say Y here.
+
 config ACPI_BLACKLIST_YEAR
 	int "Disable ACPI for systems before Jan 1st this year" if X86_32
 	default 0
--- linux-2.6.24.orig/drivers/acpi/osl.c
+++ linux-2.6.24/drivers/acpi/osl.c
@@ -68,6 +68,10 @@ EXPORT_SYMBOL(acpi_in_debugger);
 extern char line_buf[80];
 #endif				/*ENABLE_DEBUGGER */
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+int acpi_must_unregister_table = FALSE;
+#endif
+
 static unsigned int acpi_irq_irq;
 static acpi_osd_handler acpi_irq_handler;
 static void *acpi_irq_context;
@@ -312,6 +316,113 @@ acpi_os_predefined_override(const struct
 	return AE_OK;
 }
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+#define MAX_DS_SDTS 10
+static struct acpi_table_header *ds_sdt_buffers[MAX_DS_SDTS];
+static unsigned int tables_loaded = 0;
+
+void acpi_load_override_tables(void){
+	struct file         *firmware_file;
+	mm_segment_t        oldfs;
+	unsigned long       len, len2;
+	struct kstat        stat;
+	unsigned int        x, y;
+	char *ramfs_ds_sdt_names[MAX_DS_SDTS] = {
+		"/DSDT.aml",
+		"/SSDT.aml",
+		"/SSDT1.aml",
+		"/SSDT2.aml",
+		"/SSDT3.aml",
+		"/SSDT4.aml",
+		"/SSDT5.aml",
+		"/SSDT6.aml",
+		"/SSDT7.aml",
+		"/SSDT8.aml",
+	};
+	/*
+	 * Never do this at home, only the user-space is allowed to open a file.
+	 * The clean way would be to use the firmware loader. But this code must be run
+	 * before there is any userspace available. So we need a static/init firmware
+	 * infrastructure, which doesn't exist yet...
+	 */
+	for (x = 0; x < MAX_DS_SDTS; x++){
+		if (vfs_stat(ramfs_ds_sdt_names[x], &stat) < 0) {
+			continue;
+		}
+		len = stat.size;
+		/* check especially against empty files */
+		if (len <= 4) {
+			printk("error file %s is too small, only %lu bytes.\n",
+			       ramfs_ds_sdt_names[x], len);
+			continue;
+		}
+
+		ds_sdt_buffers[x] = kmalloc(len, GFP_KERNEL);
+		if (!ds_sdt_buffers[x]) {
+			printk("error when allocating %lu bytes of memory.\n",
+			       len);
+			/* better free all tables again */
+			for (y = 0; y < x; y++){
+				if (ds_sdt_buffers[y])
+					kfree(ds_sdt_buffers[x]);
+			}
+			acpi_must_unregister_table = FALSE;
+			return;
+		}
+
+		firmware_file = filp_open(ramfs_ds_sdt_names[x], O_RDONLY, 0);
+		if (IS_ERR(firmware_file)) {
+			printk("error, could not open file %s.\n",
+			       ramfs_ds_sdt_names[x]);
+			kfree(ds_sdt_buffers[x]);
+			continue;
+		}
+
+		oldfs = get_fs();
+		set_fs(KERNEL_DS);
+		len2 = vfs_read(firmware_file,
+				(char __user *)ds_sdt_buffers[x],
+				len,
+				&firmware_file->f_pos);
+		set_fs(oldfs);
+		filp_close(firmware_file, NULL);
+		if (len2 < len) {
+			printk("error trying to read %lu bytes from %s.\n",
+			       len, ramfs_ds_sdt_names[x]);
+			kfree(ds_sdt_buffers[x]);
+			continue;
+		}
+		printk(PREFIX "successfully read %lu bytes from file %s\n",
+		       len, ramfs_ds_sdt_names[x]);
+	}
+}
+
+struct acpi_table_header * acpi_find_dsdt_initrd(struct acpi_table_header * t)
+{
+	struct acpi_table_header	*ret = NULL;
+	unsigned int                     x;
+	for (x = 0; x < MAX_DS_SDTS; x++){
+		if (ds_sdt_buffers[x]){
+			if (!memcmp(ds_sdt_buffers[x]->signature,
+				    t->signature, 4) &&
+			    !memcmp(ds_sdt_buffers[x]->oem_table_id,
+				    t->oem_table_id, 8)){
+				ret = ds_sdt_buffers[x];
+				printk(PREFIX "Override [%4.4s-%8.8s]"
+				       " from initramfs -"
+				       " tainting kernel\n",
+				       t->signature,
+				       t->oem_table_id);
+				add_taint(TAINT_NO_SUPPORT);
+				acpi_must_unregister_table = TRUE;
+				break;
+			}
+		}
+	}
+	return ret;
+}
+#endif
+
 acpi_status
 acpi_os_table_override(struct acpi_table_header * existing_table,
 		       struct acpi_table_header ** new_table)
@@ -319,13 +430,21 @@ acpi_os_table_override(struct acpi_table
 	if (!existing_table || !new_table)
 		return AE_BAD_PARAMETER;
 
+	*new_table = NULL;
+
 #ifdef CONFIG_ACPI_CUSTOM_DSDT
 	if (strncmp(existing_table->signature, "DSDT", 4) == 0)
 		*new_table = (struct acpi_table_header *)AmlCode;
-	else
-		*new_table = NULL;
-#else
-	*new_table = NULL;
+#endif
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+	if (!tables_loaded){
+		acpi_load_override_tables();
+		tables_loaded = 1;
+	}
+	if (!strncmp(existing_table->signature, "DSDT", 4) ||
+	    !strncmp(existing_table->signature, "SSDT", 4)){
+		*new_table = acpi_find_dsdt_initrd(existing_table);
+	}
 #endif
 	return AE_OK;
 }
--- linux-2.6.24.orig/include/acpi/acpiosxf.h
+++ linux-2.6.24/include/acpi/acpiosxf.h
@@ -95,6 +95,10 @@ acpi_status
 acpi_os_table_override(struct acpi_table_header *existing_table,
 		       struct acpi_table_header **new_table);
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+extern int acpi_must_unregister_table;
+#endif
+
 /*
  * Spinlock primitives
  */
--- linux-2.6.24.orig/init/initramfs.c
+++ linux-2.6.24/init/initramfs.c
@@ -541,7 +541,7 @@ skip:
 
 #endif
 
-static int __init populate_rootfs(void)
+int __init populate_rootfs(void)
 {
 	char *err = unpack_to_rootfs(__initramfs_start,
 			 __initramfs_end - __initramfs_start, 0);
@@ -582,4 +582,6 @@ static int __init populate_rootfs(void)
 #endif
 	return 0;
 }
+#ifndef CONFIG_ACPI_CUSTOM_DSDT_INITRD
 rootfs_initcall(populate_rootfs);
+#endif
--- linux-2.6.24.orig/init/main.c
+++ linux-2.6.24/init/main.c
@@ -102,6 +102,12 @@ static inline void mark_rodata_ro(void) 
 extern void tc_init(void);
 #endif
 
+#ifdef CONFIG_BLK_DEV_INITRD
+extern int populate_rootfs(void);
+#else
+static inline void populate_rootfs(void) {}
+#endif
+
 enum system_states system_state;
 EXPORT_SYMBOL(system_state);
 
@@ -642,6 +648,9 @@ asmlinkage void __init start_kernel(void
 
 	check_bugs();
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+	populate_rootfs(); /* For DSDT override from initramfs */
+#endif
 	acpi_early_init(); /* before LAPIC and SMP init */
 
 	/* Do the rest non-__init'ed, we're now alive */


-
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux