Magellan Linux

Contents of /trunk/kernel26-magellan/patches-2.6.29-r8/0157-2.6.29-acpi-dsdt-initrd-0.9c.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1114 - (show annotations) (download)
Sun Aug 22 17:59:15 2010 UTC (13 years, 8 months ago) by niro
File size: 9992 byte(s)
-added

1 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