[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 01/04] Kexec / Kdump: Generic code



[PATCH 01/04] Kexec / Kdump: Generic code

This patch implements the generic portion of the Kexec / Kdump port to Xen.

Signed-Off-By: Magnus Damm <magnus@xxxxxxxxxxxxx>
---

 Applies on top of xen-unstable-11760.

 linux-2.6-xen-sparse/drivers/xen/core/Makefile        |    1
 linux-2.6-xen-sparse/drivers/xen/core/reboot.c        |    4
 patches/linux-2.6.16.29/series                        |    1
 linux-2.6-xen-sparse/drivers/xen/core/crash.c         |   49 ++
 linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c |   76 +++
 patches/linux-2.6.16.29/kexec-generic.patch           |  283 ++++++++++++
 xen/arch/ia64/xen/crash.c                             |   26 +
 xen/arch/ia64/xen/machine_kexec.c                     |   41 +
 xen/arch/powerpc/crash.c                              |   26 +
 xen/arch/powerpc/machine_kexec.c                      |   41 +
 xen/arch/x86/crash.c                                  |   26 +
 xen/arch/x86/machine_kexec.c                          |   41 +
 xen/common/kexec.c                                    |  260 +++++++++++
 xen/include/asm-ia64/kexec.h                          |   32 +
 xen/include/asm-x86/kexec.h                           |   31 +
 xen/include/public/kexec.h                            |   84 +++
 xen/include/xen/elfcore.h                             |   73 +++
 xen/include/xen/kexec.h                               |   30 +
 xen/arch/ia64/xen/Makefile                            |    2
 xen/arch/powerpc/Makefile                             |    2
 xen/arch/x86/Makefile                                 |    2
 xen/common/Makefile                                   |    1
 xen/common/page_alloc.c                               |   33 -
 xen/drivers/char/console.c                            |    3
 xen/include/xen/hypercall.h                           |    6
 xen/include/xen/mm.h                                  |    1
 26 files changed, 1164 insertions(+), 11 deletions(-)

--- 0001/linux-2.6-xen-sparse/drivers/xen/core/Makefile
+++ work/linux-2.6-xen-sparse/drivers/xen/core/Makefile 2006-10-16 
12:04:03.000000000 +0900
@@ -11,3 +11,4 @@ obj-$(CONFIG_XEN_SYSFS)               += xen_sysfs.o
 obj-$(CONFIG_XEN_SKBUFF)       += skbuff.o
 obj-$(CONFIG_XEN_REBOOT)       += reboot.o
 obj-$(CONFIG_XEN_SMPBOOT)      += smpboot.o
+obj-$(CONFIG_KEXEC)            += machine_kexec.o crash.o
--- /dev/null
+++ work/linux-2.6-xen-sparse/drivers/xen/core/crash.c  2006-10-16 
12:04:04.000000000 +0900
@@ -0,0 +1,49 @@
+/*
+ * drivers/xen/core/crash.c
+ * Architecture independent functions for kexec based crash dumps in xen.
+ *
+ * Created by: Horms <horms@xxxxxxxxxxxx>
+ *
+ */
+
+#include <asm/ptrace.h>
+#include <linux/types.h>
+#include <asm/kexec-xen.h>
+#include <asm/hypervisor.h>
+#include <asm/system.h>
+#include <linux/preempt.h>
+#include <linux/smp.h>
+#include <asm/hw_irq.h>
+#include <xen/interface/kexec.h>
+
+/* 
+ * This passes the registers's down to the hypervisor and has it kexec()
+ * This is a bit different to the linux implementation which
+ * has this call save registers and stop CPUs and then goes into
+ * machine_kexec() later. But for Xen it makes more sense to
+ * have the kexec hypercall do everything, and this call
+ * has the registers parameter that is needed.
+ * to the hypervisor to allow the hypervisor to kdump itself
+ * on an internal panic 
+ */
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+       struct cpu_user_regs xen_regs;
+       printk("machine_crash_shutdown: %d\n", smp_processor_id());
+       local_irq_disable();
+#ifdef CONFIG_X86_IO_APIC
+       disable_IO_APIC();
+#endif
+       crash_translate_regs(regs, &xen_regs);
+       HYPERVISOR_kexec(KEXEC_CMD_kexec, KEXEC_TYPE_CRASH, &xen_regs);
+}
+
+/*
+ * Local variables:
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
--- /dev/null
+++ work/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c  2006-10-16 
12:04:04.000000000 +0900
@@ -0,0 +1,76 @@
+/*
+ * drivers/xen/core/machine_kexec.c 
+ * handle transition of Linux booting another kernel
+ *
+ * Created By: Horms <horms@xxxxxxxxxxxx>
+ *
+ * Losely based on arch/i386/kernel/machine_kexec.c
+ */
+
+#include <linux/kexec.h>
+#include <xen/interface/kexec.h>
+#include <linux/mm.h>
+#include <asm/hypercall.h>
+#include <asm/kexec-xen.h>
+
+extern void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, 
+                                        struct kimage *image);
+
+static void setup_load_arg(xen_kexec_image_t *xki, struct kimage *image)
+{
+       memset(xki, 0, sizeof(*xki));
+
+       machine_kexec_setup_load_arg(xki, image);
+
+       xki->indirection_page = image->head;
+       xki->start_address = image->start;
+}
+
+/*
+ * Load the image into xen so xen can kdump itself
+ * This might have been done in prepare, but prepare
+ * is currently called too early. It might make sense
+ * to move prepare, but for now, just add an extra hook.
+ */
+int xen_machine_kexec_load(struct kimage *image)
+{
+       xen_kexec_image_t xki;
+
+       setup_load_arg(&xki, image);
+       return HYPERVISOR_kexec(KEXEC_CMD_kexec_load, image->type, &xki);
+}
+
+/*
+ * Unload the image that was stored by machine_kexec_load()
+ * This might have been done in machine_kexec_cleanup() but it
+ * is called too late, and its possible xen could try and kdump
+ * using resources that have been freed.
+ */
+void xen_machine_kexec_unload(struct kimage *image)
+{
+       HYPERVISOR_kexec(KEXEC_CMD_kexec_unload, image->type, NULL);
+}
+
+/*
+ * Do not allocate memory (or fail in any way) in machine_kexec().
+ * We are past the point of no return, committed to rebooting now.
+ *
+ * This has the hypervisor move to the prefered reboot CPU, 
+ * stop all CPUs and kexec. That is it combines machine_shutdown()
+ * and machine_kexec() in Linux kexec terms.
+ */
+NORET_TYPE void xen_machine_kexec(struct kimage *image)
+{
+       HYPERVISOR_kexec(KEXEC_CMD_kexec, image->type, NULL);
+       panic("KEXEC_CMD_kexec hypercall should not return\n");
+}
+
+/*
+ * Local variables:
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
--- 0001/linux-2.6-xen-sparse/drivers/xen/core/reboot.c
+++ work/linux-2.6-xen-sparse/drivers/xen/core/reboot.c 2006-10-16 
12:04:03.000000000 +0900
@@ -65,6 +65,10 @@ void machine_power_off(void)
        HYPERVISOR_shutdown(SHUTDOWN_poweroff);
 }
 
+#ifdef CONFIG_KEXEC
+void machine_shutdown(void) { }
+#endif
+
 int reboot_thru_bios = 0;      /* for dmi_scan.c */
 EXPORT_SYMBOL(machine_restart);
 EXPORT_SYMBOL(machine_halt);
--- /dev/null
+++ work/patches/linux-2.6.16.29/kexec-generic.patch    2006-10-16 
12:04:04.000000000 +0900
@@ -0,0 +1,283 @@
+ drivers/base/cpu.c    |   20 +++++++++++++++++
+ include/linux/kexec.h |    5 ++++
+ kernel/kexec.c        |   57 ++++++++++++++++++++++++++++++++++++++-----------
+ kernel/sys.c          |    4 +++
+ 4 files changed, 74 insertions(+), 12 deletions(-)
+
+--- x/drivers/base/cpu.c
++++ x/drivers/base/cpu.c
+@@ -11,6 +11,10 @@
+ 
+ #include "base.h"
+ 
++#ifdef CONFIG_XEN
++#include <xen/interface/kexec.h>
++#endif
++
+ struct sysdev_class cpu_sysdev_class = {
+       set_kset_name("cpu"),
+ };
+@@ -86,6 +90,18 @@ static inline void register_cpu_control(
+ #ifdef CONFIG_KEXEC
+ #include <linux/kexec.h>
+ 
++#ifdef CONFIG_XEN
++static unsigned long get_crash_notes(int cpu)
++{
++      unsigned long crash_note;
++
++      if (HYPERVISOR_kexec(KEXEC_CMD_kexec_crash_note, cpu, &crash_note) < 0)
++              return 0UL;
++      return crash_note;
++}
++#endif
++
++/* XXX: This only finds dom0's CPU's */
+ static ssize_t show_crash_notes(struct sys_device *dev, char *buf)
+ {
+       struct cpu *cpu = container_of(dev, struct cpu, sysdev);
+@@ -101,7 +117,11 @@ static ssize_t show_crash_notes(struct s
+        * boot up and this data does not change there after. Hence this
+        * operation should be safe. No locking required.
+        */
++#ifndef CONFIG_XEN
+       addr = __pa(per_cpu_ptr(crash_notes, cpunum));
++#else
++      addr = (unsigned long long)get_crash_notes(cpunum);
++#endif
+       rc = sprintf(buf, "%Lx\n", addr);
+       return rc;
+ }
+--- x/include/linux/kexec.h
++++ x/include/linux/kexec.h
+@@ -91,6 +91,11 @@ struct kimage {
+ extern NORET_TYPE void machine_kexec(struct kimage *image) ATTRIB_NORET;
+ extern int machine_kexec_prepare(struct kimage *image);
+ extern void machine_kexec_cleanup(struct kimage *image);
++#ifdef CONFIG_XEN
++extern int xen_machine_kexec_load(struct kimage *image);
++extern void xen_machine_kexec_unload(struct kimage *image);
++extern NORET_TYPE void xen_machine_kexec(struct kimage *image) ATTRIB_NORET;
++#endif
+ extern asmlinkage long sys_kexec_load(unsigned long entry,
+                                       unsigned long nr_segments,
+                                       struct kexec_segment __user *segments,
+--- x/kernel/kexec.c
++++ x/kernel/kexec.c
+@@ -26,6 +26,9 @@
+ #include <asm/io.h>
+ #include <asm/system.h>
+ #include <asm/semaphore.h>
++#ifdef CONFIG_XEN
++#include <asm/kexec-xen.h>
++#endif
+ 
+ /* Per cpu memory for storing cpu states in case of system crash. */
+ note_buf_t* crash_notes;
+@@ -403,7 +406,7 @@ static struct page *kimage_alloc_normal_
+               pages = kimage_alloc_pages(GFP_KERNEL, order);
+               if (!pages)
+                       break;
+-              pfn   = page_to_pfn(pages);
++              pfn   = kexec_page_to_pfn(pages);
+               epfn  = pfn + count;
+               addr  = pfn << PAGE_SHIFT;
+               eaddr = epfn << PAGE_SHIFT;
+@@ -437,6 +440,7 @@ static struct page *kimage_alloc_normal_
+       return pages;
+ }
+ 
++#ifndef CONFIG_XEN
+ static struct page *kimage_alloc_crash_control_pages(struct kimage *image,
+                                                     unsigned int order)
+ {
+@@ -490,7 +494,7 @@ static struct page *kimage_alloc_crash_c
+               }
+               /* If I don't overlap any segments I have found my hole! */
+               if (i == image->nr_segments) {
+-                      pages = pfn_to_page(hole_start >> PAGE_SHIFT);
++                      pages = kexec_pfn_to_page(hole_start >> PAGE_SHIFT);
+                       break;
+               }
+       }
+@@ -517,6 +521,13 @@ struct page *kimage_alloc_control_pages(
+ 
+       return pages;
+ }
++#else /* !CONFIG_XEN */
++struct page *kimage_alloc_control_pages(struct kimage *image,
++                                       unsigned int order)
++{
++      return kimage_alloc_normal_control_pages(image, order);
++}
++#endif
+ 
+ static int kimage_add_entry(struct kimage *image, kimage_entry_t entry)
+ {
+@@ -532,7 +543,7 @@ static int kimage_add_entry(struct kimag
+                       return -ENOMEM;
+ 
+               ind_page = page_address(page);
+-              *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION;
++              *image->entry = kexec_virt_to_phys(ind_page) | IND_INDIRECTION;
+               image->entry = ind_page;
+               image->last_entry = ind_page +
+                                     ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1);
+@@ -593,13 +604,13 @@ static int kimage_terminate(struct kimag
+ #define for_each_kimage_entry(image, ptr, entry) \
+       for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \
+               ptr = (entry & IND_INDIRECTION)? \
+-                      phys_to_virt((entry & PAGE_MASK)): ptr +1)
++                      kexec_phys_to_virt((entry & PAGE_MASK)): ptr +1)
+ 
+ static void kimage_free_entry(kimage_entry_t entry)
+ {
+       struct page *page;
+ 
+-      page = pfn_to_page(entry >> PAGE_SHIFT);
++      page = kexec_pfn_to_page(entry >> PAGE_SHIFT);
+       kimage_free_pages(page);
+ }
+ 
+@@ -611,6 +622,10 @@ static void kimage_free(struct kimage *i
+       if (!image)
+               return;
+ 
++#ifdef CONFIG_XEN
++      xen_machine_kexec_unload(image);
++#endif
++
+       kimage_free_extra_pages(image);
+       for_each_kimage_entry(image, ptr, entry) {
+               if (entry & IND_INDIRECTION) {
+@@ -686,7 +701,7 @@ static struct page *kimage_alloc_page(st
+        * have a match.
+        */
+       list_for_each_entry(page, &image->dest_pages, lru) {
+-              addr = page_to_pfn(page) << PAGE_SHIFT;
++              addr = kexec_page_to_pfn(page) << PAGE_SHIFT;
+               if (addr == destination) {
+                       list_del(&page->lru);
+                       return page;
+@@ -701,12 +716,12 @@ static struct page *kimage_alloc_page(st
+               if (!page)
+                       return NULL;
+               /* If the page cannot be used file it away */
+-              if (page_to_pfn(page) >
++              if (kexec_page_to_pfn(page) >
+                               (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) {
+                       list_add(&page->lru, &image->unuseable_pages);
+                       continue;
+               }
+-              addr = page_to_pfn(page) << PAGE_SHIFT;
++              addr = kexec_page_to_pfn(page) << PAGE_SHIFT;
+ 
+               /* If it is the destination page we want use it */
+               if (addr == destination)
+@@ -729,7 +744,7 @@ static struct page *kimage_alloc_page(st
+                       struct page *old_page;
+ 
+                       old_addr = *old & PAGE_MASK;
+-                      old_page = pfn_to_page(old_addr >> PAGE_SHIFT);
++                      old_page = kexec_pfn_to_page(old_addr >> PAGE_SHIFT);
+                       copy_highpage(page, old_page);
+                       *old = addr | (*old & ~PAGE_MASK);
+ 
+@@ -779,7 +794,7 @@ static int kimage_load_normal_segment(st
+                       result  = -ENOMEM;
+                       goto out;
+               }
+-              result = kimage_add_page(image, page_to_pfn(page)
++              result = kimage_add_page(image, kexec_page_to_pfn(page)
+                                                               << PAGE_SHIFT);
+               if (result < 0)
+                       goto out;
+@@ -811,6 +826,7 @@ out:
+       return result;
+ }
+ 
++#ifndef CONFIG_XEN
+ static int kimage_load_crash_segment(struct kimage *image,
+                                       struct kexec_segment *segment)
+ {
+@@ -833,7 +849,7 @@ static int kimage_load_crash_segment(str
+               char *ptr;
+               size_t uchunk, mchunk;
+ 
+-              page = pfn_to_page(maddr >> PAGE_SHIFT);
++              page = kexec_pfn_to_page(maddr >> PAGE_SHIFT);
+               if (page == 0) {
+                       result  = -ENOMEM;
+                       goto out;
+@@ -881,6 +897,13 @@ static int kimage_load_segment(struct ki
+ 
+       return result;
+ }
++#else /* CONFIG_XEN */
++static int kimage_load_segment(struct kimage *image,
++                              struct kexec_segment *segment)
++{
++      return kimage_load_normal_segment(image, segment);
++}
++#endif
+ 
+ /*
+  * Exec Kernel system call: for obvious reasons only root may call it.
+@@ -991,6 +1014,11 @@ asmlinkage long sys_kexec_load(unsigned 
+               if (result)
+                       goto out;
+       }
++#ifdef CONFIG_XEN
++      result = xen_machine_kexec_load(image);
++      if (result)
++              goto out;
++#endif
+       /* Install the new kernel, and  Uninstall the old */
+       image = xchg(dest_image, image);
+ 
+@@ -1045,7 +1073,6 @@ void crash_kexec(struct pt_regs *regs)
+       struct kimage *image;
+       int locked;
+ 
+-
+       /* Take the kexec_lock here to prevent sys_kexec_load
+        * running on one cpu from replacing the crash kernel
+        * we are using after a panic on a different cpu.
+@@ -1061,12 +1088,17 @@ void crash_kexec(struct pt_regs *regs)
+                       struct pt_regs fixed_regs;
+                       crash_setup_regs(&fixed_regs, regs);
+                       machine_crash_shutdown(&fixed_regs);
++#ifdef CONFIG_XEN
++                      xen_machine_kexec(image);
++#else
+                       machine_kexec(image);
++#endif
+               }
+               xchg(&kexec_lock, 0);
+       }
+ }
+ 
++#ifndef CONFIG_XEN
+ static int __init crash_notes_memory_init(void)
+ {
+       /* Allocate memory for saving cpu registers. */
+@@ -1079,3 +1111,4 @@ static int __init crash_notes_memory_ini
+       return 0;
+ }
+ module_init(crash_notes_memory_init)
++#endif
+--- x/kernel/sys.c
++++ x/kernel/sys.c
+@@ -435,8 +435,12 @@ void kernel_kexec(void)
+       kernel_restart_prepare(NULL);
+       printk(KERN_EMERG "Starting new kernel\n");
+       machine_shutdown();
++#ifdef CONFIG_XEN
++      xen_machine_kexec(image);
++#else
+       machine_kexec(image);
+ #endif
++#endif
+ }
+ EXPORT_SYMBOL_GPL(kernel_kexec);
+ 
--- 0001/patches/linux-2.6.16.29/series
+++ work/patches/linux-2.6.16.29/series 2006-10-16 12:04:03.000000000 +0900
@@ -1,3 +1,4 @@
+kexec-generic.patch
 blktap-aio-16_03_06.patch
 device_bind.patch
 fix-hz-suspend.patch
--- 0001/xen/arch/ia64/xen/Makefile
+++ work/xen/arch/ia64/xen/Makefile     2006-10-16 12:04:03.000000000 +0900
@@ -25,5 +25,7 @@ obj-y += xensetup.o
 obj-y += xentime.o
 obj-y += flushd.o
 obj-y += privop_stat.o
+obj-y += machine_kexec.o
+obj-y += crash.o
 
 obj-$(crash_debug) += gdbstub.o
--- /dev/null
+++ work/xen/arch/ia64/xen/crash.c      2006-10-16 12:04:04.000000000 +0900
@@ -0,0 +1,26 @@
+/**********************************************************************
+ * arch/ia64/xen/crash.c
+ *
+ * Created By: Horms
+ * 
+ */
+
+#include <xen/lib.h>       /* for printk() used in stub */
+#include <xen/types.h>
+#include <public/kexec.h>
+
+void machine_crash_shutdown(struct cpu_user_regs *regs)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
--- /dev/null
+++ work/xen/arch/ia64/xen/machine_kexec.c      2006-10-16 12:04:04.000000000 
+0900
@@ -0,0 +1,41 @@
+/**********************************************************************
+ * arch/ia64/xen/machine_kexec.c
+ *
+ * Created By: Horms
+ * 
+ */
+
+#include <xen/lib.h>       /* for printk() used in stubs */
+#include <xen/types.h>
+#include <public/kexec.h>
+
+int machine_kexec_load(int type, xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+    return -1;
+}
+
+void machine_kexec_unload(int type, xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+void machine_kexec(xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+void machine_shutdown(xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- 0001/xen/arch/powerpc/Makefile
+++ work/xen/arch/powerpc/Makefile      2006-10-16 12:04:03.000000000 +0900
@@ -40,6 +40,8 @@ obj-y += smp-tbsync.o
 obj-y += sysctl.o
 obj-y += time.o
 obj-y += usercopy.o
+obj-y += machine_kexec.o
+obj-y += crash.o
 
 obj-$(debug) += 0opt.o
 obj-$(crash_debug) += gdbstub.o
--- /dev/null
+++ work/xen/arch/powerpc/crash.c       2006-10-16 12:04:04.000000000 +0900
@@ -0,0 +1,26 @@
+/**********************************************************************
+ * arch/powerpc/crash.c
+ *
+ * Created By: Horms
+ * 
+ */
+
+#include <xen/lib.h>       /* for printk() used in stub */
+#include <xen/types.h>
+#include <public/kexec.h>
+
+void machine_crash_shutdown(struct cpu_user_regs *regs)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
--- /dev/null
+++ work/xen/arch/powerpc/machine_kexec.c       2006-10-16 12:04:04.000000000 
+0900
@@ -0,0 +1,41 @@
+/**********************************************************************
+ * arch/powerpc/machine_kexec.c
+ *
+ * Created By: Horms
+ * 
+ */
+
+#include <xen/lib.h>       /* for printk() used in stubs */
+#include <xen/types.h>
+#include <public/kexec.h>
+
+int machine_kexec_load(int type, xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+    return -1;
+}
+
+void machine_kexec_unload(int type, xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+void machine_kexec(xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+void machine_shutdown(xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- 0001/xen/arch/x86/Makefile
+++ work/xen/arch/x86/Makefile  2006-10-16 12:04:03.000000000 +0900
@@ -41,6 +41,8 @@ obj-y += trampoline.o
 obj-y += traps.o
 obj-y += usercopy.o
 obj-y += x86_emulate.o
+obj-y += machine_kexec.o
+obj-y += crash.o
 
 obj-$(crash_debug) += gdbstub.o
 
--- /dev/null
+++ work/xen/arch/x86/crash.c   2006-10-16 12:04:04.000000000 +0900
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * arch/x86/crash.c
+ * 
+ * Created By: Horms
+ *
+ * Should be based heavily on arch/i386/kernel/crash.c from Linux 2.6.16
+ */
+
+#include <xen/lib.h>       /* for printk() used in stub */
+#include <xen/types.h>
+#include <public/xen.h>
+
+void machine_crash_shutdown(struct cpu_user_regs *regs)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- /dev/null
+++ work/xen/arch/x86/machine_kexec.c   2006-10-16 12:04:04.000000000 +0900
@@ -0,0 +1,41 @@
+/******************************************************************************
+ * arch/x86/machine_kexec.c
+ * 
+ * Created By: Horms
+ *
+ */
+
+#include <xen/lib.h>       /* for printk() used in stubs */
+#include <xen/types.h>
+#include <public/kexec.h>
+
+int machine_kexec_load(int type, xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+    return -1;
+}
+
+void machine_kexec_unload(int type, xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+void machine_kexec(xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+void machine_shutdown(xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- 0001/xen/common/Makefile
+++ work/xen/common/Makefile    2006-10-16 12:04:03.000000000 +0900
@@ -7,6 +7,7 @@ obj-y += event_channel.o
 obj-y += grant_table.o
 obj-y += kernel.o
 obj-y += keyhandler.o
+obj-y += kexec.o
 obj-y += lib.o
 obj-y += memory.o
 obj-y += multicall.o
--- /dev/null
+++ work/xen/common/kexec.c     2006-10-16 12:23:11.000000000 +0900
@@ -0,0 +1,260 @@
+/******************************************************************************
+ * common/kexec.c - Achitecture independent kexec code for Xen
+ *
+ * Created By: Horms <horms@xxxxxxxxxxxx>
+ *
+ * Based in part on Linux 2.6.16's kernel/kexec.c
+ */
+
+#include <asm/kexec.h>
+#include <xen/lib.h>
+#include <xen/ctype.h>
+#include <xen/errno.h>
+#include <xen/guest_access.h>
+#include <xen/sched.h>
+#include <xen/types.h>
+#include <xen/kexec.h>
+#include <xen/keyhandler.h>
+#include <public/kexec.h>
+
+static char opt_crashkernel[32] = "";
+string_param("crashkernel", opt_crashkernel);
+
+DEFINE_PER_CPU (note_buf_t, crash_notes);
+
+static xen_kexec_image_t kexec_image;
+static int kexec_image_set = 0;
+static xen_kexec_image_t kexec_crash_image;
+static int kexec_crash_image_set = 0;
+static int kexec_crash_lock = 0;
+
+/* Must call with kexec_crash_lock held */
+void __crash_kexec(struct cpu_user_regs *regs)
+{
+    struct cpu_user_regs fixed_regs;
+
+    if (!kexec_crash_image_set)
+           return;
+    crash_setup_regs(&fixed_regs, regs);
+    machine_crash_shutdown(&fixed_regs);
+    machine_kexec(&kexec_crash_image); /* Does not return */
+}
+
+void crash_kexec(struct cpu_user_regs *regs)
+{
+    int locked;
+
+    locked = xchg(&kexec_crash_lock, 1);
+    if (locked)
+        return;
+    __crash_kexec(regs);
+
+    /* The if() here is bogus, but gcc will throws a warning that the
+     * computed value is unused and xen compiles with -Werror.
+     * This seems like a viable work around.
+     * This did not seem to happen with slightly older gcc.
+     * Observed with: 
+     * gcc version 4.1.2 20060604 (prerelease) (Debian * 4.1.1-2) */
+    if (xchg(&kexec_crash_lock, 0)) ;
+
+    return;
+}
+
+static void do_crashdump_trigger(unsigned char key)
+{
+       printk("triggering crashdump\n");
+       crash_kexec(NULL);
+}
+
+static __init int register_crashdump_trigger(void)
+{
+       register_keyhandler('c', do_crashdump_trigger, "trigger a crashdump");
+       return 0;
+}
+__initcall(register_crashdump_trigger);
+
+static int get_crash_note(int vcpuid, XEN_GUEST_HANDLE(void) uarg)
+{
+    struct domain *domain = current->domain;
+    unsigned long crash_note;
+    struct vcpu *vcpu;
+    int locked;
+
+    if (vcpuid < 0 || vcpuid > MAX_VIRT_CPUS)
+       return -EINVAL;
+
+    if ( ! (vcpu = domain->vcpu[vcpuid]) )
+       return -EINVAL;
+
+    locked = xchg(&kexec_crash_lock, 1);
+    if (locked)
+    {
+       printk("do_kexec_op: (CMD_kexec_crash_note): dump is locked\n");
+       return -EFAULT;
+    }
+    crash_note = __pa((unsigned long)per_cpu(crash_notes, vcpu->processor));
+
+    /* The if() here is bogus, but gcc will throws a warning that the
+     * computed value is unused and xen compiles with -Werror.
+     * This seems like a viable work around.
+     * This did not seem to happen with slightly older gcc.
+     * Observed with: 
+     * gcc version 4.1.2 20060604 (prerelease) (Debian * 4.1.1-2) */
+    if (xchg(&kexec_crash_lock, 0)) ;
+
+    if ( unlikely(copy_to_guest(uarg, &crash_note, 1) != 0) )
+    {
+        printk("do_kexec_op: (CMD_kexec_crash_note): copy_to_guest failed\n");
+        return -EFAULT;
+    }
+    
+    return 0;
+}
+
+void machine_kexec_reserved(xen_kexec_reserve_t *reservation)
+{
+    unsigned long val[2];
+    char *str = opt_crashkernel;
+    int k = 0; 
+
+    memset(reservation, 0, sizeof(*reservation));
+
+    while (k < ARRAY_SIZE(val)) {
+        if (*str == '\0') {
+            break;
+        }
+        val[k] = simple_strtoul(str, &str, 0);
+        switch (toupper(*str)) {
+        case 'G': val[k] <<= 10;
+        case 'M': val[k] <<= 10;
+        case 'K': val[k] <<= 10;
+            str++;
+        }
+        if (*str == '@') {
+            str++;
+        }
+        k++;
+    }
+
+    if (k == ARRAY_SIZE(val)) {
+        reservation->size = val[0];
+        reservation->start = val[1];
+    }
+}
+
+static int get_reserve(XEN_GUEST_HANDLE(void) uarg)
+{
+    xen_kexec_reserve_t reservation;
+    
+    machine_kexec_reserved(&reservation);
+    if ( unlikely(copy_to_guest(uarg, &reservation, 1) != 0) )
+    {
+        printk("do_kexec_op (CMD_kexec_reserve): copy_to_guest failed\n");
+        return -EFAULT;
+    }
+    
+    return 0;
+}
+
+static int __do_kexec(unsigned long type, XEN_GUEST_HANDLE(void) uarg,
+                     xen_kexec_image_t *image)
+{
+    cpu_user_regs_t regs;
+
+    if (type == KEXEC_TYPE_DEFAULT)
+        machine_shutdown(image); /* Does not return */
+    else
+    {
+        if ( unlikely(copy_from_guest(&regs, uarg, 1) != 0) )
+        {
+            printk("do_kexec_op (CMD_kexec): copy_from_guest failed\n");
+            return -EFAULT;
+        }
+        __crash_kexec(&regs); /* Does not return */
+    }
+
+    return -EINVAL;
+}
+
+long do_kexec_op(unsigned long op, int arg1, XEN_GUEST_HANDLE(void) uarg)
+{
+    xen_kexec_image_t *image;
+    int locked;
+    int *image_set;
+    int status = -EINVAL;
+
+    if ( !IS_PRIV(current->domain) )  
+        return -EPERM;
+
+    switch (op)
+    {
+    case KEXEC_CMD_kexec_crash_note:
+        return get_crash_note(arg1, uarg);
+    case KEXEC_CMD_kexec_reserve:
+       return get_reserve(uarg);
+    }
+
+    /* For all other ops, arg1 is the type of kexec, that is
+     * KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH */
+    if (arg1 == KEXEC_TYPE_CRASH)
+    {
+        image = &kexec_crash_image;
+        image_set = &kexec_crash_image_set;
+        locked = xchg(&kexec_crash_lock, 1);
+        if (locked)
+        {
+           printk("do_kexec_op: dump is locked\n");
+           return -EFAULT;
+        }
+    }
+    else
+    {
+        image = &kexec_image;
+        image_set = &kexec_image_set;
+    }
+
+    switch(op) {
+    case KEXEC_CMD_kexec:
+        BUG_ON(!*image_set);
+       status = __do_kexec(arg1, uarg, image);
+        break;
+    case KEXEC_CMD_kexec_load:
+        BUG_ON(*image_set);
+        if ( unlikely(copy_from_guest(image, uarg, 1) != 0) )
+        {
+            printk("do_kexec_op (CMD_kexec_load): copy_from_guest failed\n");
+            status = -EFAULT;
+           break;
+        }
+        *image_set = 1;
+        status = machine_kexec_load(arg1, image);
+        break;
+    case KEXEC_CMD_kexec_unload:
+        BUG_ON(!*image_set);
+        *image_set = 0;
+        machine_kexec_unload(arg1, image);
+        status = 0;
+        break;
+    }
+
+    if (arg1 == KEXEC_TYPE_CRASH)
+        /* The if() here is bogus, but gcc will throws a warning that the
+         * computed value is unused and xen compiles with -Werror.
+         * This seems like a viable work around.
+         * This did not seem to happen with slightly older gcc.
+         * Observed with: 
+         * gcc version 4.1.2 20060604 (prerelease) (Debian * 4.1.1-2) */
+        if (xchg(&kexec_crash_lock, 0)) ;
+
+    return status;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- 0001/xen/common/page_alloc.c
+++ work/xen/common/page_alloc.c        2006-10-16 12:04:03.000000000 +0900
@@ -213,24 +213,35 @@ void init_boot_pages(paddr_t ps, paddr_t
     }
 }
 
+unsigned long alloc_boot_pages_at(unsigned long nr_pfns, unsigned long pfn_at)
+{
+    unsigned long i;
+
+    for ( i = 0; i < nr_pfns; i++ )
+        if ( allocated_in_map(pfn_at + i) )
+             break;
+
+    if ( i == nr_pfns )
+    {
+        map_alloc(pfn_at, nr_pfns);
+        return pfn_at;
+    }
+
+    return 0;
+}
+
 unsigned long alloc_boot_pages(unsigned long nr_pfns, unsigned long pfn_align)
 {
-    unsigned long pg, i;
+    unsigned long pg, i = 0;
 
     for ( pg = 0; (pg + nr_pfns) < max_page; pg += pfn_align )
     {
-        for ( i = 0; i < nr_pfns; i++ )
-            if ( allocated_in_map(pg + i) )
-                 break;
-
-        if ( i == nr_pfns )
-        {
-            map_alloc(pg, nr_pfns);
-            return pg;
-        }
+        i = alloc_boot_pages_at(nr_pfns, pg);
+        if (i != 0)
+            break;
     }
 
-    return 0;
+    return i;
 }
 
 
--- 0001/xen/drivers/char/console.c
+++ work/xen/drivers/char/console.c     2006-10-16 12:04:03.000000000 +0900
@@ -613,6 +613,7 @@ void panic(const char *fmt, ...)
     char buf[128];
     unsigned long flags;
     static DEFINE_SPINLOCK(lock);
+    extern void crash_kexec(struct cpu_user_regs *regs);
     
     debugtrace_dump();
 
@@ -635,6 +636,8 @@ void panic(const char *fmt, ...)
 
     debugger_trap_immediate();
 
+    crash_kexec(NULL);
+
     if ( opt_noreboot )
     {
         machine_halt();
--- /dev/null
+++ work/xen/include/asm-ia64/kexec.h   2006-10-16 12:04:04.000000000 +0900
@@ -0,0 +1,32 @@
+/******************************************************************************
+ * include/asm-ia64/kexec.h
+ * 
+ * Created By: Horms
+ *
+ */
+
+#ifndef __IA64_KEXEC_H__
+#define __IA64_KEXEC_H__
+
+#include <xen/lib.h>       /* for printk() used in stub */
+#include <xen/types.h>
+#include <public/xen.h>
+
+static void crash_setup_regs(struct cpu_user_regs *newregs,
+                            struct cpu_user_regs *oldregs)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+#endif /* __IA64_KEXEC_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
--- /dev/null
+++ work/xen/include/asm-x86/kexec.h    2006-10-16 12:04:04.000000000 +0900
@@ -0,0 +1,31 @@
+/******************************************************************************
+ * include/asm-x86/kexec.h
+ * 
+ * Created By: Horms
+ *
+ */
+
+#ifndef __X86_KEXEC_H__
+#define __X86_KEXEC_H__
+
+#include <xen/lib.h>       /* for printk() used in stub */
+#include <xen/types.h>
+#include <public/xen.h>
+
+static void crash_setup_regs(struct cpu_user_regs *newregs,
+                            struct cpu_user_regs *oldregs)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+#endif /* __X86_KEXEC_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- /dev/null
+++ work/xen/include/public/kexec.h     2006-10-16 12:04:04.000000000 +0900
@@ -0,0 +1,84 @@
+/******************************************************************************
+ * kexec.h - Public portion
+ *
+ * Created By: Horms <horms@xxxxxxxxxxxx>
+ *
+ * Types based on those in ./vcpu.h on request from Keir Frasier
+ */
+
+#ifndef _XEN_PUBLIC_KEXEC_H
+#define _XEN_PUBLIC_KEXEC_H
+
+#include "xen.h"
+
+/*
+ * Prototype for this hypercall is:
+ *  int kexec_op(int cmd, int type, void *extra_args)
+ * @cmd        == KEXEC_CMD_... 
+ *                KEXEC operation to perform
+ * @arg1       == Operation-specific unsigned long argument
+ *                This could be in extra_args, but by putting it here
+ *                copy_from_user can be avoided, inparticular in
+ *                KEXEC_CMD_kexec during a crash dump, which is a failry
+ *                critical section of code.If this turns out not to be
+ *                important then it can be collapsed into extra_args.
+ * @extra_args == Operation-specific extra arguments (NULL if none).
+ */
+
+#define KEXEC_TYPE_DEFAULT 0
+#define KEXEC_TYPE_CRASH   1
+
+/*
+ * Perform kexec having previously loaded a kexec or kdump kernel
+ * as appropriate.
+ * @arg1      == KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH
+ * @extra_arg == pointer to cpu_user_regs_t structure.
+ */
+#define KEXEC_CMD_kexec                 0
+
+/*
+ * Load kernel image in preparation for kexec or kdump.
+ * @arg1      == KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH
+ * @extra_arg == pointer to xen_kexec_image_t structure.
+ */
+#define KEXEC_CMD_kexec_load            1
+typedef struct xen_kexec_image {
+    unsigned long indirection_page;
+    unsigned long start_address;
+} xen_kexec_image_t;
+
+/*
+ * Clean up image loaded by KEXEC_CMD_kexec_load
+ * @arg1      == KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH
+ */
+#define KEXEC_CMD_kexec_unload          2
+
+/*
+ * Find the base pointer and size of the area that xen has 
+ * reserved for use by the crash kernel.
+ * @extra_arg == pointer to xen_kexec_reserve_t structure.
+ */
+#define KEXEC_CMD_kexec_reserve         3
+typedef struct xen_kexec_reserve {
+    unsigned long size;
+    unsigned long start;
+} xen_kexec_reserve_t;
+
+/*
+ * Find the base pointer of the area that xen has 
+ * reserved for use by a crash note for a given VCPU
+ * @extra_arg == pointer to unsigned long.
+ */
+#define KEXEC_CMD_kexec_crash_note      4
+
+#endif /* _XEN_PUBLIC_KEXEC_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- /dev/null
+++ work/xen/include/xen/elfcore.h      2006-10-16 12:04:04.000000000 +0900
@@ -0,0 +1,73 @@
+/******************************************************************************
+ * include/xen/elfcore.h
+ * 
+ * Created By: Horms
+ *
+ * Based heavily on include/linux/elfcore.h from Linux 2.6.16
+ * Naming scheeme based on include/xen/elf.h (not include/linux/elfcore.h)
+ *
+ */
+
+#ifndef __ELFCOREC_H__
+#define __ELFCOREC_H__
+
+#include <xen/types.h>
+#include <xen/elf.h>
+#include <public/xen.h>
+
+#define NT_PRSTATUS     1
+
+typedef struct
+{
+    int signo;                       /* signal number */
+    int code;                        /* extra code */
+    int errno;                       /* errno */
+} ELF_Signifo;
+
+/* These seem to be the same length on all architectures on Linux */
+typedef int ELF_Pid;
+typedef struct {
+       long tv_sec;
+       long tv_usec;
+} ELF_Timeval;
+typedef unsigned long ELF_Greg;
+#define ELF_NGREG (sizeof (struct cpu_user_regs) / sizeof(ELF_Greg))
+typedef ELF_Greg ELF_Gregset[ELF_NGREG];
+
+/*
+ * Definitions to generate Intel SVR4-like core files.
+ * These mostly have the same names as the SVR4 types with "elf_"
+ * tacked on the front to prevent clashes with linux definitions,
+ * and the typedef forms have been avoided.  This is mostly like
+ * the SVR4 structure, but more Linuxy, with things that Linux does
+ * not support and which gdb doesn't really use excluded.
+ */
+typedef struct
+{
+    ELF_Signifo pr_info;         /* Info associated with signal */
+    short pr_cursig;             /* Current signal */
+    unsigned long pr_sigpend;    /* Set of pending signals */
+    unsigned long pr_sighold;    /* Set of held signals */
+    ELF_Pid pr_pid;
+    ELF_Pid pr_ppid;
+    ELF_Pid pr_pgrp;
+    ELF_Pid pr_sid;
+    ELF_Timeval pr_utime;        /* User time */
+    ELF_Timeval pr_stime;        /* System time */
+    ELF_Timeval pr_cutime;       /* Cumulative user time */
+    ELF_Timeval pr_cstime;       /* Cumulative system time */
+    ELF_Gregset pr_reg;          /* GP registers */
+    int pr_fpvalid;              /* True if math co-processor being used.  */
+} ELF_Prstatus;
+
+#endif /* __ELFCOREC_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- 0001/xen/include/xen/hypercall.h
+++ work/xen/include/xen/hypercall.h    2006-10-16 12:04:03.000000000 +0900
@@ -102,4 +102,10 @@ do_hvm_op(
     unsigned long op,
     XEN_GUEST_HANDLE(void) arg);
 
+extern long
+do_kexec_op(
+    unsigned long op,
+    int arg1,
+    XEN_GUEST_HANDLE(void) arg);
+
 #endif /* __XEN_HYPERCALL_H__ */
--- /dev/null
+++ work/xen/include/xen/kexec.h        2006-10-16 12:21:58.000000000 +0900
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * include/xen/kexec.h - Internal archtecture independant portion
+ *
+ * Created By: Horms <horms@xxxxxxxxxxxx>
+ *
+ */
+
+#include <public/kexec.h>
+
+#define MAX_NOTE_BYTES 1024
+
+typedef u32 note_buf_t[MAX_NOTE_BYTES/4];
+DECLARE_PER_CPU (note_buf_t, crash_notes);
+
+int machine_kexec_load(int type, xen_kexec_image_t *image);
+void machine_kexec_unload(int type, xen_kexec_image_t *image);
+void machine_kexec_reserved(xen_kexec_reserve_t *reservation);
+void machine_kexec(xen_kexec_image_t *image);
+void machine_shutdown(xen_kexec_image_t *image);
+void machine_crash_shutdown(cpu_user_regs_t *regs);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- 0001/xen/include/xen/mm.h
+++ work/xen/include/xen/mm.h   2006-10-16 12:04:03.000000000 +0900
@@ -40,6 +40,7 @@ struct page_info;
 paddr_t init_boot_allocator(paddr_t bitmap_start);
 void init_boot_pages(paddr_t ps, paddr_t pe);
 unsigned long alloc_boot_pages(unsigned long nr_pfns, unsigned long pfn_align);
+unsigned long alloc_boot_pages_at(unsigned long nr_pfns, unsigned long pfn_at);
 void end_boot_allocator(void);
 
 /* Generic allocator. These functions are *not* interrupt-safe. */

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.