[PATCH 3/3 -mm] kexec jump -v8 : access memory image of kexec_image
This patch adds a file in proc file system to access the loaded kexec_image, which may contains the memory image of kexeced system. This can be used to: - Communicate between original kernel and kexeced kernel through write to some pages in original kernel. - Communicate between original kernel and kexeced kernel through read memory image of kexeced kernel, amend the image, and reload the amended image. - Accelerate boot of kexeced kernel. If you have a memory image of kexeced kernel, you need not a normal boot process to jump to the kexeced kernel, just load the memory image, jump to the point where you leave last time in kexeced kernel. Signed-off-by: Huang Ying <[EMAIL PROTECTED]> --- fs/proc/Makefile |1 fs/proc/kimgcore.c| 277 ++ fs/proc/proc_misc.c |6 + include/linux/kexec.h |7 + kernel/kexec.c|5 5 files changed, 291 insertions(+), 5 deletions(-) --- /dev/null +++ b/fs/proc/kimgcore.c @@ -0,0 +1,277 @@ +/* + * fs/proc/kimgcore.c - Interface for accessing the loaded + * kexec_image, which may contains the memory image of kexeced system. + * Heavily borrowed from fs/proc/kcore.c + * + * Copyright (C) 2007, Intel Corp. + * Huang Ying <[EMAIL PROTECTED]> + * + * This file is released under the GPLv2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct proc_dir_entry *proc_root_kimgcore; + +static u32 kimgcore_size; + +static char *elfcorebuf; +static size_t elfcorebuf_sz; + +static void *buf_page; + +static ssize_t kimage_copy_to_user(struct kimage *image, char __user *buf, + unsigned long offset, size_t count) +{ + kimage_entry_t *ptr, entry; + unsigned long off = 0, offinp, trunk; + struct page *page; + void *vaddr; + + for_each_kimage_entry(image, ptr, entry) { + if (!(entry & IND_SOURCE)) + continue; + if (off + PAGE_SIZE > offset) { + offinp = offset - off; + if (count > PAGE_SIZE - offinp) + trunk = PAGE_SIZE - offinp; + else + trunk = count; + page = pfn_to_page(entry >> PAGE_SHIFT); + if (PageHighMem(page)) { + vaddr = kmap(page); + memcpy(buf_page, vaddr+offinp, trunk); + kunmap(page); + vaddr = buf_page; + } else + vaddr = __va(entry & PAGE_MASK) + offinp; + if (copy_to_user(buf, vaddr, trunk)) + return -EFAULT; + buf += trunk; + offset += trunk; + count -= trunk; + if (!count) + break; + } + off += PAGE_SIZE; + } + return count; +} + +static ssize_t kimage_copy_from_user(struct kimage *image, +const char __user *buf, +unsigned long offset, +size_t count) +{ + kimage_entry_t *ptr, entry; + unsigned long off = 0, offinp, trunk; + struct page *page; + void *vaddr; + + for_each_kimage_entry(image, ptr, entry) { + if (!(entry & IND_SOURCE)) + continue; + if (off + PAGE_SIZE > offset) { + offinp = offset - off; + if (count > PAGE_SIZE - offinp) + trunk = PAGE_SIZE - offinp; + else + trunk = count; + page = pfn_to_page(entry >> PAGE_SHIFT); + if (PageHighMem(page)) + vaddr = buf_page; + else + vaddr = __va(entry & PAGE_MASK) + offinp; + if (copy_from_user(vaddr, buf, trunk)) + return -EFAULT; + if (PageHighMem(page)) { + vaddr = kmap(page); + memcpy(vaddr+offinp, buf_page, trunk); + kunmap(page); + } + buf += trunk; + offset += trunk; + count -= trunk; + if (!count) + break; + } + off += PAGE_SIZE; + } + return count; +} + +static ssize_t read_kimgcore(struct file *file, char __user *buffer, +size_t buflen, loff_t *fpos) +{ + size_t acc = 0; + size_t tsz;
[PATCH 3/3 -mm] kexec jump -v8 : access memory image of kexec_image
This patch adds a file in proc file system to access the loaded kexec_image, which may contains the memory image of kexeced system. This can be used to: - Communicate between original kernel and kexeced kernel through write to some pages in original kernel. - Communicate between original kernel and kexeced kernel through read memory image of kexeced kernel, amend the image, and reload the amended image. - Accelerate boot of kexeced kernel. If you have a memory image of kexeced kernel, you need not a normal boot process to jump to the kexeced kernel, just load the memory image, jump to the point where you leave last time in kexeced kernel. Signed-off-by: Huang Ying [EMAIL PROTECTED] --- fs/proc/Makefile |1 fs/proc/kimgcore.c| 277 ++ fs/proc/proc_misc.c |6 + include/linux/kexec.h |7 + kernel/kexec.c|5 5 files changed, 291 insertions(+), 5 deletions(-) --- /dev/null +++ b/fs/proc/kimgcore.c @@ -0,0 +1,277 @@ +/* + * fs/proc/kimgcore.c - Interface for accessing the loaded + * kexec_image, which may contains the memory image of kexeced system. + * Heavily borrowed from fs/proc/kcore.c + * + * Copyright (C) 2007, Intel Corp. + * Huang Ying [EMAIL PROTECTED] + * + * This file is released under the GPLv2 + */ + +#include linux/mm.h +#include linux/proc_fs.h +#include linux/user.h +#include linux/elf.h +#include linux/init.h +#include linux/kexec.h +#include linux/io.h +#include linux/highmem.h +#include linux/page-flags.h +#include asm/uaccess.h + +struct proc_dir_entry *proc_root_kimgcore; + +static u32 kimgcore_size; + +static char *elfcorebuf; +static size_t elfcorebuf_sz; + +static void *buf_page; + +static ssize_t kimage_copy_to_user(struct kimage *image, char __user *buf, + unsigned long offset, size_t count) +{ + kimage_entry_t *ptr, entry; + unsigned long off = 0, offinp, trunk; + struct page *page; + void *vaddr; + + for_each_kimage_entry(image, ptr, entry) { + if (!(entry IND_SOURCE)) + continue; + if (off + PAGE_SIZE offset) { + offinp = offset - off; + if (count PAGE_SIZE - offinp) + trunk = PAGE_SIZE - offinp; + else + trunk = count; + page = pfn_to_page(entry PAGE_SHIFT); + if (PageHighMem(page)) { + vaddr = kmap(page); + memcpy(buf_page, vaddr+offinp, trunk); + kunmap(page); + vaddr = buf_page; + } else + vaddr = __va(entry PAGE_MASK) + offinp; + if (copy_to_user(buf, vaddr, trunk)) + return -EFAULT; + buf += trunk; + offset += trunk; + count -= trunk; + if (!count) + break; + } + off += PAGE_SIZE; + } + return count; +} + +static ssize_t kimage_copy_from_user(struct kimage *image, +const char __user *buf, +unsigned long offset, +size_t count) +{ + kimage_entry_t *ptr, entry; + unsigned long off = 0, offinp, trunk; + struct page *page; + void *vaddr; + + for_each_kimage_entry(image, ptr, entry) { + if (!(entry IND_SOURCE)) + continue; + if (off + PAGE_SIZE offset) { + offinp = offset - off; + if (count PAGE_SIZE - offinp) + trunk = PAGE_SIZE - offinp; + else + trunk = count; + page = pfn_to_page(entry PAGE_SHIFT); + if (PageHighMem(page)) + vaddr = buf_page; + else + vaddr = __va(entry PAGE_MASK) + offinp; + if (copy_from_user(vaddr, buf, trunk)) + return -EFAULT; + if (PageHighMem(page)) { + vaddr = kmap(page); + memcpy(vaddr+offinp, buf_page, trunk); + kunmap(page); + } + buf += trunk; + offset += trunk; + count -= trunk; + if (!count) + break; + } + off += PAGE_SIZE; + } + return count; +} + +static ssize_t read_kimgcore(struct file *file, char __user