From: Roland M. Roehrich <rroehric at mc.com>

This patch allows sys_kexec_load to accept a passed in codepage to 
trampoline to a destination kernel.  The existing code assumed that it 
was starting a kernel similar to itself, with a particular set of 
registers, and data.  The patch allows a codepage to be passed in as the 
first segment, which can be customized to the destination kernel.  A 
different customization is needed when going from a 2.6 arch/ppc to 2.6 
arch/powerpc kernel, or from a 2.6 kernel to a 2.4 kernel, or to a 
non-Linux kernel.

Signed-off-by: Roland M. Roehrich <rroehric at mc.com>

---

This patch applies to 2.6.18.  Please comment on the interface.

diff -uprN linux-2.6.18/include/linux/kexec.h 
linux-2.6.18.mercury/include/linux/kexec.h
--- linux-2.6.18/include/linux/kexec.h  2006-09-19 23:42:06.000000000 -0400
+++ linux-2.6.18.mercury/include/linux/kexec.h  2006-10-20 
15:27:33.000047000 -0400
@@ -108,8 +108,9 @@ int kexec_should_crash(struct task_struc
 extern struct kimage *kexec_image;
 extern struct kimage *kexec_crash_image;

-#define KEXEC_ON_CRASH  0x00000001
-#define KEXEC_ARCH_MASK 0xffff0000
+#define KEXEC_ON_CRASH             0x00000001
+#define KEXEC_USE_PASSED_CODEPAGE  0x00000002
+#define KEXEC_ARCH_MASK            0xffff0000

 /* These values match the ELF architecture values.
  * Unless there is a good reason that should continue to be the case.
@@ -123,7 +124,8 @@ extern struct kimage *kexec_crash_image;
 #define KEXEC_ARCH_S390    (22 << 16)
 #define KEXEC_ARCH_SH      (42 << 16)

-#define KEXEC_FLAGS    (KEXEC_ON_CRASH)  /* List of defined/legal kexec 
flags */
+/* List of defined/legal kexec flags */
+#define KEXEC_FLAGS    (KEXEC_ON_CRASH|KEXEC_USE_PASSED_CODEPAGE)

 /* Location of a reserved region to hold the crash kernel.
  */
diff -uprN linux-2.6.18/kernel/kexec.c linux-2.6.18.mercury/kernel/kexec.c
--- linux-2.6.18/kernel/kexec.c 2006-09-19 23:42:06.000000000 -0400
+++ linux-2.6.18.mercury/kernel/kexec.c 2006-10-19 13:37:33.000307000 -0400
@@ -207,7 +207,8 @@ out:

 static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry,
                                unsigned long nr_segments,
-                               struct kexec_segment __user *segments)
+                               struct kexec_segment __user *segments,
+                               unsigned long flags)
 {
        int result;
        struct kimage *image;
@@ -233,6 +234,18 @@ static int kimage_normal_alloc(struct ki
                goto out;
        }

+       if (flags & KEXEC_USE_PASSED_CODEPAGE) {
+               unsigned long pfn, epfn, addr, eaddr;
+
+               pfn   = page_to_pfn(image->control_code_page);
+               epfn  = pfn + 1 << get_order(KEXEC_CONTROL_CODE_SIZE);
+               addr  = pfn << PAGE_SHIFT;
+               eaddr = epfn << PAGE_SHIFT;
+
+               image->segment[0].mem = addr;
+               image->segment[0].memsz = eaddr - addr;
+       }
+
        result = 0;
  out:
        if (result == 0)
@@ -751,6 +764,62 @@ static struct page *kimage_alloc_page(st
        return page;
 }

+static int kimage_load_control_segment(struct kimage *image)
+{
+       struct kexec_segment *segment;
+       unsigned long maddr;
+       unsigned long ubytes, mbytes;
+       int result;
+       unsigned char __user *buf;
+       unsigned long pfn;
+
+       result = 0;
+       segment = image->segment;
+       pfn = page_to_pfn(image->control_code_page);
+       buf = segment->buf;
+       ubytes = segment->bufsz;
+       mbytes = segment->memsz;
+       maddr = segment->mem;
+
+       result = kimage_set_destination(image, maddr);
+       if (result < 0)
+               goto out;
+
+       while (mbytes) {
+               struct page *page;
+               char *ptr;
+               size_t uchunk, mchunk;
+
+               page = pfn_to_page(pfn);
+
+               ptr = kmap(page);
+               /* Start with a clear page */
+               memset(ptr, 0, PAGE_SIZE);
+               ptr += maddr & ~PAGE_MASK;
+               mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK);
+               if (mchunk > mbytes)
+                       mchunk = mbytes;
+
+               uchunk = mchunk;
+               if (uchunk > ubytes)
+                       uchunk = ubytes;
+
+               result = copy_from_user(ptr, buf, uchunk);
+               kunmap(page);
+               if (result) {
+                       result = (result < 0) ? result : -EIO;
+                       goto out;
+               }
+               ubytes -= uchunk;
+               maddr  += mchunk;
+               buf    += mchunk;
+               mbytes -= mchunk;
+               pfn++;
+       }
+out:
+       return result;
+}
+
 static int kimage_load_normal_segment(struct kimage *image,
                                         struct kexec_segment *segment)
 {
@@ -965,7 +1034,7 @@ asmlinkage long sys_kexec_load(unsigned
                /* Loading another kernel to reboot into */
                if ((flags & KEXEC_ON_CRASH) == 0)
                        result = kimage_normal_alloc(&image, entry,
-                                                       nr_segments, 
segments);
+                                                       nr_segments, 
segments, flags);
                /* Loading another kernel to switch to if this one 
crashes */
                else if (flags & KEXEC_ON_CRASH) {
                        /* Free any current crash dump kernel before
@@ -982,7 +1051,18 @@ asmlinkage long sys_kexec_load(unsigned
                if (result)
                        goto out;

-               for (i = 0; i < nr_segments; i++) {
+               if (flags & KEXEC_USE_PASSED_CODEPAGE) {
+                       result = kimage_load_control_segment(image);
+                       if (result)
+                               goto out;
+                       i=1;
+                       image->codepage_loaded = KEXEC_CODEPAGE_LOADED;
+               } else {
+                       i=0;    /* i.e. NO KEXEC_USE_PASSED_CODEPAGE */
+                       image->codepage_loaded = KEXEC_CODEPAGE_UNLOADED;
+               }
+
+               for (i = i; i < nr_segments; i++) {
                        result = kimage_load_segment(image, 
&image->segment[i]);
                        if (result)
                                goto out;

_______________________________________________
fastboot mailing list
[email protected]
https://lists.osdl.org/mailman/listinfo/fastboot

Reply via email to