Annotation of /trunk/kernel26-alx/patches-2.6.29-r1/0157-2.6.29-acpi-dsdt-initrd-0.9c.patch
Parent Directory | Revision Log
Revision 875 -
(hide annotations)
(download)
Tue Aug 4 20:59:11 2009 UTC (15 years, 1 month ago) by niro
File size: 9992 byte(s)
Tue Aug 4 20:59:11 2009 UTC (15 years, 1 month ago) by niro
File size: 9992 byte(s)
-2.6.29-alx-r1
1 | niro | 875 | ACPI: initramfs DSDT override support |
2 | |||
3 | Permits to load of DSDT (the main ACPI table) from initramfs. In case this | ||
4 | option is selected, the initramfs is parsed at ACPI initialization (very early | ||
5 | boot time) to look for a file called "DSDT.aml". This aims at allowing users to | ||
6 | override the DSDT without recompiling the kernel. | ||
7 | |||
8 | Version 0.9 uses a different approach for reading the initramfs which avoids | ||
9 | using the filesystem infrastructure. It leverages the initramfs unpack code to find | ||
10 | and unpack the DSDT directly into the memory. | ||
11 | |||
12 | v0.9a: Fix compilation on non-ACPI platforms by René Rebe <rene@exactcode.de> | ||
13 | v0.9b: Declare more functions __init by Jan Beulich <jbeulich@novell.com> | ||
14 | v0.9c: Allow root to be / instead of nothing, bug reported by Robert Hampovcan | ||
15 | |||
16 | Signed-off-by: Eric Piel <eric.piel@tremplin-utc.net> | ||
17 | --- | ||
18 | Documentation/acpi/dsdt-override.txt | 12 +++- | ||
19 | Documentation/acpi/initramfs-add-dsdt.sh | 43 ++++++++++++++ | ||
20 | Documentation/kernel-parameters.txt | 3 + | ||
21 | drivers/acpi/Kconfig | 11 ++++ | ||
22 | drivers/acpi/osl.c | 24 ++++++++ | ||
23 | init/initramfs.c | 89 ++++++++++++++++++++++++++++++ | ||
24 | 6 files changed, 180 insertions(+), 2 deletions(-) | ||
25 | create mode 100644 Documentation/acpi/initramfs-add-dsdt.sh | ||
26 | |||
27 | diff --git a/Documentation/acpi/dsdt-override.txt b/Documentation/acpi/dsdt-override.txt | ||
28 | index febbb1b..5008f25 100644 | ||
29 | --- a/Documentation/acpi/dsdt-override.txt | ||
30 | +++ b/Documentation/acpi/dsdt-override.txt | ||
31 | @@ -1,7 +1,15 @@ | ||
32 | -Linux supports a method of overriding the BIOS DSDT: | ||
33 | +Linux supports two methods of overriding the BIOS DSDT: | ||
34 | |||
35 | CONFIG_ACPI_CUSTOM_DSDT builds the image into the kernel. | ||
36 | |||
37 | -When to use this method is described in detail on the | ||
38 | +CONFIG_ACPI_CUSTOM_DSDT_INITRD adds the image to the initrd. | ||
39 | + | ||
40 | +When to use these methods is described in detail on the | ||
41 | Linux/ACPI home page: | ||
42 | http://www.lesswatts.org/projects/acpi/overridingDSDT.php | ||
43 | + | ||
44 | +Note that if both options are used, the DSDT supplied | ||
45 | +by the INITRD method takes precedence. | ||
46 | + | ||
47 | +Documentation/initramfs-add-dsdt.sh is provided for convenience | ||
48 | +for use with the CONFIG_ACPI_CUSTOM_DSDT_INITRD method. | ||
49 | diff --git a/Documentation/acpi/initramfs-add-dsdt.sh b/Documentation/acpi/initramfs-add-dsdt.sh | ||
50 | new file mode 100644 | ||
51 | index 0000000..17ef6e8 | ||
52 | --- /dev/null | ||
53 | +++ b/Documentation/acpi/initramfs-add-dsdt.sh | ||
54 | @@ -0,0 +1,43 @@ | ||
55 | +#!/bin/bash | ||
56 | +# Adds a DSDT file to the initrd (if it's an initramfs) | ||
57 | +# first argument is the name of archive | ||
58 | +# second argument is the name of the file to add | ||
59 | +# The file will be copied as /DSDT.aml | ||
60 | + | ||
61 | +# 20060126: fix "Premature end of file" with some old cpio (Roland Robic) | ||
62 | +# 20060205: this time it should really work | ||
63 | + | ||
64 | +# check the arguments | ||
65 | +if [ $# -ne 2 ]; then | ||
66 | + program_name=$(basename $0) | ||
67 | + echo "\ | ||
68 | +$program_name: too few arguments | ||
69 | +Usage: $program_name initrd-name.img DSDT-to-add.aml | ||
70 | +Adds a DSDT file to an initrd (in initramfs format) | ||
71 | + | ||
72 | + initrd-name.img: filename of the initrd in initramfs format | ||
73 | + DSDT-to-add.aml: filename of the DSDT file to add | ||
74 | + " 1>&2 | ||
75 | + exit 1 | ||
76 | +fi | ||
77 | + | ||
78 | +# we should check it's an initramfs | ||
79 | + | ||
80 | +tempcpio=$(mktemp -d) | ||
81 | +# cleanup on exit, hangup, interrupt, quit, termination | ||
82 | +trap 'rm -rf $tempcpio' 0 1 2 3 15 | ||
83 | + | ||
84 | +# extract the archive | ||
85 | +gunzip -c "$1" > "$tempcpio"/initramfs.cpio || exit 1 | ||
86 | + | ||
87 | +# copy the DSDT file at the root of the directory so that we can call it "/DSDT.aml" | ||
88 | +cp -f "$2" "$tempcpio"/DSDT.aml | ||
89 | + | ||
90 | +# add the file | ||
91 | +cd "$tempcpio" | ||
92 | +(echo DSDT.aml | cpio --quiet -H newc -o -A -O "$tempcpio"/initramfs.cpio) || exit 1 | ||
93 | +cd "$OLDPWD" | ||
94 | + | ||
95 | +# re-compress the archive | ||
96 | +gzip -c "$tempcpio"/initramfs.cpio > "$1" | ||
97 | + | ||
98 | diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt | ||
99 | index 343e0f0..76707c4 100644 | ||
100 | --- a/Documentation/kernel-parameters.txt | ||
101 | +++ b/Documentation/kernel-parameters.txt | ||
102 | @@ -180,6 +180,9 @@ and is between 256 and 4096 characters. It is defined in the file | ||
103 | |||
104 | acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT | ||
105 | |||
106 | + acpi_no_initrd_override [KNL,ACPI] | ||
107 | + Disable loading custom ACPI tables from the initramfs | ||
108 | + | ||
109 | acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS | ||
110 | Format: To spoof as Windows 98: ="Microsoft Windows" | ||
111 | |||
112 | diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig | ||
113 | index f4f6329..f070331 100644 | ||
114 | --- a/drivers/acpi/Kconfig | ||
115 | +++ b/drivers/acpi/Kconfig | ||
116 | @@ -297,6 +297,17 @@ config ACPI_CUSTOM_DSDT | ||
117 | bool | ||
118 | default ACPI_CUSTOM_DSDT_FILE != "" | ||
119 | |||
120 | +config ACPI_CUSTOM_DSDT_INITRD | ||
121 | + bool "Read Custom DSDT from initramfs" | ||
122 | + depends on BLK_DEV_INITRD | ||
123 | + default n | ||
124 | + help | ||
125 | + This option supports a custom DSDT by optionally loading it from initrd. | ||
126 | + See Documentation/acpi/dsdt-override.txt | ||
127 | + | ||
128 | + If you are not using this feature now, but may use it later, | ||
129 | + it is safe to say Y here. | ||
130 | + | ||
131 | config ACPI_BLACKLIST_YEAR | ||
132 | int "Disable ACPI for systems before Jan 1st this year" if X86_32 | ||
133 | default 0 | ||
134 | diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c | ||
135 | index 4be2521..2e0df9f 100644 | ||
136 | --- a/drivers/acpi/osl.c | ||
137 | +++ b/drivers/acpi/osl.c | ||
138 | @@ -96,6 +96,11 @@ static DEFINE_SPINLOCK(acpi_res_lock); | ||
139 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ | ||
140 | static char osi_additional_string[OSI_STRING_LENGTH_MAX]; | ||
141 | |||
142 | +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
143 | +static __initdata int acpi_no_initrd_override; | ||
144 | +extern struct acpi_table_header *acpi_find_dsdt_initrd(void); | ||
145 | +#endif | ||
146 | + | ||
147 | /* | ||
148 | * "Ode to _OSI(Linux)" | ||
149 | * | ||
150 | @@ -338,6 +343,16 @@ acpi_os_table_override(struct acpi_table_header * existing_table, | ||
151 | if (strncmp(existing_table->signature, "DSDT", 4) == 0) | ||
152 | *new_table = (struct acpi_table_header *)AmlCode; | ||
153 | #endif | ||
154 | +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
155 | + if ((strncmp(existing_table->signature, "DSDT", 4) == 0) && | ||
156 | + !acpi_no_initrd_override) { | ||
157 | + struct acpi_table_header *initrd_table; | ||
158 | + | ||
159 | + initrd_table = acpi_find_dsdt_initrd(); | ||
160 | + if (initrd_table) | ||
161 | + *new_table = initrd_table; | ||
162 | + } | ||
163 | +#endif | ||
164 | if (*new_table != NULL) { | ||
165 | printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], " | ||
166 | "this is unsafe: tainting kernel\n", | ||
167 | @@ -348,6 +363,15 @@ acpi_os_table_override(struct acpi_table_header * existing_table, | ||
168 | return AE_OK; | ||
169 | } | ||
170 | |||
171 | +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
172 | +static int __init acpi_no_initrd_override_setup(char *s) | ||
173 | +{ | ||
174 | + acpi_no_initrd_override = 1; | ||
175 | + return 1; | ||
176 | +} | ||
177 | +__setup("acpi_no_initrd_override", acpi_no_initrd_override_setup); | ||
178 | +#endif | ||
179 | + | ||
180 | static irqreturn_t acpi_irq(int irq, void *dev_id) | ||
181 | { | ||
182 | u32 handled; | ||
183 | diff --git a/init/initramfs.c b/init/initramfs.c | ||
184 | index 4f5ba75..d2aaa87 100644 | ||
185 | --- a/init/initramfs.c | ||
186 | +++ b/init/initramfs.c | ||
187 | @@ -7,6 +7,9 @@ | ||
188 | #include <linux/string.h> | ||
189 | #include <linux/syscalls.h> | ||
190 | #include <linux/utime.h> | ||
191 | +#ifdef ACPI_CONFIG | ||
192 | +#include <acpi/acpi.h> | ||
193 | +#endif | ||
194 | |||
195 | static __initdata char *message; | ||
196 | static void __init error(char *x) | ||
197 | @@ -124,6 +127,12 @@ static __initdata unsigned long body_len, name_len; | ||
198 | static __initdata uid_t uid; | ||
199 | static __initdata gid_t gid; | ||
200 | static __initdata unsigned rdev; | ||
201 | +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
202 | +static __initdata char *file_looked_for; | ||
203 | +static __initdata struct acpi_table_header *file_mem; | ||
204 | +#else | ||
205 | +const char *file_looked_for = NULL; | ||
206 | +#endif | ||
207 | |||
208 | static void __init parse_header(char *s) | ||
209 | { | ||
210 | @@ -158,6 +167,7 @@ static __initdata enum state { | ||
211 | SkipIt, | ||
212 | GotName, | ||
213 | CopyFile, | ||
214 | + CopyFileMem, | ||
215 | GotSymlink, | ||
216 | Reset | ||
217 | } state, next_state; | ||
218 | @@ -295,6 +305,54 @@ static void __init clean_path(char *path, mode_t mode) | ||
219 | |||
220 | static __initdata int wfd; | ||
221 | |||
222 | +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
223 | +static __init int is_file_looked_for(char *filename) | ||
224 | +{ | ||
225 | + char *tmp_collected = collected; | ||
226 | + if (file_looked_for == NULL) | ||
227 | + return 0; | ||
228 | + if (!S_ISREG(mode)) | ||
229 | + return 0; | ||
230 | + /* remove the leading / */ | ||
231 | + while (*tmp_collected == '/') | ||
232 | + tmp_collected++; | ||
233 | + return (strcmp(tmp_collected, file_looked_for) == 0); | ||
234 | +} | ||
235 | + | ||
236 | +static int __init do_copy_mem(void) | ||
237 | +{ | ||
238 | + static void *file_current; /* current position in the memory */ | ||
239 | + if (file_mem == NULL) { | ||
240 | + if (body_len < 4) { /* check especially against empty files */ | ||
241 | + error("file is less than 4 bytes"); | ||
242 | + return 1; | ||
243 | + } | ||
244 | + file_mem = kmalloc(body_len, GFP_ATOMIC); | ||
245 | + if (!file_mem) { | ||
246 | + error("failed to allocate enough memory"); | ||
247 | + return 1; | ||
248 | + } | ||
249 | + file_current = file_mem; | ||
250 | + } | ||
251 | + if (count >= body_len) { | ||
252 | + memcpy(file_current, victim, body_len); | ||
253 | + eat(body_len); | ||
254 | + file_looked_for = NULL; /* don't find files with same name */ | ||
255 | + state = SkipIt; | ||
256 | + return 0; | ||
257 | + } else { | ||
258 | + memcpy(file_current, victim, count); | ||
259 | + file_current += count; | ||
260 | + body_len -= count; | ||
261 | + eat(count); | ||
262 | + return 1; | ||
263 | + } | ||
264 | +} | ||
265 | +#else | ||
266 | +static inline int is_file_looked_for(char *filename) {return 0;} | ||
267 | +#define do_copy_mem NULL /* because it is used as a pointer */ | ||
268 | +#endif | ||
269 | + | ||
270 | static int __init do_name(void) | ||
271 | { | ||
272 | state = SkipIt; | ||
273 | @@ -303,6 +361,8 @@ static int __init do_name(void) | ||
274 | free_hash(); | ||
275 | return 0; | ||
276 | } | ||
277 | + if (is_file_looked_for(file_looked_for)) | ||
278 | + state = CopyFileMem; | ||
279 | if (dry_run) | ||
280 | return 0; | ||
281 | clean_path(collected, mode); | ||
282 | @@ -375,6 +435,7 @@ static __initdata int (*actions[])(void) = { | ||
283 | [SkipIt] = do_skip, | ||
284 | [GotName] = do_name, | ||
285 | [CopyFile] = do_copy, | ||
286 | + [CopyFileMem] = do_copy_mem, | ||
287 | [GotSymlink] = do_symlink, | ||
288 | [Reset] = do_reset, | ||
289 | }; | ||
290 | @@ -613,3 +674,31 @@ static int __init populate_rootfs(void) | ||
291 | return 0; | ||
292 | } | ||
293 | rootfs_initcall(populate_rootfs); | ||
294 | + | ||
295 | +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
296 | +struct __init acpi_table_header *acpi_find_dsdt_initrd(void) | ||
297 | +{ | ||
298 | + char *err, *ramfs_dsdt_name = "DSDT.aml"; | ||
299 | + | ||
300 | + printk(KERN_INFO "ACPI: Checking initramfs for custom DSDT\n"); | ||
301 | + file_mem = NULL; | ||
302 | + file_looked_for = ramfs_dsdt_name; | ||
303 | + err = unpack_to_rootfs((char *)initrd_start, | ||
304 | + initrd_end - initrd_start, 1); | ||
305 | + file_looked_for = NULL; | ||
306 | + | ||
307 | + if (err) { | ||
308 | + /* | ||
309 | + * Even if reading the DSDT file was successful, | ||
310 | + * we give up if the initramfs cannot be entirely read. | ||
311 | + */ | ||
312 | + kfree(file_mem); | ||
313 | + printk(KERN_ERR "ACPI: Aborded because %s.\n", err); | ||
314 | + return NULL; | ||
315 | + } | ||
316 | + if (file_mem) | ||
317 | + printk(KERN_INFO "ACPI: Found DSDT in %s.\n", ramfs_dsdt_name); | ||
318 | + | ||
319 | + return file_mem; | ||
320 | +} | ||
321 | +#endif |