diff options
-rw-r--r-- | Documentation/acpi/dsdt-override.txt | 15 | ||||
-rwxr-xr-x | Documentation/acpi/initramfs-add-dsdt.sh | 43 | ||||
-rw-r--r-- | Documentation/kernel-parameters.txt | 3 | ||||
-rw-r--r-- | drivers/acpi/Kconfig | 17 | ||||
-rw-r--r-- | drivers/acpi/osl.c | 97 | ||||
-rw-r--r-- | include/linux/kernel.h | 1 | ||||
-rw-r--r-- | init/initramfs.c | 8 | ||||
-rw-r--r-- | init/main.c | 7 | ||||
-rw-r--r-- | kernel/panic.c | 5 |
9 files changed, 187 insertions, 9 deletions
diff --git a/Documentation/acpi/dsdt-override.txt b/Documentation/acpi/dsdt-override.txt new file mode 100644 index 000000000000..5008f256a2db --- /dev/null +++ b/Documentation/acpi/dsdt-override.txt | |||
@@ -0,0 +1,15 @@ | |||
1 | Linux supports two methods of overriding the BIOS DSDT: | ||
2 | |||
3 | CONFIG_ACPI_CUSTOM_DSDT builds the image into the kernel. | ||
4 | |||
5 | CONFIG_ACPI_CUSTOM_DSDT_INITRD adds the image to the initrd. | ||
6 | |||
7 | When to use these methods is described in detail on the | ||
8 | Linux/ACPI home page: | ||
9 | http://www.lesswatts.org/projects/acpi/overridingDSDT.php | ||
10 | |||
11 | Note that if both options are used, the DSDT supplied | ||
12 | by the INITRD method takes precedence. | ||
13 | |||
14 | Documentation/initramfs-add-dsdt.sh is provided for convenience | ||
15 | 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 100755 index 000000000000..17ef6e838e14 --- /dev/null +++ b/Documentation/acpi/initramfs-add-dsdt.sh | |||
@@ -0,0 +1,43 @@ | |||
1 | #!/bin/bash | ||
2 | # Adds a DSDT file to the initrd (if it's an initramfs) | ||
3 | # first argument is the name of archive | ||
4 | # second argument is the name of the file to add | ||
5 | # The file will be copied as /DSDT.aml | ||
6 | |||
7 | # 20060126: fix "Premature end of file" with some old cpio (Roland Robic) | ||
8 | # 20060205: this time it should really work | ||
9 | |||
10 | # check the arguments | ||
11 | if [ $# -ne 2 ]; then | ||
12 | program_name=$(basename $0) | ||
13 | echo "\ | ||
14 | $program_name: too few arguments | ||
15 | Usage: $program_name initrd-name.img DSDT-to-add.aml | ||
16 | Adds a DSDT file to an initrd (in initramfs format) | ||
17 | |||
18 | initrd-name.img: filename of the initrd in initramfs format | ||
19 | DSDT-to-add.aml: filename of the DSDT file to add | ||
20 | " 1>&2 | ||
21 | exit 1 | ||
22 | fi | ||
23 | |||
24 | # we should check it's an initramfs | ||
25 | |||
26 | tempcpio=$(mktemp -d) | ||
27 | # cleanup on exit, hangup, interrupt, quit, termination | ||
28 | trap 'rm -rf $tempcpio' 0 1 2 3 15 | ||
29 | |||
30 | # extract the archive | ||
31 | gunzip -c "$1" > "$tempcpio"/initramfs.cpio || exit 1 | ||
32 | |||
33 | # copy the DSDT file at the root of the directory so that we can call it "/DSDT.aml" | ||
34 | cp -f "$2" "$tempcpio"/DSDT.aml | ||
35 | |||
36 | # add the file | ||
37 | cd "$tempcpio" | ||
38 | (echo DSDT.aml | cpio --quiet -H newc -o -A -O "$tempcpio"/initramfs.cpio) || exit 1 | ||
39 | cd "$OLDPWD" | ||
40 | |||
41 | # re-compress the archive | ||
42 | gzip -c "$tempcpio"/initramfs.cpio > "$1" | ||
43 | |||
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 8ea41b6e6a85..0dcbd266b442 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -177,6 +177,9 @@ and is between 256 and 4096 characters. It is defined in the file | |||
177 | 177 | ||
178 | acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT | 178 | acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT |
179 | 179 | ||
180 | acpi_no_initrd_override [KNL,ACPI] | ||
181 | Disable loading custom ACPI tables from the initramfs | ||
182 | |||
180 | acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS | 183 | acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS |
181 | Format: To spoof as Windows 98: ="Microsoft Windows" | 184 | Format: To spoof as Windows 98: ="Microsoft Windows" |
182 | 185 | ||
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index d141bdb3a7d4..7ef172c2a1d6 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
@@ -276,8 +276,10 @@ config ACPI_CUSTOM_DSDT | |||
276 | depends on !STANDALONE | 276 | depends on !STANDALONE |
277 | default n | 277 | default n |
278 | help | 278 | help |
279 | This option is to load a custom ACPI DSDT | 279 | This option supports a custom DSDT by linking it into the kernel. |
280 | If you don't know what that is, say N. | 280 | See Documentation/acpi/dsdt-override.txt |
281 | |||
282 | If unsure, say N. | ||
281 | 283 | ||
282 | config ACPI_CUSTOM_DSDT_FILE | 284 | config ACPI_CUSTOM_DSDT_FILE |
283 | string "Custom DSDT Table file to include" | 285 | string "Custom DSDT Table file to include" |
@@ -287,6 +289,17 @@ config ACPI_CUSTOM_DSDT_FILE | |||
287 | Enter the full path name to the file which includes the AmlCode | 289 | Enter the full path name to the file which includes the AmlCode |
288 | declaration. | 290 | declaration. |
289 | 291 | ||
292 | config ACPI_CUSTOM_DSDT_INITRD | ||
293 | bool "Read Custom DSDT from initramfs" | ||
294 | depends on BLK_DEV_INITRD | ||
295 | default n | ||
296 | help | ||
297 | This option supports a custom DSDT by optionally loading it from initrd. | ||
298 | See Documentation/acpi/dsdt-override.txt | ||
299 | |||
300 | If you are not using this feature now, but may use it later, | ||
301 | it is safe to say Y here. | ||
302 | |||
290 | config ACPI_BLACKLIST_YEAR | 303 | config ACPI_BLACKLIST_YEAR |
291 | int "Disable ACPI for systems before Jan 1st this year" if X86_32 | 304 | int "Disable ACPI for systems before Jan 1st this year" if X86_32 |
292 | default 0 | 305 | default 0 |
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c2c585366fa6..27ccd68b8f46 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -91,6 +91,10 @@ static DEFINE_SPINLOCK(acpi_res_lock); | |||
91 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ | 91 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ |
92 | static char osi_additional_string[OSI_STRING_LENGTH_MAX]; | 92 | static char osi_additional_string[OSI_STRING_LENGTH_MAX]; |
93 | 93 | ||
94 | #ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
95 | static int acpi_no_initrd_override; | ||
96 | #endif | ||
97 | |||
94 | /* | 98 | /* |
95 | * "Ode to _OSI(Linux)" | 99 | * "Ode to _OSI(Linux)" |
96 | * | 100 | * |
@@ -329,6 +333,67 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val, | |||
329 | return AE_OK; | 333 | return AE_OK; |
330 | } | 334 | } |
331 | 335 | ||
336 | #ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
337 | struct acpi_table_header *acpi_find_dsdt_initrd(void) | ||
338 | { | ||
339 | struct file *firmware_file; | ||
340 | mm_segment_t oldfs; | ||
341 | unsigned long len, len2; | ||
342 | struct acpi_table_header *dsdt_buffer, *ret = NULL; | ||
343 | struct kstat stat; | ||
344 | char *ramfs_dsdt_name = "/DSDT.aml"; | ||
345 | |||
346 | printk(KERN_INFO PREFIX "Checking initramfs for custom DSDT"); | ||
347 | |||
348 | /* | ||
349 | * Never do this at home, only the user-space is allowed to open a file. | ||
350 | * The clean way would be to use the firmware loader. | ||
351 | * But this code must be run before there is any userspace available. | ||
352 | * A static/init firmware infrastructure doesn't exist yet... | ||
353 | */ | ||
354 | if (vfs_stat(ramfs_dsdt_name, &stat) < 0) | ||
355 | return ret; | ||
356 | |||
357 | len = stat.size; | ||
358 | /* check especially against empty files */ | ||
359 | if (len <= 4) { | ||
360 | printk(KERN_ERR PREFIX "Failed: DSDT only %lu bytes.\n", len); | ||
361 | return ret; | ||
362 | } | ||
363 | |||
364 | firmware_file = filp_open(ramfs_dsdt_name, O_RDONLY, 0); | ||
365 | if (IS_ERR(firmware_file)) { | ||
366 | printk(KERN_ERR PREFIX "Failed to open %s.\n", ramfs_dsdt_name); | ||
367 | return ret; | ||
368 | } | ||
369 | |||
370 | dsdt_buffer = kmalloc(len, GFP_ATOMIC); | ||
371 | if (!dsdt_buffer) { | ||
372 | printk(KERN_ERR PREFIX "Failed to allocate %lu bytes.\n", len); | ||
373 | goto err; | ||
374 | } | ||
375 | |||
376 | oldfs = get_fs(); | ||
377 | set_fs(KERNEL_DS); | ||
378 | len2 = vfs_read(firmware_file, (char __user *)dsdt_buffer, len, | ||
379 | &firmware_file->f_pos); | ||
380 | set_fs(oldfs); | ||
381 | if (len2 < len) { | ||
382 | printk(KERN_ERR PREFIX "Failed to read %lu bytes from %s.\n", | ||
383 | len, ramfs_dsdt_name); | ||
384 | ACPI_FREE(dsdt_buffer); | ||
385 | goto err; | ||
386 | } | ||
387 | |||
388 | printk(KERN_INFO PREFIX "Found %lu byte DSDT in %s.\n", | ||
389 | len, ramfs_dsdt_name); | ||
390 | ret = dsdt_buffer; | ||
391 | err: | ||
392 | filp_close(firmware_file, NULL); | ||
393 | return ret; | ||
394 | } | ||
395 | #endif | ||
396 | |||
332 | acpi_status | 397 | acpi_status |
333 | acpi_os_table_override(struct acpi_table_header * existing_table, | 398 | acpi_os_table_override(struct acpi_table_header * existing_table, |
334 | struct acpi_table_header ** new_table) | 399 | struct acpi_table_header ** new_table) |
@@ -336,17 +401,41 @@ acpi_os_table_override(struct acpi_table_header * existing_table, | |||
336 | if (!existing_table || !new_table) | 401 | if (!existing_table || !new_table) |
337 | return AE_BAD_PARAMETER; | 402 | return AE_BAD_PARAMETER; |
338 | 403 | ||
404 | *new_table = NULL; | ||
405 | |||
339 | #ifdef CONFIG_ACPI_CUSTOM_DSDT | 406 | #ifdef CONFIG_ACPI_CUSTOM_DSDT |
340 | if (strncmp(existing_table->signature, "DSDT", 4) == 0) | 407 | if (strncmp(existing_table->signature, "DSDT", 4) == 0) |
341 | *new_table = (struct acpi_table_header *)AmlCode; | 408 | *new_table = (struct acpi_table_header *)AmlCode; |
342 | else | ||
343 | *new_table = NULL; | ||
344 | #else | ||
345 | *new_table = NULL; | ||
346 | #endif | 409 | #endif |
410 | #ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
411 | if ((strncmp(existing_table->signature, "DSDT", 4) == 0) && | ||
412 | !acpi_no_initrd_override) { | ||
413 | struct acpi_table_header *initrd_table; | ||
414 | |||
415 | initrd_table = acpi_find_dsdt_initrd(); | ||
416 | if (initrd_table) | ||
417 | *new_table = initrd_table; | ||
418 | } | ||
419 | #endif | ||
420 | if (*new_table != NULL) { | ||
421 | printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], " | ||
422 | "this is unsafe: tainting kernel\n", | ||
423 | existing_table->signature, | ||
424 | existing_table->oem_table_id); | ||
425 | add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); | ||
426 | } | ||
347 | return AE_OK; | 427 | return AE_OK; |
348 | } | 428 | } |
349 | 429 | ||
430 | #ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
431 | int __init acpi_no_initrd_override_setup(char *s) | ||
432 | { | ||
433 | acpi_no_initrd_override = 1; | ||
434 | return 1; | ||
435 | } | ||
436 | __setup("acpi_no_initrd_override", acpi_no_initrd_override_setup); | ||
437 | #endif | ||
438 | |||
350 | static irqreturn_t acpi_irq(int irq, void *dev_id) | 439 | static irqreturn_t acpi_irq(int irq, void *dev_id) |
351 | { | 440 | { |
352 | u32 handled; | 441 | u32 handled; |
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 18222f267bc4..9e01f376840a 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
@@ -243,6 +243,7 @@ extern enum system_states { | |||
243 | #define TAINT_BAD_PAGE (1<<5) | 243 | #define TAINT_BAD_PAGE (1<<5) |
244 | #define TAINT_USER (1<<6) | 244 | #define TAINT_USER (1<<6) |
245 | #define TAINT_DIE (1<<7) | 245 | #define TAINT_DIE (1<<7) |
246 | #define TAINT_OVERRIDDEN_ACPI_TABLE (1<<8) | ||
246 | 247 | ||
247 | extern void dump_stack(void) __cold; | 248 | extern void dump_stack(void) __cold; |
248 | 249 | ||
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 | ||
541 | static int __init populate_rootfs(void) | 541 | int __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 | */ | ||
580 | rootfs_initcall(populate_rootfs); | 585 | rootfs_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) { } | |||
102 | extern void tc_init(void); | 102 | extern void tc_init(void); |
103 | #endif | 103 | #endif |
104 | 104 | ||
105 | #ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
106 | extern int populate_rootfs(void); | ||
107 | #else | ||
108 | static inline void populate_rootfs(void) {} | ||
109 | #endif | ||
110 | |||
105 | enum system_states system_state; | 111 | enum system_states system_state; |
106 | EXPORT_SYMBOL(system_state); | 112 | EXPORT_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 */ |
diff --git a/kernel/panic.c b/kernel/panic.c index d9e90cfe3298..24af9f8bac99 100644 --- a/kernel/panic.c +++ b/kernel/panic.c | |||
@@ -161,7 +161,7 @@ const char *print_tainted(void) | |||
161 | { | 161 | { |
162 | static char buf[20]; | 162 | static char buf[20]; |
163 | if (tainted) { | 163 | if (tainted) { |
164 | snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c", | 164 | snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c", |
165 | tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G', | 165 | tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G', |
166 | tainted & TAINT_FORCED_MODULE ? 'F' : ' ', | 166 | tainted & TAINT_FORCED_MODULE ? 'F' : ' ', |
167 | tainted & TAINT_UNSAFE_SMP ? 'S' : ' ', | 167 | tainted & TAINT_UNSAFE_SMP ? 'S' : ' ', |
@@ -169,7 +169,8 @@ const char *print_tainted(void) | |||
169 | tainted & TAINT_MACHINE_CHECK ? 'M' : ' ', | 169 | tainted & TAINT_MACHINE_CHECK ? 'M' : ' ', |
170 | tainted & TAINT_BAD_PAGE ? 'B' : ' ', | 170 | tainted & TAINT_BAD_PAGE ? 'B' : ' ', |
171 | tainted & TAINT_USER ? 'U' : ' ', | 171 | tainted & TAINT_USER ? 'U' : ' ', |
172 | tainted & TAINT_DIE ? 'D' : ' '); | 172 | tainted & TAINT_DIE ? 'D' : ' ', |
173 | tainted & TAINT_OVERRIDDEN_ACPI_TABLE ? 'A' : ' '); | ||
173 | } | 174 | } |
174 | else | 175 | else |
175 | snprintf(buf, sizeof(buf), "Not tainted"); | 176 | snprintf(buf, sizeof(buf), "Not tainted"); |