- patches.suse/acpi-dsdt-initrd-v0.9a-2.6.25.patch: ACPI:
authorThomas Renninger <trenn@suse.de>
Mon, 19 May 2008 07:45:46 +0000 (07:45 +0000)
committerThomas Renninger <trenn@suse.de>
Mon, 19 May 2008 07:45:46 +0000 (07:45 +0000)
  initramfs DSDT override support.
  -> Did not make it into 2.6.25 again...
- Update config files.

suse-commit: eb0284e6019098251300b556ccb8bcdbc114b0b4

Documentation/acpi/dsdt-override.txt
Documentation/acpi/initramfs-add-dsdt.sh [new file with mode: 0644]
Documentation/kernel-parameters.txt
drivers/acpi/Kconfig
drivers/acpi/osl.c
init/initramfs.c

index febbb1b..5008f25 100644 (file)
@@ -1,7 +1,15 @@
-Linux supports a method of overriding the BIOS DSDT:
+Linux supports two methods of overriding the BIOS DSDT:
 
 CONFIG_ACPI_CUSTOM_DSDT builds the image into the kernel.
 
-When to use this method is described in detail on the
+CONFIG_ACPI_CUSTOM_DSDT_INITRD adds the image to the initrd.
+
+When to use these methods is described in detail on the
 Linux/ACPI home page:
 http://www.lesswatts.org/projects/acpi/overridingDSDT.php
+
+Note that if both options are used, the DSDT supplied
+by the INITRD method takes precedence.
+
+Documentation/initramfs-add-dsdt.sh is provided for convenience
+for use with the CONFIG_ACPI_CUSTOM_DSDT_INITRD method.
diff --git a/Documentation/acpi/initramfs-add-dsdt.sh b/Documentation/acpi/initramfs-add-dsdt.sh
new file mode 100644 (file)
index 0000000..17ef6e8
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Adds a DSDT file to the initrd (if it's an initramfs)
+# first argument is the name of archive
+# second argument is the name of the file to add
+# The file will be copied as /DSDT.aml
+
+# 20060126: fix "Premature end of file" with some old cpio (Roland Robic)
+# 20060205: this time it should really work
+
+# check the arguments
+if [ $# -ne 2 ]; then
+       program_name=$(basename $0)
+       echo "\
+$program_name: too few arguments
+Usage: $program_name initrd-name.img DSDT-to-add.aml
+Adds a DSDT file to an initrd (in initramfs format)
+
+  initrd-name.img: filename of the initrd in initramfs format
+  DSDT-to-add.aml: filename of the DSDT file to add
+  " 1>&2
+    exit 1
+fi
+
+# we should check it's an initramfs
+
+tempcpio=$(mktemp -d)
+# cleanup on exit, hangup, interrupt, quit, termination
+trap 'rm -rf $tempcpio' 0 1 2 3 15
+
+# extract the archive
+gunzip -c "$1" > "$tempcpio"/initramfs.cpio || exit 1
+
+# copy the DSDT file at the root of the directory so that we can call it "/DSDT.aml"
+cp -f "$2" "$tempcpio"/DSDT.aml
+
+# add the file
+cd "$tempcpio"
+(echo DSDT.aml | cpio --quiet -H newc -o -A -O "$tempcpio"/initramfs.cpio) || exit 1
+cd "$OLDPWD"
+
+# re-compress the archive
+gzip -c "$tempcpio"/initramfs.cpio > "$1"
+
index 1b527b9..b6da2ee 100644 (file)
@@ -172,6 +172,9 @@ and is between 256 and 4096 characters. It is defined in the file
 
        acpi_no_auto_ssdt       [HW,ACPI] Disable automatic loading of SSDT
 
+       acpi_no_initrd_override [KNL,ACPI]
+                       Disable loading custom ACPI tables from the initramfs
+
        acpi_os_name=   [HW,ACPI] Tell ACPI BIOS the name of the OS
                        Format: To spoof as Windows 98: ="Microsoft Windows"
 
index ee7bdcc..4c29a7f 100644 (file)
@@ -300,6 +300,17 @@ config ACPI_CUSTOM_DSDT
        bool
        default ACPI_CUSTOM_DSDT_FILE != ""
 
+config ACPI_CUSTOM_DSDT_INITRD
+       bool "Read Custom DSDT from initramfs"
+       depends on BLK_DEV_INITRD
+       default n
+       help
+         This option supports a custom DSDT by optionally loading it from initrd.
+         See Documentation/acpi/dsdt-override.txt
+
+         If you are not using this feature now, but may use it 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
index a697fb6..8fa630f 100644 (file)
@@ -91,6 +91,11 @@ static DEFINE_SPINLOCK(acpi_res_lock);
 #define        OSI_STRING_LENGTH_MAX 64        /* arbitrary */
 static char osi_additional_string[OSI_STRING_LENGTH_MAX];
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+static int acpi_no_initrd_override;
+extern struct acpi_table_header *acpi_find_dsdt_initrd(void);
+#endif
+
 /*
  * "Ode to _OSI(Linux)"
  *
@@ -333,6 +338,16 @@ acpi_os_table_override(struct acpi_table_header * existing_table,
        if (strncmp(existing_table->signature, "DSDT", 4) == 0)
                *new_table = (struct acpi_table_header *)AmlCode;
 #endif
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+       if ((strncmp(existing_table->signature, "DSDT", 4) == 0) &&
+           !acpi_no_initrd_override) {
+               struct acpi_table_header *initrd_table;
+
+               initrd_table = acpi_find_dsdt_initrd();
+               if (initrd_table)
+                       *new_table = initrd_table;
+       }
+#endif
        if (*new_table != NULL) {
                printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], "
                           "this is unsafe: tainting kernel\n",
@@ -343,6 +358,15 @@ acpi_os_table_override(struct acpi_table_header * existing_table,
        return AE_OK;
 }
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+static int __init acpi_no_initrd_override_setup(char *s)
+{
+       acpi_no_initrd_override = 1;
+       return 1;
+}
+__setup("acpi_no_initrd_override", acpi_no_initrd_override_setup);
+#endif
+
 static irqreturn_t acpi_irq(int irq, void *dev_id)
 {
        u32 handled;
index d53fee8..cf7582b 100644 (file)
@@ -6,6 +6,9 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/syscalls.h>
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+#include <acpi/acpi.h>
+#endif
 
 static __initdata char *message;
 static void __init error(char *x)
@@ -90,6 +93,12 @@ static __initdata unsigned long body_len, name_len;
 static __initdata uid_t uid;
 static __initdata gid_t gid;
 static __initdata unsigned rdev;
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+static __initdata char *file_looked_for;
+static __initdata struct acpi_table_header *file_mem;
+#else
+const char *file_looked_for = NULL;
+#endif
 
 static void __init parse_header(char *s)
 {
@@ -123,6 +132,7 @@ static __initdata enum state {
        SkipIt,
        GotName,
        CopyFile,
+       CopyFileMem,
        GotSymlink,
        Reset
 } state, next_state;
@@ -267,6 +277,9 @@ static int __init do_name(void)
                free_hash();
                return 0;
        }
+       if (file_looked_for && S_ISREG(mode) &&
+               (strcmp(collected, file_looked_for) == 0))
+               state = CopyFileMem;
        if (dry_run)
                return 0;
        clean_path(collected, mode);
@@ -299,6 +312,40 @@ static int __init do_name(void)
        return 0;
 }
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+static int __init do_copy_mem(void)
+{
+       static void *file_current; /* current position in the memory */
+       if (file_mem == NULL) {
+               if (body_len < 4) { /* check especially against empty files */
+                       error("file is less than 4 bytes");
+                       return 1;
+               }
+               file_mem = kmalloc(body_len, GFP_ATOMIC);
+               if (!file_mem) {
+                       error("failed to allocate enough memory");
+                       return 1;
+               }
+               file_current = file_mem;
+       }
+       if (count >= body_len) {
+               memcpy(file_current, victim, body_len);
+               eat(body_len);
+               file_looked_for = NULL; /* don't find files with same name */
+               state = SkipIt;
+               return 0;
+       } else {
+               memcpy(file_current, victim, count);
+               file_current += count;
+               body_len -= count;
+               eat(count);
+               return 1;
+       }
+}
+#else
+#define do_copy_mem NULL
+#endif
+
 static int __init do_copy(void)
 {
        if (count >= body_len) {
@@ -333,6 +380,7 @@ static __initdata int (*actions[])(void) = {
        [SkipIt]        = do_skip,
        [GotName]       = do_name,
        [CopyFile]      = do_copy,
+       [CopyFileMem]   = do_copy_mem,
        [GotSymlink]    = do_symlink,
        [Reset]         = do_reset,
 };
@@ -578,3 +626,31 @@ static int __init populate_rootfs(void)
        return 0;
 }
 rootfs_initcall(populate_rootfs);
+
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+struct acpi_table_header *acpi_find_dsdt_initrd(void)
+{
+       char *err, *ramfs_dsdt_name = "DSDT.aml";
+
+       printk(KERN_INFO "ACPI: Checking initramfs for custom DSDT\n");
+       file_mem = NULL;
+       file_looked_for = ramfs_dsdt_name;
+       err = unpack_to_rootfs((char *)initrd_start,
+                       initrd_end - initrd_start, 1);
+       file_looked_for = NULL;
+
+       if (err) {
+               /*
+                * Even if reading the DSDT file was successful,
+                * we give up if the initramfs cannot be entirely read.
+                */
+               kfree(file_mem);
+               printk(KERN_ERR "ACPI: Aborded because %s.\n", err);
+               return NULL;
+       }
+       if (file_mem)
+               printk(KERN_INFO "ACPI: Found DSDT in %s.\n", ramfs_dsdt_name);
+
+       return file_mem;
+}
+#endif