diff --git a/include/linux/kexec.h b/include/linux/kexec.h index 8c2c7fc..a0412ce 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -121,6 +121,8 @@ extern struct page *kimage_alloc_control_pages(struct kimage *image, extern void crash_kexec(struct pt_regs *); int kexec_should_crash(struct task_struct *); void crash_save_cpu(struct pt_regs *regs, int cpu); +void crash_save_mkdfinfo(void); + extern struct kimage *kexec_image; extern struct kimage *kexec_crash_image; @@ -153,7 +155,10 @@ extern struct kimage *kexec_crash_image; extern struct resource crashk_res; typedef u32 note_buf_t[KEXEC_NOTE_BYTES/4]; extern note_buf_t *crash_notes; - +extern unsigned char mkdfinfo_data[MAX_NOTE_BYTES]; +extern unsigned int mkdfinfo_size; +extern unsigned int mkdfinfo_max_size; +extern note_buf_t mkdfinfo_note; #else /* !CONFIG_KEXEC */ struct pt_regs; diff --git a/kernel/kexec.c b/kernel/kexec.c index 25db14b..25228e3 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -32,6 +34,12 @@ /* Per cpu memory for storing cpu states in case of system crash. */ note_buf_t* crash_notes; +/* mkdfinfo stuff */ +unsigned char mkdfinfo_data[MAX_NOTE_BYTES]; +unsigned int mkdfinfo_size = 0; +unsigned int mkdfinfo_max_size = sizeof(mkdfinfo_data); +note_buf_t mkdfinfo_note; + /* Location of the reserved area for the crash kernel */ struct resource crashk_res = { .name = "Crash kernel", @@ -1062,6 +1070,7 @@ void crash_kexec(struct pt_regs *regs) struct pt_regs fixed_regs; crash_setup_regs(&fixed_regs, regs); machine_crash_shutdown(&fixed_regs); + crash_save_mkdfinfo(); machine_kexec(kexec_crash_image); } locked = xchg(&kexec_lock, 0); @@ -1135,3 +1144,88 @@ static int __init crash_notes_memory_init(void) return 0; } module_init(crash_notes_memory_init) + +void crash_save_mkdfinfo(void) +{ + u32 *buf; + + if (!mkdfinfo_size) + return; + + buf = (u32 *)mkdfinfo_note; + buf = append_elf_note(buf, "LINUX", 0, mkdfinfo_data, + mkdfinfo_size); + final_note(buf); +} + +void mkdfinfo_append_str(const char *fmt, ...) +{ + va_list args; + char buf[0x50]; + int r; + + va_start(args, fmt); + r = vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + if (r + mkdfinfo_size > mkdfinfo_max_size) + r = mkdfinfo_max_size - mkdfinfo_size; + + memcpy(&mkdfinfo_data[mkdfinfo_size], buf, r); + + mkdfinfo_size += r; +} + +#define SYMBOL(name) \ + mkdfinfo_append_str("SYMBOL(%s)=%lx\n", #name, (unsigned long)&name) +#define SIZE(name) \ + mkdfinfo_append_str("SIZE(%s)=%d\n", #name, sizeof(struct name)) +#define OFFSET(name, field) \ + mkdfinfo_append_str("OFFSET(%s.%s)=%d\n", #name, #field, &(((struct name *)0)->field)) +#define LENGTH(name, field) \ + mkdfinfo_append_str("LENGTH(%s.%s)=%d\n", #name, #field, sizeof(((struct name *)0)->field)) + +static int __init crash_save_mkdfinfo_init(void) +{ + extern char _stext; + + mkdfinfo_append_str("OSRELEASE=%s\n", UTS_RELEASE); + mkdfinfo_append_str("PAGESIZE=%d\n", PAGE_SIZE); + + SYMBOL(mem_map); + SYMBOL(init_uts_ns); + SYMBOL(_stext); + SYMBOL(node_online_map); + SYMBOL(contig_page_data); + SIZE(page); + SIZE(pglist_data); + SIZE(zone); + SIZE(free_area); + SIZE(list_head); + OFFSET(page, flags); + OFFSET(page, _count); + OFFSET(page, mapping); + OFFSET(page, lru); + OFFSET(pglist_data, node_zones); + OFFSET(pglist_data, nr_zones); + OFFSET(pglist_data, node_mem_map); + OFFSET(pglist_data, node_start_pfn); + OFFSET(pglist_data, node_spanned_pages); + OFFSET(zone, free_area); + OFFSET(zone, vm_stat); + OFFSET(zone, spanned_pages); + OFFSET(free_area, free_list); + OFFSET(list_head, next); + OFFSET(list_head, prev); + LENGTH(zone, free_area); + +#ifdef __PAGETABLE_PUD_FOLDED + mkdfinfo_append_str("SRCFILE(pud_t)=include/asm-generic/pgtable-nopud.h\n"); +#else + mkdfinfo_append_str("SRCFILE(pud_t)=include/asm/page.h\n"); +#endif + + return 0; +} + +module_init(crash_save_mkdfinfo_init) diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index 559deca..70ddca2 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -60,6 +60,15 @@ static ssize_t kexec_crash_loaded_show(struct kset *kset, char *page) return sprintf(page, "%d\n", !!kexec_crash_image); } KERNEL_ATTR_RO(kexec_crash_loaded); + +static ssize_t mkdfinfo_show(struct subsystem *subsys, char *page) +{ + return sprintf(page, "%lx %x\n", + __pa((unsigned long)(char *)&mkdfinfo_note), + MAX_NOTE_BYTES); +} +KERNEL_ATTR_RO(mkdfinfo); + #endif /* CONFIG_KEXEC */ decl_subsys(kernel, NULL, NULL); @@ -73,6 +82,7 @@ static struct attribute * kernel_attrs[] = { #ifdef CONFIG_KEXEC &kexec_loaded_attr.attr, &kexec_crash_loaded_attr.attr, + &mkdfinfo_attr.attr, #endif NULL };