aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Gaugusch <dsdt@gaugusch.at>2008-02-04 18:04:06 -0500
committerLen Brown <len.brown@intel.com>2008-02-06 22:07:41 -0500
commit71fc47a9adf8ee89e5c96a47222915c5485ac437 (patch)
treea2eaefbb703dde933a9726eae7e6399761d40136
parent488b5ec871191359b9b79262a3d48456dae7ea5f (diff)
ACPI: basic initramfs DSDT override support
The basics of DSDT from initramfs. In case this option is selected, populate_rootfs() is called a bit earlier to have the initramfs content available during ACPI initialization. This is a very similar path to the one available at http://gaugusch.at/kernel.shtml but with some update in the documentation, default set to No and the change of populate_rootfs() the "Jeff Mahony way" (which avoids reading the initramfs twice). Signed-off-by: Thomas Renninger <trenn@suse.de> Signed-off-by: Eric Piel <eric.piel@tremplin-utc.net> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--Documentation/acpi/dsdt-initrd.txt99
-rw-r--r--drivers/acpi/Kconfig17
-rw-r--r--drivers/acpi/osl.c73
-rw-r--r--init/initramfs.c8
-rw-r--r--init/main.c7
5 files changed, 199 insertions, 5 deletions
diff --git a/Documentation/acpi/dsdt-initrd.txt b/Documentation/acpi/dsdt-initrd.txt
new file mode 100644
index 000000000000..736043359dfb
--- /dev/null
+++ b/Documentation/acpi/dsdt-initrd.txt
@@ -0,0 +1,99 @@
1ACPI Custom DSDT read from initramfs
2
32003 by Markus Gaugusch < dsdt at gaugusch dot at >
4Special thanks go to Thomas Renninger from SuSE, who updated the patch for
52.6.0 and later modified it to read inside initramfs
62004 - 2008 maintained by Eric Piel < eric dot piel at tremplin-utc dot net >
7
8This option is intended for people who would like to hack their DSDT and don't
9want to recompile their kernel after every change. It can also be useful to
10distros which offers pre-compiled kernels and want to allow their users to use
11a modified DSDT. In the Kernel config, enable the initial RAM filesystem
12support (in General Setup) and enable ACPI_CUSTOM_DSDT_INITRD at the ACPI
13options (General Setup|ACPI Support|Read Custom DSDT from initramfs).
14
15A custom DSDT (Differentiated System Description Table) is useful when your
16computer uses ACPI but problems occur due to broken implementation. Typically,
17your computer works but there are some troubles with the hardware detection or
18the power management. You can check that troubles come from errors in the DSDT by
19activating the ACPI debug option and reading the logs. This table is provided
20by the BIOS, therefore it might be a good idea to check for BIOS update on your
21vendor website before going any further. Errors are often caused by vendors
22testing their hardware only with Windows or because there is code which is
23executed only on a specific OS with a specific version and Linux hasn't been
24considered during the development.
25
26Before you run away from customising your DSDT, you should note that already
27corrected tables are available for a fair amount of computers on this web-page:
28http://acpi.sf.net/dsdt . Be careful though, to work correctly a DSDT has to
29match closely the hardware, including the amount of RAM, the frequency of the
30processor and the PCI cards present! If you are part of the unluckies who
31cannot find their hardware in this database, you can modify your DSDT by
32yourself. This process is less painful than it sounds. Download the Intel ASL
33compiler/decompiler at http://www.intel.com/technology/IAPC/acpi/downloads.htm .
34As root, you then have to dump your DSDT and decompile it. By using the
35compiler messages as well as the kernel ACPI debug messages and the reference
36book (available at the Intel website and also at http://www.acpi.info), it is
37quite easy to obtain a fully working table.
38
39Once your new DSDT is ready you'll have to add it to an initramfs so that the
40kernel can read the table at the very beginning of the boot. As the file has to
41be accessed very early during the boot process the initramfs has to be an
42initramfs. The file is contained into the initramfs under the name /DSDT.aml .
43To obtain such an initramfs, you might have to modify your initramfs script or
44you can add it later to the initramfs with the script appended to this
45document. The command will look like:
46initramfs-add-dsdt initramfs.img my-dsdt.aml
47
48In case you don't use any initramfs, the possibilities you have are to either
49start using one (try mkinitrd or yaird), or use the "Include Custom DSDT"
50configure option to directly include your DSDT inside the kernel.
51
52The message "Looking for DSDT in initramfs..." will tell you if the DSDT was
53found or not. If you need to update your DSDT, generate a new initramfs and
54perform the steps above. Don't forget that with Lilo, you'll have to re-run it.
55
56
57====================== Here starts initramfs-add-dsdt ==========================
58#!/bin/bash
59# Adds a DSDT file to the initrd (if it's an initramfs)
60# first argument is the name of archive
61# second argument is the name of the file to add
62# The file will be copied as /DSDT.aml
63
64# 20060126: fix "Premature end of file" with some old cpio (Roland Robic)
65# 20060205: this time it should really work
66
67# check the arguments
68if [ $# -ne 2 ]; then
69 program_name=$(basename $0)
70 echo "\
71$program_name: too few arguments
72Usage: $program_name initrd-name.img DSDT-to-add.aml
73Adds a DSDT file to an initrd (in initramfs format)
74
75 initrd-name.img: filename of the initrd in initramfs format
76 DSDT-to-add.aml: filename of the DSDT file to add
77 " 1>&2
78 exit 1
79fi
80
81# we should check it's an initramfs
82
83tempcpio=$(mktemp -d)
84# cleanup on exit, hangup, interrupt, quit, termination
85trap 'rm -rf $tempcpio' 0 1 2 3 15
86
87# extract the archive
88gunzip -c "$1" > "$tempcpio"/initramfs.cpio || exit 1
89
90# copy the DSDT file at the root of the directory so that we can call it "/DSDT.aml"
91cp -f "$2" "$tempcpio"/DSDT.aml
92
93# add the file
94cd "$tempcpio"
95(echo DSDT.aml | cpio --quiet -H newc -o -A -O "$tempcpio"/initramfs.cpio) || exit 1
96cd "$OLDPWD"
97
98# re-compress the archive
99gzip -c "$tempcpio"/initramfs.cpio > "$1"
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index ccf6ea95f68c..0442ae153a24 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -274,6 +274,23 @@ config ACPI_CUSTOM_DSDT_FILE
274 Enter the full path name to the file which includes the AmlCode 274 Enter the full path name to the file which includes the AmlCode
275 declaration. 275 declaration.
276 276
277config ACPI_CUSTOM_DSDT_INITRD
278 bool "Read Custom DSDT from initramfs"
279 depends on BLK_DEV_INITRD
280 default n
281 help
282 The DSDT (Differentiated System Description Table) often needs to be
283 overridden because of broken BIOS implementations. If this feature is
284 activated you will be able to provide a customized DSDT by adding it
285 to your initramfs. If your mkinitrd tool does not support this feature
286 a script is provided in the documentation. For more details see
287 <file:Documentation/dsdt-initrd.txt> or <http://gaugusch.at/kernel.shtml>.
288 If there is no table found, it will fall-back to the custom DSDT
289 in-kernel (if activated) or to the DSDT from the BIOS.
290
291 Even if you do not need a new one at the moment, you may want to use a
292 better DSDT later. It is safe to say Y here.
293
277config ACPI_BLACKLIST_YEAR 294config ACPI_BLACKLIST_YEAR
278 int "Disable ACPI for systems before Jan 1st this year" if X86_32 295 int "Disable ACPI for systems before Jan 1st this year" if X86_32
279 default 0 296 default 0
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index e53fb516f9d4..131936e7ff17 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -312,6 +312,66 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
312 return AE_OK; 312 return AE_OK;
313} 313}
314 314
315#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
316struct acpi_table_header *acpi_find_dsdt_initrd(void)
317{
318 struct file *firmware_file;
319 mm_segment_t oldfs;
320 unsigned long len, len2;
321 struct acpi_table_header *dsdt_buffer, *ret = NULL;
322 struct kstat stat;
323 char *ramfs_dsdt_name = "/DSDT.aml";
324
325 printk(KERN_INFO PREFIX "Looking for DSDT in initramfs... ");
326
327 /*
328 * Never do this at home, only the user-space is allowed to open a file.
329 * The clean way would be to use the firmware loader. But this code must be run
330 * before there is any userspace available. So we need a static/init firmware
331 * infrastructure, which doesn't exist yet...
332 */
333 if (vfs_stat(ramfs_dsdt_name, &stat) < 0) {
334 printk("not found.\n");
335 return ret;
336 }
337
338 len = stat.size;
339 /* check especially against empty files */
340 if (len <= 4) {
341 printk("error, file is too small: only %lu bytes.\n", len);
342 return ret;
343 }
344
345 firmware_file = filp_open(ramfs_dsdt_name, O_RDONLY, 0);
346 if (IS_ERR(firmware_file)) {
347 printk("error, could not open file %s.\n", ramfs_dsdt_name);
348 return ret;
349 }
350
351 dsdt_buffer = ACPI_ALLOCATE(len);
352 if (!dsdt_buffer) {
353 printk("error when allocating %lu bytes of memory.\n", len);
354 goto err;
355 }
356
357 oldfs = get_fs();
358 set_fs(KERNEL_DS);
359 len2 = vfs_read(firmware_file, (char __user *)dsdt_buffer, len, &firmware_file->f_pos);
360 set_fs(oldfs);
361 if (len2 < len) {
362 printk("error trying to read %lu bytes from %s.\n", len, ramfs_dsdt_name);
363 ACPI_FREE(dsdt_buffer);
364 goto err;
365 }
366
367 printk("successfully read %lu bytes from %s.\n", len, ramfs_dsdt_name);
368 ret = dsdt_buffer;
369err:
370 filp_close(firmware_file, NULL);
371 return ret;
372}
373#endif
374
315acpi_status 375acpi_status
316acpi_os_table_override(struct acpi_table_header * existing_table, 376acpi_os_table_override(struct acpi_table_header * existing_table,
317 struct acpi_table_header ** new_table) 377 struct acpi_table_header ** new_table)
@@ -319,13 +379,18 @@ acpi_os_table_override(struct acpi_table_header * existing_table,
319 if (!existing_table || !new_table) 379 if (!existing_table || !new_table)
320 return AE_BAD_PARAMETER; 380 return AE_BAD_PARAMETER;
321 381
382 *new_table = NULL;
383
322#ifdef CONFIG_ACPI_CUSTOM_DSDT 384#ifdef CONFIG_ACPI_CUSTOM_DSDT
323 if (strncmp(existing_table->signature, "DSDT", 4) == 0) 385 if (strncmp(existing_table->signature, "DSDT", 4) == 0)
324 *new_table = (struct acpi_table_header *)AmlCode; 386 *new_table = (struct acpi_table_header *)AmlCode;
325 else 387#endif
326 *new_table = NULL; 388#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
327#else 389 if (strncmp(existing_table->signature, "DSDT", 4) == 0) {
328 *new_table = NULL; 390 struct acpi_table_header *initrd_table = acpi_find_dsdt_initrd();
391 if (initrd_table)
392 *new_table = initrd_table;
393 }
329#endif 394#endif
330 return AE_OK; 395 return AE_OK;
331} 396}
diff --git a/init/initramfs.c b/init/initramfs.c
index d53fee8d8604..c0b1e0533d80 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -538,7 +538,7 @@ skip:
538 initrd_end = 0; 538 initrd_end = 0;
539} 539}
540 540
541static int __init populate_rootfs(void) 541int __init populate_rootfs(void)
542{ 542{
543 char *err = unpack_to_rootfs(__initramfs_start, 543 char *err = unpack_to_rootfs(__initramfs_start,
544 __initramfs_end - __initramfs_start, 0); 544 __initramfs_end - __initramfs_start, 0);
@@ -577,4 +577,10 @@ static int __init populate_rootfs(void)
577 } 577 }
578 return 0; 578 return 0;
579} 579}
580#ifndef CONFIG_ACPI_CUSTOM_DSDT_INITRD
581/*
582 * if this option is enabled, populate_rootfs() is called _earlier_ in the
583 * boot sequence. This insures that the ACPI initialisation can find the file.
584 */
580rootfs_initcall(populate_rootfs); 585rootfs_initcall(populate_rootfs);
586#endif
diff --git a/init/main.c b/init/main.c
index c691f5f7fc27..2a78932f6c07 100644
--- a/init/main.c
+++ b/init/main.c
@@ -102,6 +102,12 @@ static inline void mark_rodata_ro(void) { }
102extern void tc_init(void); 102extern void tc_init(void);
103#endif 103#endif
104 104
105#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
106extern int populate_rootfs(void);
107#else
108static inline void populate_rootfs(void) {}
109#endif
110
105enum system_states system_state; 111enum system_states system_state;
106EXPORT_SYMBOL(system_state); 112EXPORT_SYMBOL(system_state);
107 113
@@ -648,6 +654,7 @@ asmlinkage void __init start_kernel(void)
648 654
649 check_bugs(); 655 check_bugs();
650 656
657 populate_rootfs(); /* For DSDT override from initramfs */
651 acpi_early_init(); /* before LAPIC and SMP init */ 658 acpi_early_init(); /* before LAPIC and SMP init */
652 659
653 /* Do the rest non-__init'ed, we're now alive */ 660 /* Do the rest non-__init'ed, we're now alive */