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>
This commit is contained in:
parent
488b5ec871
commit
71fc47a9ad
5 changed files with 199 additions and 5 deletions
99
Documentation/acpi/dsdt-initrd.txt
Normal file
99
Documentation/acpi/dsdt-initrd.txt
Normal file
|
@ -0,0 +1,99 @@
|
|||
ACPI Custom DSDT read from initramfs
|
||||
|
||||
2003 by Markus Gaugusch < dsdt at gaugusch dot at >
|
||||
Special thanks go to Thomas Renninger from SuSE, who updated the patch for
|
||||
2.6.0 and later modified it to read inside initramfs
|
||||
2004 - 2008 maintained by Eric Piel < eric dot piel at tremplin-utc dot net >
|
||||
|
||||
This option is intended for people who would like to hack their DSDT and don't
|
||||
want to recompile their kernel after every change. It can also be useful to
|
||||
distros which offers pre-compiled kernels and want to allow their users to use
|
||||
a modified DSDT. In the Kernel config, enable the initial RAM filesystem
|
||||
support (in General Setup) and enable ACPI_CUSTOM_DSDT_INITRD at the ACPI
|
||||
options (General Setup|ACPI Support|Read Custom DSDT from initramfs).
|
||||
|
||||
A custom DSDT (Differentiated System Description Table) is useful when your
|
||||
computer uses ACPI but problems occur due to broken implementation. Typically,
|
||||
your computer works but there are some troubles with the hardware detection or
|
||||
the power management. You can check that troubles come from errors in the DSDT by
|
||||
activating the ACPI debug option and reading the logs. This table is provided
|
||||
by the BIOS, therefore it might be a good idea to check for BIOS update on your
|
||||
vendor website before going any further. Errors are often caused by vendors
|
||||
testing their hardware only with Windows or because there is code which is
|
||||
executed only on a specific OS with a specific version and Linux hasn't been
|
||||
considered during the development.
|
||||
|
||||
Before you run away from customising your DSDT, you should note that already
|
||||
corrected tables are available for a fair amount of computers on this web-page:
|
||||
http://acpi.sf.net/dsdt . Be careful though, to work correctly a DSDT has to
|
||||
match closely the hardware, including the amount of RAM, the frequency of the
|
||||
processor and the PCI cards present! If you are part of the unluckies who
|
||||
cannot find their hardware in this database, you can modify your DSDT by
|
||||
yourself. This process is less painful than it sounds. Download the Intel ASL
|
||||
compiler/decompiler at http://www.intel.com/technology/IAPC/acpi/downloads.htm .
|
||||
As root, you then have to dump your DSDT and decompile it. By using the
|
||||
compiler messages as well as the kernel ACPI debug messages and the reference
|
||||
book (available at the Intel website and also at http://www.acpi.info), it is
|
||||
quite easy to obtain a fully working table.
|
||||
|
||||
Once your new DSDT is ready you'll have to add it to an initramfs so that the
|
||||
kernel can read the table at the very beginning of the boot. As the file has to
|
||||
be accessed very early during the boot process the initramfs has to be an
|
||||
initramfs. The file is contained into the initramfs under the name /DSDT.aml .
|
||||
To obtain such an initramfs, you might have to modify your initramfs script or
|
||||
you can add it later to the initramfs with the script appended to this
|
||||
document. The command will look like:
|
||||
initramfs-add-dsdt initramfs.img my-dsdt.aml
|
||||
|
||||
In case you don't use any initramfs, the possibilities you have are to either
|
||||
start using one (try mkinitrd or yaird), or use the "Include Custom DSDT"
|
||||
configure option to directly include your DSDT inside the kernel.
|
||||
|
||||
The message "Looking for DSDT in initramfs..." will tell you if the DSDT was
|
||||
found or not. If you need to update your DSDT, generate a new initramfs and
|
||||
perform the steps above. Don't forget that with Lilo, you'll have to re-run it.
|
||||
|
||||
|
||||
====================== Here starts initramfs-add-dsdt ==========================
|
||||
#!/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"
|
|
@ -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 n
|
||||
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. If your mkinitrd tool does not support this feature
|
||||
a script is provided in the documentation. For more details see
|
||||
<file:Documentation/dsdt-initrd.txt> or <http://gaugusch.at/kernel.shtml>.
|
||||
If there is no table found, it will fall-back 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 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
|
||||
|
|
|
@ -312,6 +312,66 @@ 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 "Looking for DSDT in initramfs... ");
|
||||
|
||||
/*
|
||||
* 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...
|
||||
*/
|
||||
if (vfs_stat(ramfs_dsdt_name, &stat) < 0) {
|
||||
printk("not found.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
len = stat.size;
|
||||
/* check especially against empty files */
|
||||
if (len <= 4) {
|
||||
printk("error, file is too small: only %lu bytes.\n", len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
firmware_file = filp_open(ramfs_dsdt_name, O_RDONLY, 0);
|
||||
if (IS_ERR(firmware_file)) {
|
||||
printk("error, could not open file %s.\n", ramfs_dsdt_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dsdt_buffer = ACPI_ALLOCATE(len);
|
||||
if (!dsdt_buffer) {
|
||||
printk("error when allocating %lu bytes of memory.\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("error trying to read %lu bytes from %s.\n", len, ramfs_dsdt_name);
|
||||
ACPI_FREE(dsdt_buffer);
|
||||
goto err;
|
||||
}
|
||||
|
||||
printk("successfully read %lu bytes from %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)
|
||||
|
@ -319,13 +379,18 @@ 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) {
|
||||
struct acpi_table_header *initrd_table = acpi_find_dsdt_initrd();
|
||||
if (initrd_table)
|
||||
*new_table = initrd_table;
|
||||
}
|
||||
#endif
|
||||
return AE_OK;
|
||||
}
|
||||
|
|
|
@ -538,7 +538,7 @@ static void __init free_initrd(void)
|
|||
initrd_end = 0;
|
||||
}
|
||||
|
||||
static int __init populate_rootfs(void)
|
||||
int __init populate_rootfs(void)
|
||||
{
|
||||
char *err = unpack_to_rootfs(__initramfs_start,
|
||||
__initramfs_end - __initramfs_start, 0);
|
||||
|
@ -577,4 +577,10 @@ static 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);
|
||||
#endif
|
||||
|
|
|
@ -102,6 +102,12 @@ 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);
|
||||
|
||||
|
@ -648,6 +654,7 @@ 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 */
|
||||
|
|
Loading…
Reference in a new issue