1 #define __KERNEL_SYSCALLS__
2 #include <linux/init.h>
4 #include <linux/slab.h>
5 #include <linux/types.h>
6 #include <linux/fcntl.h>
7 #include <linux/unistd.h>
8 #include <linux/delay.h>
9 #include <linux/string.h>
10 #include <linux/vmalloc.h>
12 #ifdef CONFIG_ACPI_INITRD
13 unsigned char *dsdt_start;
16 static __initdata char *message;
18 static void __init error(char *x)
24 static void __init *malloc(int size)
26 return kmalloc(size, GFP_KERNEL);
29 static void __init free(void *where)
34 asmlinkage long sys_mkdir(char *name, int mode);
35 asmlinkage long sys_mknod(char *name, int mode, unsigned dev);
36 asmlinkage long sys_symlink(char *old, char *new);
37 asmlinkage long sys_link(char *old, char *new);
38 asmlinkage long sys_write(int fd, const char *buf, size_t size);
39 asmlinkage long sys_chown(char *name, uid_t uid, gid_t gid);
40 asmlinkage long sys_lchown(char *name, uid_t uid, gid_t gid);
41 asmlinkage long sys_fchown(int fd, uid_t uid, gid_t gid);
42 asmlinkage long sys_chmod(char *name, mode_t mode);
43 asmlinkage long sys_fchmod(int fd, mode_t mode);
48 int ino, minor, major;
53 static inline int hash(int major, int minor, int ino)
55 unsigned long tmp = ino + minor + (major << 3);
60 static char __init *find_link(int major, int minor, int ino, char *name)
63 for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) {
66 if ((*p)->minor != minor)
68 if ((*p)->major != major)
72 q = (struct hash *)malloc(sizeof(struct hash));
74 panic("can't allocate link hash entry");
84 static void __init free_hash(void)
87 for (p = head; p < head + 32; p++) {
96 /* cpio header parsing */
98 static __initdata unsigned long ino, major, minor, nlink;
99 static __initdata mode_t mode;
100 static __initdata unsigned long body_len, name_len;
101 static __initdata uid_t uid;
102 static __initdata gid_t gid;
103 static __initdata unsigned rdev;
105 static void __init parse_header(char *s)
107 unsigned long parsed[12];
112 for (i = 0, s += 6; i < 12; i++, s += 8) {
114 parsed[i] = simple_strtoul(buf, NULL, 16);
121 body_len = parsed[6];
124 rdev = new_encode_dev(MKDEV(parsed[9], parsed[10]));
125 name_len = parsed[11];
130 static __initdata enum state {
141 static __initdata char *victim;
142 static __initdata unsigned count;
143 static __initdata loff_t this_header, next_header;
145 static __initdata int dry_run;
147 static inline void eat(unsigned n)
154 #define N_ALIGN(len) ((((len) + 1) & ~3) + 2)
156 static __initdata char *collected;
157 static __initdata int remains;
158 static __initdata char *collect;
160 static void __init read_into(char *buf, unsigned size, enum state next)
167 collect = collected = buf;
174 static __initdata char *header_buf, *symlink_buf, *name_buf;
176 static int __init do_start(void)
178 read_into(header_buf, 110, GotHeader);
182 static int __init do_collect(void)
184 unsigned n = remains;
187 memcpy(collect, victim, n);
196 static int __init do_header(void)
198 if (memcmp(collected, "070701", 6)) {
199 error("no cpio magic");
202 parse_header(collected);
203 next_header = this_header + N_ALIGN(name_len) + body_len;
204 next_header = (next_header + 3) & ~3;
206 read_into(name_buf, N_ALIGN(name_len), GotName);
210 if (name_len <= 0 || name_len > PATH_MAX)
213 if (body_len > PATH_MAX)
215 collect = collected = symlink_buf;
216 remains = N_ALIGN(name_len) + body_len;
217 next_state = GotSymlink;
221 if (S_ISREG(mode) || !body_len)
222 read_into(name_buf, N_ALIGN(name_len), GotName);
226 static int __init do_skip(void)
228 if (this_header + count <= next_header) {
232 eat(next_header - this_header);
238 static int __init do_reset(void)
240 while(count && *victim == '\0')
242 if (count && (this_header & 3))
243 error("broken padding");
247 static int __init maybe_link(void)
250 char *old = find_link(major, minor, ino, collected);
252 return (sys_link(old, collected) < 0) ? -1 : 1;
257 static __initdata int wfd;
259 static int __init do_name(void)
263 if (strcmp(collected, "TRAILER!!!") == 0) {
271 if (maybe_link() >= 0) {
272 wfd = sys_open(collected, O_WRONLY|O_CREAT, mode);
274 sys_fchown(wfd, uid, gid);
275 sys_fchmod(wfd, mode);
279 } else if (S_ISDIR(mode)) {
280 sys_mkdir(collected, mode);
281 sys_chown(collected, uid, gid);
282 sys_chmod(collected, mode);
283 } else if (S_ISBLK(mode) || S_ISCHR(mode) ||
284 S_ISFIFO(mode) || S_ISSOCK(mode)) {
285 if (maybe_link() == 0) {
286 sys_mknod(collected, mode, rdev);
287 sys_chown(collected, uid, gid);
288 sys_chmod(collected, mode);
294 static int __init do_copy(void)
296 if (count >= body_len) {
297 sys_write(wfd, victim, body_len);
303 sys_write(wfd, victim, count);
310 static int __init do_symlink(void)
312 collected[N_ALIGN(name_len) + body_len] = '\0';
313 sys_symlink(collected + N_ALIGN(name_len), collected);
314 sys_lchown(collected, uid, gid);
320 static __initdata int (*actions[])(void) = {
322 [Collect] = do_collect,
323 [GotHeader] = do_header,
326 [CopyFile] = do_copy,
327 [GotSymlink] = do_symlink,
331 static int __init write_buffer(char *buf, unsigned len)
336 while (!actions[state]())
341 static void __init flush_buffer(char *buf, unsigned len)
346 while ((written = write_buffer(buf, len)) < len && !message) {
347 char c = buf[written];
353 error("junk in compressed archive");
361 #define OF(args) args
364 #define memzero(s, n) memset ((s), 0, (n))
367 typedef unsigned char uch;
368 typedef unsigned short ush;
369 typedef unsigned long ulg;
371 #define WSIZE 0x8000 /* window size--must be a power of two, and */
372 /* at least 32K for zip's deflate method */
377 static unsigned insize; /* valid bytes in inbuf */
378 static unsigned inptr; /* index of next byte to be processed in inbuf */
379 static unsigned outcnt; /* bytes in output buffer */
380 static long bytes_out;
382 #define get_byte() (inptr < insize ? inbuf[inptr++] : -1)
384 /* Diagnostic functions (stubbed out) */
385 #define Assert(cond,msg)
392 #define STATIC static
394 static void flush_window(void);
395 static void error(char *m);
396 static void gzip_mark(void **);
397 static void gzip_release(void **);
399 #include "../lib/inflate.c"
401 static void __init gzip_mark(void **ptr)
405 static void __init gzip_release(void **ptr)
409 /* ===========================================================================
410 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
411 * (Used for the decompressed data only.)
413 static void __init flush_window(void)
415 ulg c = crc; /* temporary variable */
419 flush_buffer(window, outcnt);
421 for (n = 0; n < outcnt; n++) {
423 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
426 bytes_out += (ulg)outcnt;
430 char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
433 dry_run = check_only;
434 header_buf = malloc(110);
435 symlink_buf = malloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1);
436 name_buf = malloc(N_ALIGN(PATH_MAX));
437 window = malloc(WSIZE);
438 if (!window || !header_buf || !symlink_buf || !name_buf)
439 panic("can't allocate buffers");
443 while (!message && len) {
444 loff_t saved_offset = this_header;
445 if (*buf == '0' && !(this_header & 3)) {
447 written = write_buffer(buf, len);
462 outcnt = 0; /* bytes in output buffer */
464 crc = (ulg)0xffffffffL; /* shift register contents */
467 message = "ungzip failed";
469 error("junk in gzipped archive");
470 this_header = saved_offset + inptr;
481 extern char __initramfs_start, __initramfs_end;
482 #ifdef CONFIG_BLK_DEV_INITRD
483 #include <linux/initrd.h>
486 void __init populate_rootfs(void)
488 char *err = unpack_to_rootfs(&__initramfs_start,
489 &__initramfs_end - &__initramfs_start, 0);
492 #ifdef CONFIG_BLK_DEV_INITRD
497 printk(KERN_INFO "checking if image is initramfs...");
498 err = unpack_to_rootfs((char *)initrd_start,
499 initrd_end - initrd_start, 1);
502 unpack_to_rootfs((char *)initrd_start,
503 initrd_end - initrd_start, 0);
504 free_initrd_mem(initrd_start, initrd_end);
507 printk("it isn't (%s); looks like an initrd\n", err);
509 #ifdef CONFIG_ACPI_INITRD
510 unsigned char start_signature[] = "INITRDDSDT123DSDT123";
511 unsigned char end_signature[] = "INITRDDSDT321DSDT321";
513 unsigned char *dsdt_start_tmp = NULL;
514 unsigned char *initrd_end_tmp = NULL;
517 printk(KERN_INFO "Looking for DSDT in initrd ...");
518 //* don't scan above end, do not modify initrd borders *//
519 initrd_end_tmp=(unsigned char*)initrd_end-sizeof(end_signature);
521 // searching for start signature in initrd
522 for (data=(unsigned char*)initrd_start;
523 data < (unsigned char*)initrd_end_tmp ; ++data) {
525 if (!memcmp(data, start_signature,
526 sizeof(start_signature)-1)) {
527 printk(KERN_INFO " found (at offset %u in initrd)!\n",
528 data+sizeof(start_signature)-
529 (unsigned char*)initrd_start);
530 dsdt_start_tmp = data+sizeof(start_signature);
534 // check if head of dsdt is valid
535 if (dsdt_start_tmp != NULL && !memcmp(dsdt_start_tmp, "DSDT", 4)) {
536 // searching for end signature in initrd
537 for (data += sizeof(end_signature);
538 data <= (unsigned char*)initrd_end; data++){
539 if (!memcmp(data, end_signature,
540 sizeof(end_signature)-1)){
544 printk (KERN_INFO "size of dsdt: %u!\n", data-dsdt_start_tmp);
545 // DSDT could be about 10-200kb, maybe more?
546 // could kmalloc be used ?
547 // am I allowed to use vmalloc ?
548 dsdt_start = vmalloc(data-dsdt_start_tmp+1);
549 memcpy(dsdt_start, dsdt_start_tmp, data-dsdt_start_tmp);
550 printk(KERN_INFO "%d bytes allocated and copied for DSDT", data-dsdt_start_tmp);
553 printk(KERN_INFO "No customized DSDT found in initrd!\n");
557 fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 700);
559 sys_write(fd, (char *)initrd_start,
560 initrd_end - initrd_start);
562 free_initrd_mem(initrd_start, initrd_end);