--- linux-2.6.21.5/kernel/ksysfs.c.orig 2007-06-30 16:42:36.000000000 -0500 +++ linux-2.6.21.5/kernel/ksysfs.c 2007-06-30 20:04:38.000000000 -0500 @@ -49,6 +49,165 @@ #endif #ifdef CONFIG_KEXEC + +#include + +extern unsigned long kexec_boot_params; + +char kexec_cmdline[COMMAND_LINE_SIZE] = ""; + +static void +replace_cmdline_tag(void) +{ + char *t; + struct tag *real; + struct tag *copy; + struct tag *rend; + int i; + +/* TODO: check the return params */ + t = kmalloc(KEXEC_BOOT_PARAMS_SIZE + COMMAND_LINE_SIZE, GFP_KERNEL); + memset((void *)t, 0, KEXEC_BOOT_PARAMS_SIZE + COMMAND_LINE_SIZE); + +/* TODO: validate that the boot params are ATAGS, in fact */ + + copy = (struct tag *)t; + real = (struct tag *)kexec_boot_params; + rend = (struct tag *)(kexec_boot_params + KEXEC_BOOT_PARAMS_SIZE); + while ((real->hdr.size) && (real < rend)) { + if (real->hdr.tag != ATAG_CMDLINE) { + memcpy((void *)copy, (void *)real, real->hdr.size * 4); + copy = tag_next(copy); + } + real = tag_next(real); + } + +/* TODO: validate that we have enough space in the buffer */ + + i = strlen(kexec_cmdline); + if (i) { + copy->hdr.tag = ATAG_CMDLINE; + copy->hdr.size = (sizeof(struct tag_header) + i + 1 + 4) >> 2; + strcpy(copy->u.cmdline.cmdline, kexec_cmdline); + copy = tag_next(copy); + } + + copy->hdr.tag = ATAG_NONE; /* Empty tag ends list */ + copy->hdr.size = 0; /* zero length */ + +/* TODO: validate that the temporary buffer isn't too full */ + + memcpy((void *)kexec_boot_params, (void *)t, KEXEC_BOOT_PARAMS_SIZE); + + kfree(t); /* Don't forget to free the big buffer we used */ +} + +static ssize_t kexec_cmdline_show(struct subsystem *subsys, char *page) +{ + return sprintf(page, "%s\n", kexec_cmdline); +} + +static ssize_t kexec_cmdline_store(struct subsystem *subsys, const char *page, + size_t count) +{ + if ((count + 1) > COMMAND_LINE_SIZE) + count = COMMAND_LINE_SIZE; + memcpy(kexec_cmdline, page, count); + kexec_cmdline[count] = '\0'; + if (count && (kexec_cmdline[count - 1] == '\n')) + kexec_cmdline[count - 1] = '\0'; + replace_cmdline_tag(); + return count; +} +KERNEL_ATTR_RW(kexec_cmdline); + +static ssize_t kexec_boot_params_show(struct subsystem *subsys, char *page) +{ + unsigned long *p; + char buf[PAGE_SIZE]; + int keep_doing; + + p = (unsigned long *)kexec_boot_params; + + /* if this doesn't look like atags, just print first few words */ + if (p[1] != ATAG_CORE) + return sprintf(page, "0x%lx 0x%lx 0x%lx 0x%lx\n", + p[0], p[1], p[2], p[3]); + + /* carefully walk the atag list, and print out the structure */ + keep_doing = 1; + do { + switch (p[1]) { + case ATAG_CORE: + /* watch out, core tag is permitted to be empty */ + if (p[0] == 5) + sprintf(buf, + "CORE flg=%ld pgsz=%ld rdev=0x%lx\n", + p[2], p[3], p[4]); + else + sprintf(buf,"CORE\n"); + break; + case ATAG_MEM: + sprintf(buf,"MEM %ldM@0x%lx\n", p[2] / (1024 * 1024), + p[3]); + break; + case ATAG_VIDEOTEXT: + sprintf(buf,"VIDEOTEXT sz=%ld\n", p[0]); + break; + case ATAG_RAMDISK: + sprintf(buf,"RAMDISK prmpt=%ld %ldK@0x%lx\n", + p[2], p[3], p[4]); + break; + case ATAG_INITRD2: + sprintf(buf,"INITRD2 %ldK@0x%lx\n", p[3] / 1024, p[2]); + break; + case ATAG_SERIAL: + sprintf(buf,"SERIAL high=0x%08lx low=0x%08lx\n", + p[3], p[2]); + break; + case ATAG_REVISION: + sprintf(buf,"REVISION rev=%ld\n", p[2]); + break; + case ATAG_VIDEOLFB: + sprintf(buf,"VIDEOLFB sz=%ld\n", p[0]); + break; + case ATAG_CMDLINE: + sprintf(buf,"CMD \"%s\"\n", (char *)&p[2]); + break; + case ATAG_NONE: + sprintf(buf,"NONE\n"); + keep_doing = 0; + break; + default: + sprintf(buf,"-unknown- sz=%ld\n", p[0]); + break; + } + + /* carefully add to page */ + if ((strlen(buf) + strlen(page)) < PAGE_SIZE) { + strcat(page, buf); + } else { + keep_doing = 0; + } + + /* stop when we encounter a header length of 0 */ + if (p[0] == 0) + keep_doing = 0; + + /* go to the next tag */ + p += p[0]; + + /* stop if we walked off the end of the buffer */ + if (p > (unsigned long *)(kexec_boot_params + + KEXEC_BOOT_PARAMS_SIZE)) + keep_doing = 0; + + } while (keep_doing); + + return (strlen(page)); +} +KERNEL_ATTR_RO(kexec_boot_params); + static ssize_t kexec_loaded_show(struct subsystem *subsys, char *page) { return sprintf(page, "%d\n", !!kexec_image); @@ -60,6 +219,7 @@ return sprintf(page, "%d\n", !!kexec_crash_image); } KERNEL_ATTR_RO(kexec_crash_loaded); + #endif /* CONFIG_KEXEC */ decl_subsys(kernel, NULL, NULL); @@ -73,6 +233,8 @@ #ifdef CONFIG_KEXEC &kexec_loaded_attr.attr, &kexec_crash_loaded_attr.attr, + &kexec_cmdline_attr.attr, + &kexec_boot_params_attr.attr, #endif NULL };