[PATCH 3/3 -mm] kexec jump -v8 : access memory image of kexec_image

2007-12-20 Thread Huang, Ying
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

2007-12-20 Thread Huang, Ying
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