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