[PATCH 1/1] DSDT in initramfs: directly access the initramfs

From: Eric Piel
Date: Sat Mar 15 2008 - 14:49:05 EST


The current method for reading the DSDT in the initramfs uses the filesystem. Not only this is bad because such functions should normally not used in the kernel, but in addition it brings the requirement that the filesystem infrastructure is already initialised before initialising ACPI. This is quite unlikely to ever happen. (cf http://marc.info/?t=120536629300001&r=1&w=2)

This patch changes the method of access to initramfs. It uses directly unpack_to_rootfs(). This is build over the "check_only" mode: the initramfs is just read... but if we find a file matching the one we are looking for we copy it to memory.

Signed-off-by: Eric Piel <eric.piel@xxxxxxxxxxxxxxxx>
---
drivers/acpi/osl.c | 62 +----------------------------------------
init/initramfs.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++----
init/main.c | 7 ----
3 files changed, 74 insertions(+), 74 deletions(-)

diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 065819b..8fa630f 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -93,6 +93,7 @@ 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

/*
@@ -324,67 +325,6 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
return AE_OK;
}

-#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
-static 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\n");
-
- /*
- * 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)
diff --git a/init/initramfs.c b/init/initramfs.c
index c0b1e05..224bf48 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -6,8 +6,15 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/syscalls.h>
+#include <acpi/acpi.h>

static __initdata char *message;
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+static __initdata char *file_looked_for;
+static __initdata void *file_mem;
+#else
+#define file_looked_for 0
+#endif
static void __init error(char *x)
{
if (!message)
@@ -123,6 +130,7 @@ static __initdata enum state {
SkipIt,
GotName,
CopyFile,
+ CopyFileMem,
GotSymlink,
Reset
} state, next_state;
@@ -267,6 +275,11 @@ static int __init do_name(void)
free_hash();
return 0;
}
+ if (file_looked_for) {
+ if (S_ISREG(mode) && (strcmp(collected, file_looked_for) == 0))
+ state = CopyFileMem;
+ return 0;
+ }
if (dry_run)
return 0;
clean_path(collected, mode);
@@ -299,6 +312,37 @@ 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 file */
+ 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);
+ } else {
+ memcpy(file_current, victim, count);
+ body_len -= count;
+ file_current += count;
+ eat(count);
+ }
+ return 1;
+}
+#else
+#define do_copy_mem NULL
+#endif
+
static int __init do_copy(void)
{
if (count >= body_len) {
@@ -333,6 +377,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,
};
@@ -538,7 +583,7 @@ skip:
initrd_end = 0;
}

-int __init populate_rootfs(void)
+static int __init populate_rootfs(void)
{
char *err = unpack_to_rootfs(__initramfs_start,
__initramfs_end - __initramfs_start, 0);
@@ -577,10 +622,32 @@ int __init populate_rootfs(void)
}
return 0;
}
-#ifndef CONFIG_ACPI_CUSTOM_DSDT_INITRD
-/*
- * if this option is enabled, populate_rootfs() is called _earlier_ in the
- * boot sequence. This insures that the ACPI initialisation can find the file.
- */
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
diff --git a/init/main.c b/init/main.c
index fbb0167..99ce949 100644
--- a/init/main.c
+++ b/init/main.c
@@ -102,12 +102,6 @@ static inline void mark_rodata_ro(void) { }
extern void tc_init(void);
#endif

-#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
-extern int populate_rootfs(void);
-#else
-static inline void populate_rootfs(void) {}
-#endif
-
enum system_states system_state;
EXPORT_SYMBOL(system_state);

@@ -650,7 +644,6 @@ asmlinkage void __init start_kernel(void)

check_bugs();

- populate_rootfs(); /* For DSDT override from initramfs */
acpi_early_init(); /* before LAPIC and SMP init */

/* Do the rest non-__init'ed, we're now alive */
--
1.5.4.3


--------------030904090409050707080003--
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/