]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/acpi/osl.c
Merge branches 'release' and 'dsdt-override' into release
[linux-2.6-omap-h63xx.git] / drivers / acpi / osl.c
index c2c585366fa6957ed2b51d9b9b0f3dbeafb5f9fe..27ccd68b8f462de790a7243219197e4631b8fcf9 100644 (file)
@@ -91,6 +91,10 @@ 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;
+#endif
+
 /*
  * "Ode to _OSI(Linux)"
  *
@@ -329,6 +333,67 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
        return AE_OK;
 }
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+struct acpi_table_header *acpi_find_dsdt_initrd(void)
+{
+       struct file *firmware_file;
+       mm_segment_t oldfs;
+       unsigned long len, len2;
+       struct acpi_table_header *dsdt_buffer, *ret = NULL;
+       struct kstat stat;
+       char *ramfs_dsdt_name = "/DSDT.aml";
+
+       printk(KERN_INFO PREFIX "Checking initramfs for custom DSDT");
+
+       /*
+        * 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.
+        * A static/init firmware infrastructure doesn't exist yet...
+        */
+       if (vfs_stat(ramfs_dsdt_name, &stat) < 0)
+               return ret;
+
+       len = stat.size;
+       /* check especially against empty files */
+       if (len <= 4) {
+               printk(KERN_ERR PREFIX "Failed: DSDT only %lu bytes.\n", len);
+               return ret;
+       }
+
+       firmware_file = filp_open(ramfs_dsdt_name, O_RDONLY, 0);
+       if (IS_ERR(firmware_file)) {
+               printk(KERN_ERR PREFIX "Failed to open %s.\n", ramfs_dsdt_name);
+               return ret;
+       }
+
+       dsdt_buffer = kmalloc(len, GFP_ATOMIC);
+       if (!dsdt_buffer) {
+               printk(KERN_ERR PREFIX "Failed to allocate %lu bytes.\n", len);
+               goto err;
+       }
+
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+       len2 = vfs_read(firmware_file, (char __user *)dsdt_buffer, len,
+               &firmware_file->f_pos);
+       set_fs(oldfs);
+       if (len2 < len) {
+               printk(KERN_ERR PREFIX "Failed to read %lu bytes from %s.\n",
+                       len, ramfs_dsdt_name);
+               ACPI_FREE(dsdt_buffer);
+               goto err;
+       }
+
+       printk(KERN_INFO PREFIX "Found %lu byte DSDT in %s.\n",
+                       len, ramfs_dsdt_name);
+       ret = dsdt_buffer;
+err:
+       filp_close(firmware_file, NULL);
+       return ret;
+}
+#endif
+
 acpi_status
 acpi_os_table_override(struct acpi_table_header * existing_table,
                       struct acpi_table_header ** new_table)
@@ -336,17 +401,41 @@ acpi_os_table_override(struct acpi_table_header * existing_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 ((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",
+                      existing_table->signature,
+                      existing_table->oem_table_id);
+               add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
+       }
        return AE_OK;
 }
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+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;