WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

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

To: Ian Campbell <Ian.Campbell@xxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH 01/04] Kexec / Kdump: Generic code
From: Magnus Damm <magnus@xxxxxxxxxxxxx>
Date: Thu, 30 Nov 2006 16:58:33 +0900
Cc: Ian Pratt <m+Ian.Pratt@xxxxxxxxxxxx>, Kazuo Moriwaka <moriwaka@xxxxxxxxxxxxx>, xen-devel@xxxxxxxxxxxxxxxxxxx, Akio Takebe <takebe_akio@xxxxxxxxxxxxxx>, magnus.damm@xxxxxxxxx, Isaku Yamahata <yamahata@xxxxxxxxxxxxx>, Magnus Damm <magnus@xxxxxxxxxxxxx>, Horms <horms@xxxxxxxxxxxx>, Dave Anderson <anderson@xxxxxxxxxx>, Itsuro ODA <oda@xxxxxxxxxxxxx>
Delivery-date: Wed, 29 Nov 2006 23:59:46 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
In-reply-to: <20061130075828.17411.96371.sendpatchset@localhost>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <20061130075828.17411.96371.sendpatchset@localhost>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
[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>
Signed-Off-By: Simon Horman <horms@xxxxxxxxxxxx>
---

 Applies on top of xen-unstable-12621.

 linux-2.6-xen-sparse/drivers/xen/core/Makefile        |    1
 linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c |  170 +++++++
 patches/linux-2.6.16.33/kexec-generic.patch           |  228 ++++++++++
 patches/linux-2.6.16.33/series                        |    1
 xen/arch/ia64/xen/Makefile                            |    2
 xen/arch/ia64/xen/crash.c                             |   19
 xen/arch/ia64/xen/machine_kexec.c                     |   34 +
 xen/arch/powerpc/Makefile                             |    2
 xen/arch/powerpc/crash.c                              |   19
 xen/arch/powerpc/machine_kexec.c                      |   34 +
 xen/arch/x86/Makefile                                 |    2
 xen/arch/x86/crash.c                                  |   19
 xen/arch/x86/machine_kexec.c                          |   34 +
 xen/common/Makefile                                   |    1
 xen/common/kexec.c                                    |  370 +++++++++++++++++
 xen/common/page_alloc.c                               |   33 +
 xen/drivers/char/console.c                            |    3
 xen/include/asm-ia64/elf.h                            |   30 +
 xen/include/asm-ia64/kexec.h                          |   25 +
 xen/include/asm-powerpc/elf.h                         |   30 +
 xen/include/asm-powerpc/kexec.h                       |   25 +
 xen/include/asm-x86/elf.h                             |   30 +
 xen/include/asm-x86/kexec.h                           |   24 +
 xen/include/public/elfnote.h                          |   19
 xen/include/public/kexec.h                            |  131 ++++++
 xen/include/xen/elf.h                                 |   16
 xen/include/xen/elfcore.h                             |  137 ++++++
 xen/include/xen/hypercall.h                           |    6
 xen/include/xen/kexec.h                               |   43 +
 xen/include/xen/mm.h                                  |    1
 30 files changed, 1466 insertions(+), 23 deletions(-)

--- 0001/linux-2.6-xen-sparse/drivers/xen/core/Makefile
+++ work/linux-2.6-xen-sparse/drivers/xen/core/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_XEN_SYSFS)               += xen_sysfs.o
 obj-$(CONFIG_XEN_SKBUFF)       += skbuff.o
 obj-$(CONFIG_XEN_REBOOT)       += reboot.o machine_reboot.o
 obj-$(CONFIG_XEN_SMPBOOT)      += smpboot.o
+obj-$(CONFIG_KEXEC)            += machine_kexec.o
--- /dev/null
+++ work/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c
@@ -0,0 +1,170 @@
+/*
+ * drivers/xen/core/machine_kexec.c 
+ * handle transition of Linux booting another kernel
+ */
+
+#include <linux/kexec.h>
+#include <xen/interface/kexec.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <asm/hypercall.h>
+
+extern void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, 
+                                        struct kimage *image);
+
+int xen_max_nr_phys_cpus;
+struct resource xen_hypervisor_res;
+struct resource *xen_phys_cpus;
+
+void xen_machine_kexec_setup_resources(void)
+{
+       xen_kexec_range_t range;
+       struct resource *res;
+       int k = 0;
+
+       /* determine maximum number of physical cpus */
+
+       while (1) {
+               memset(&range, 0, sizeof(range));
+               range.range = KEXEC_RANGE_MA_CPU;
+               range.nr = k;
+
+               if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range))
+                       break;
+
+               k++;
+       }
+
+       xen_max_nr_phys_cpus = k;
+
+       /* allocate xen_phys_cpus */
+
+       xen_phys_cpus = alloc_bootmem_low(k * sizeof(struct resource));
+       BUG_ON(!xen_phys_cpus);
+
+       /* fill in xen_phys_cpus with per-cpu crash note information */
+
+       for (k = 0; k < xen_max_nr_phys_cpus; k++) {
+               memset(&range, 0, sizeof(range));
+               range.range = KEXEC_RANGE_MA_CPU;
+               range.nr = k;
+
+               BUG_ON(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range));
+
+               res = xen_phys_cpus + k;
+
+               memset(res, 0, sizeof(*res));
+               res->name = "Crash note";
+               res->start = range.start;
+               res->end = range.start + range.size - 1;
+               res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
+       }
+
+       /* fill in xen_hypervisor_res with hypervisor machine address range */
+
+       memset(&range, 0, sizeof(range));
+       range.range = KEXEC_RANGE_MA_XEN;
+
+       BUG_ON(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range));
+
+       xen_hypervisor_res.name = "Hypervisor code and data";
+       xen_hypervisor_res.start = range.start;
+       xen_hypervisor_res.end = range.start + range.size - 1;
+       xen_hypervisor_res.flags = IORESOURCE_BUSY | IORESOURCE_MEM;
+
+       /* fill in crashk_res if range is reserved by hypervisor */
+
+       memset(&range, 0, sizeof(range));
+       range.range = KEXEC_RANGE_MA_CRASH;
+
+       BUG_ON(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range));
+
+       if (range.size) {
+               crashk_res.start = range.start;
+               crashk_res.end = range.start + range.size - 1;
+       }
+}
+
+void xen_machine_kexec_register_resources(struct resource *res)
+{
+       int k;
+
+       request_resource(res, &xen_hypervisor_res);
+
+       for (k = 0; k < xen_max_nr_phys_cpus; k++)
+               request_resource(res, xen_phys_cpus + k);
+
+}
+
+static void setup_load_arg(xen_kexec_image_t *xki, struct kimage *image)
+{
+       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_load_t xkl;
+
+       memset(&xkl, 0, sizeof(xkl));
+       xkl.type = image->type;
+       setup_load_arg(&xkl.image, image);
+       return HYPERVISOR_kexec_op(KEXEC_CMD_kexec_load, &xkl);
+}
+
+/*
+ * 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)
+{
+       xen_kexec_load_t xkl;
+
+       memset(&xkl, 0, sizeof(xkl));
+       xkl.type = image->type;
+       HYPERVISOR_kexec_op(KEXEC_CMD_kexec_unload, &xkl);
+}
+
+/*
+ * 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)
+{
+       xen_kexec_exec_t xke;
+
+       memset(&xke, 0, sizeof(xke));
+       xke.type = image->type;
+       HYPERVISOR_kexec_op(KEXEC_CMD_kexec, &xke);
+       panic("KEXEC_CMD_kexec hypercall should not return\n");
+}
+
+void machine_shutdown(void)
+{
+       /* do nothing */
+}
+
+
+/*
+ * 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/patches/linux-2.6.16.33/kexec-generic.patch
@@ -0,0 +1,228 @@
+--- 0001/include/linux/kexec.h
++++ work/include/linux/kexec.h
+@@ -31,6 +31,13 @@
+ #error KEXEC_ARCH not defined
+ #endif
+ 
++#ifndef KEXEC_ARCH_HAS_PAGE_MACROS
++#define kexec_page_to_pfn(page)  page_to_pfn(page)
++#define kexec_pfn_to_page(pfn)   pfn_to_page(pfn)
++#define kexec_virt_to_phys(addr) virt_to_phys(addr)
++#define kexec_phys_to_virt(addr) phys_to_virt(addr)
++#endif
++
+ /*
+  * This structure is used to hold the arguments that are used when loading
+  * kernel binaries.
+@@ -91,6 +98,13 @@ 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;
++extern void xen_machine_kexec_setup_resources(void);
++extern void xen_machine_kexec_register_resources(struct resource *res);
++#endif
+ extern asmlinkage long sys_kexec_load(unsigned long entry,
+                                       unsigned long nr_segments,
+                                       struct kexec_segment __user *segments,
+--- 0001/kernel/kexec.c
++++ work/kernel/kexec.c
+@@ -403,7 +403,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 +437,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 +491,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 +518,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 +540,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 +601,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 +619,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 +698,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 +713,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 +741,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 +791,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 +823,7 @@ out:
+       return result;
+ }
+ 
++#ifndef CONFIG_XEN
+ static int kimage_load_crash_segment(struct kimage *image,
+                                       struct kexec_segment *segment)
+ {
+@@ -833,7 +846,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 +894,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 +1011,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 +1070,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,7 +1085,11 @@ 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);
+       }
+--- 0002/kernel/sys.c
++++ work/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.33/series
+++ work/patches/linux-2.6.16.33/series
@@ -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
@@ -1,3 +1,5 @@
+obj-y += machine_kexec.o
+obj-y += crash.o
 obj-y += acpi.o
 obj-y += dom0_ops.o
 obj-y += domain.o
--- /dev/null
+++ work/xen/arch/ia64/xen/crash.c
@@ -0,0 +1,19 @@
+#include <xen/lib.h>       /* for printk() used in stub */
+#include <xen/types.h>
+#include <public/kexec.h>
+
+void machine_crash_shutdown(void)
+{
+    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
@@ -0,0 +1,34 @@
+#include <xen/lib.h>       /* for printk() used in stubs */
+#include <xen/types.h>
+#include <public/kexec.h>
+
+int machine_kexec_load(int type, int slot, xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+    return -1;
+}
+
+void machine_kexec_unload(int type, int slot, 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
@@ -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
@@ -0,0 +1,19 @@
+#include <xen/lib.h>       /* for printk() used in stub */
+#include <xen/types.h>
+#include <public/kexec.h>
+
+void machine_crash_shutdown(void)
+{
+    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
@@ -0,0 +1,34 @@
+#include <xen/lib.h>       /* for printk() used in stubs */
+#include <xen/types.h>
+#include <public/kexec.h>
+
+int machine_kexec_load(int type, int slot, xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+    return -1;
+}
+
+void machine_kexec_unload(int type, int slot, 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
@@ -43,6 +43,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
@@ -0,0 +1,19 @@
+#include <xen/lib.h>       /* for printk() used in stub */
+#include <xen/types.h>
+#include <public/kexec.h>
+
+void machine_crash_shutdown(void)
+{
+    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
@@ -0,0 +1,34 @@
+#include <xen/lib.h>       /* for printk() used in stubs */
+#include <xen/types.h>
+#include <public/kexec.h>
+
+int machine_kexec_load(int type, int slot, xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+    return -1;
+}
+
+void machine_kexec_unload(int type, int slot, 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
@@ -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
@@ -0,0 +1,370 @@
+/******************************************************************************
+ * kexec.c - Achitecture independent kexec code for Xen
+ * 
+ * Xen port written by:
+ * - Simon 'Horms' Horman <horms@xxxxxxxxxxxx>
+ * - Magnus Damm <magnus@xxxxxxxxxxxxx>
+ */
+
+#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>
+#include <xen/cpumask.h>
+#include <asm/atomic.h>
+#include <xen/spinlock.h>
+#include <xen/version.h>
+#include <public/elfnote.h>
+
+static char opt_crashkernel[32] = "";
+string_param("crashkernel", opt_crashkernel);
+
+DEFINE_PER_CPU (crash_note_t, crash_notes);
+cpumask_t crash_saved_cpus;
+int crashing_cpu;
+
+xen_kexec_image_t kexec_image[KEXEC_IMAGE_NR];
+
+#define KEXEC_FLAG_DEFAULT_POS   (KEXEC_IMAGE_NR + 0)
+#define KEXEC_FLAG_CRASH_POS     (KEXEC_IMAGE_NR + 1)
+#define KEXEC_FLAG_IN_PROGRESS   (KEXEC_IMAGE_NR + 2)
+
+unsigned long kexec_flags = 0; /* the lowest bits are for KEXEC_IMAGE... */
+
+spinlock_t kexec_lock = SPIN_LOCK_UNLOCKED;
+
+static void one_cpu_only(void)
+{
+   /* Only allow the first cpu to continue - force other cpus to spin */
+    if (test_and_set_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags))
+    {
+        while (1);
+    }
+}
+
+/* Save the registers in the per-cpu crash note buffer */
+
+void machine_crash_save_cpu(void)
+{
+    int cpu = smp_processor_id();
+    crash_note_t *cntp;
+
+    if (!cpu_test_and_set(cpu, crash_saved_cpus))
+    {
+        cntp = &per_cpu(crash_notes, cpu);
+        elf_core_save_regs(&cntp->core.desc.desc.pr_reg,
+                           &cntp->xen_regs.desc.desc);
+
+        /* setup crash "CORE" note */
+        setup_crash_note(cntp, core, CORE_STR, CORE_STR_LEN, NT_PRSTATUS);
+
+        /* setup crash note "Xen", XEN_ELFNOTE_CRASH_REGS */
+        setup_crash_note(cntp, xen_regs, XEN_STR, XEN_STR_LEN, 
+                         XEN_ELFNOTE_CRASH_REGS);
+    }
+}
+
+/* Setup the single Xen specific info crash note */
+
+crash_xen_info_t *machine_crash_save_info(void)
+{
+    int cpu = smp_processor_id();
+    crash_note_t *cntp;
+    crash_xen_info_t *info;
+
+    BUG_ON(!cpu_test_and_set(cpu, crash_saved_cpus));
+
+    cntp = &per_cpu(crash_notes, cpu);
+
+    /* setup crash note "Xen", XEN_ELFNOTE_CRASH_INFO */
+    setup_crash_note(cntp, xen_info, XEN_STR, XEN_STR_LEN, 
+                     XEN_ELFNOTE_CRASH_INFO);
+
+    info = &cntp->xen_info.desc.desc;
+
+    info->xen_major_version = xen_major_version();
+    info->xen_minor_version = xen_minor_version();
+    info->xen_extra_version = __pa(xen_extra_version());
+    info->xen_changeset = __pa(xen_changeset());
+    info->xen_compiler = __pa(xen_compiler());
+    info->xen_compile_date = __pa(xen_compile_date());
+    info->xen_compile_time = __pa(xen_compile_time());
+    info->tainted = tainted;
+
+    return info;
+}
+
+void machine_crash_kexec(void)
+{
+    int pos;
+    xen_kexec_image_t *image;
+
+    one_cpu_only();
+ 
+    machine_crash_save_cpu();
+    crashing_cpu = smp_processor_id();
+
+    machine_crash_shutdown();
+
+    pos = (test_bit(KEXEC_FLAG_CRASH_POS, &kexec_flags) != 0);
+
+    if (test_bit(KEXEC_IMAGE_CRASH_BASE + pos, &kexec_flags))
+    {
+        image = &kexec_image[KEXEC_IMAGE_CRASH_BASE + pos];
+        machine_kexec(image); /* Does not return */
+    }
+
+    while (1); /* No image available - just spin */
+}
+
+static void do_crashdump_trigger(unsigned char key)
+{
+       printk("triggering crashdump\n");
+       machine_crash_kexec();
+}
+
+static __init int register_crashdump_trigger(void)
+{
+       register_keyhandler('c', do_crashdump_trigger, "trigger a crashdump");
+       return 0;
+}
+__initcall(register_crashdump_trigger);
+
+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 kexec_get_reserve(xen_kexec_range_t *range)
+{
+    xen_kexec_reserve_t reservation;
+    
+    machine_kexec_reserved(&reservation);
+
+    range->start = reservation.start;
+    range->size = reservation.size;
+    return 0;
+}
+
+extern unsigned long _text, _end;
+
+static int kexec_get_xen(xen_kexec_range_t *range, int get_ma)
+{
+    if (get_ma)
+        range->start = virt_to_maddr(&_text);
+    else
+        range->start = (unsigned long) &_text;
+
+    range->size = &_end - &_text;
+    return 0;
+}
+
+static int kexec_get_cpu(xen_kexec_range_t *range)
+{
+    if (range->nr < 0 || range->nr >= num_present_cpus())
+        return -EINVAL;
+
+    range->start = __pa((unsigned long)&per_cpu(crash_notes, range->nr));
+    range->size = sizeof(crash_note_t);
+    return 0;
+}
+
+static int kexec_get_range(XEN_GUEST_HANDLE(void) uarg)
+{
+    xen_kexec_range_t range;
+    int ret = -EINVAL;
+    
+    if (unlikely(copy_from_guest(&range, uarg, 1)))
+        return -EFAULT;
+
+    switch (range.range)
+    {
+    case KEXEC_RANGE_MA_CRASH:
+        ret = kexec_get_reserve(&range);
+        break;
+    case KEXEC_RANGE_MA_XEN:
+        ret = kexec_get_xen(&range, 1);
+        break;
+    case KEXEC_RANGE_VA_XEN:
+        ret = kexec_get_xen(&range, 0);
+        break;
+    case KEXEC_RANGE_MA_CPU:
+        ret = kexec_get_cpu(&range);
+        break;
+    }
+
+    if (ret == 0 && unlikely(copy_to_guest(uarg, &range, 1)))
+        return -EFAULT;
+    
+    return ret;
+}
+
+static int kexec_load_get_bits(int type, int *base, int *bit)
+{
+    switch (type)
+    {
+    case KEXEC_TYPE_DEFAULT:
+        *base = KEXEC_IMAGE_DEFAULT_BASE;
+        *bit = KEXEC_FLAG_DEFAULT_POS;
+        break;
+    case KEXEC_TYPE_CRASH:
+        *base = KEXEC_IMAGE_CRASH_BASE;
+        *bit = KEXEC_FLAG_CRASH_POS;
+        break;
+    default:
+        return -1;
+    }
+    return 0;
+}
+
+static int kexec_load_unload(unsigned long op, XEN_GUEST_HANDLE(void) uarg)
+{
+    xen_kexec_load_t load;
+    xen_kexec_image_t *image;
+    int base, bit, pos;
+    int ret = 0;
+
+    if (unlikely(copy_from_guest(&load, uarg, 1)))
+        return -EFAULT;
+
+    if (kexec_load_get_bits(load.type, &base, &bit))
+        return -EINVAL;
+
+    pos = (test_bit(bit, &kexec_flags) != 0);
+
+    /* Load the user data into an unused image */
+    if (op == KEXEC_CMD_kexec_load)
+    {
+        image = &kexec_image[base + !pos];
+
+        BUG_ON(test_bit((base + !pos), &kexec_flags)); /* must be free */
+
+        memcpy(image, &load.image, sizeof(*image));
+            
+        if (!(ret = machine_kexec_load(load.type, base + !pos, image)))
+        {
+            /* Set image present bit */
+            set_bit((base + !pos), &kexec_flags);
+
+            /* Make new image the active one */
+            change_bit(bit, &kexec_flags);
+        }
+    }
+
+    /* Unload the old image if present and load successful */
+    if (ret == 0 && !test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags))
+    {
+        if (test_and_clear_bit((base + pos), &kexec_flags))
+        {
+            image = &kexec_image[base + pos];
+            machine_kexec_unload(load.type, base + pos, image);
+        }
+    }
+
+    return ret;
+}
+
+static int kexec_exec(XEN_GUEST_HANDLE(void) uarg)
+{
+    xen_kexec_exec_t exec;
+    xen_kexec_image_t *image;
+    int base, bit, pos;
+
+    if (unlikely(copy_from_guest(&exec, uarg, 1)))
+        return -EFAULT;
+
+    if (kexec_load_get_bits(exec.type, &base, &bit))
+        return -EINVAL;
+
+    pos = (test_bit(bit, &kexec_flags) != 0);
+
+    /* Only allow kexec/kdump into loaded images */
+    if (!test_bit(base + pos, &kexec_flags))
+        return -ENOENT;
+
+    switch (exec.type)
+    {
+    case KEXEC_TYPE_DEFAULT:
+        image = &kexec_image[base + pos];
+        one_cpu_only();
+        machine_shutdown(image); /* Does not return */
+        break;
+    case KEXEC_TYPE_CRASH:
+        machine_crash_kexec(); /* Does not return */
+        break;
+    }
+
+    return -EINVAL; /* never reached */
+}
+
+long do_kexec_op(unsigned long op, XEN_GUEST_HANDLE(void) uarg)
+{
+    unsigned long flags;
+    int ret = -EINVAL;
+
+    if ( !IS_PRIV(current->domain) )  
+        return -EPERM;
+
+    switch (op)
+    {
+    case KEXEC_CMD_kexec_get_range:
+        ret = kexec_get_range(uarg);
+        break;
+    case KEXEC_CMD_kexec_load:
+    case KEXEC_CMD_kexec_unload:
+        spin_lock_irqsave(&kexec_lock, flags);
+        if (!test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags))
+        {
+            ret = kexec_load_unload(op, uarg);
+        }
+        spin_unlock_irqrestore(&kexec_lock, flags);
+        break;
+    case KEXEC_CMD_kexec:
+        ret = kexec_exec(uarg);
+        break;
+    }
+
+    return ret;
+}
+
+/*
+ * 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
@@ -237,24 +237,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
@@ -27,6 +27,7 @@
 #include <xen/guest_access.h>
 #include <xen/shutdown.h>
 #include <xen/vga.h>
+#include <xen/kexec.h>
 #include <asm/current.h>
 #include <asm/debugger.h>
 #include <asm/io.h>
@@ -865,6 +866,8 @@ void panic(const char *fmt, ...)
 
     debugger_trap_immediate();
 
+    machine_crash_kexec();
+
     if ( opt_noreboot )
     {
         machine_halt();
--- /dev/null
+++ work/xen/include/asm-ia64/elf.h
@@ -0,0 +1,30 @@
+#ifndef __IA64_ELF_H__
+#define __IA64_ELF_H__
+
+#include <xen/lib.h>       /* for printk() used in stub */
+
+typedef struct {
+    unsigned long dummy;
+} ELF_Gregset;
+
+typedef struct {
+    unsigned long dummy;
+} crash_xen_core_t;
+
+extern inline void elf_core_save_regs(ELF_Gregset *core_regs, 
+                                      crash_xen_core_t *xen_core_regs)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+#endif /* __IA64_ELF_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-ia64/kexec.h
@@ -0,0 +1,25 @@
+#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>
+#include <xen/kexec.h>
+
+static inline void machine_kexec(xen_kexec_image_t *image)
+{
+    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-powerpc/elf.h
@@ -0,0 +1,30 @@
+#ifndef _ASM_ELF_H__
+#define _ASM_ELF_H__
+
+#include <xen/lib.h>       /* for printk() used in stub */
+
+typedef struct {
+    unsigned long dummy;
+} ELF_Gregset;
+
+typedef struct {
+    unsigned long dummy;
+} crash_xen_core_t;
+
+extern inline void elf_core_save_regs(ELF_Gregset *core_regs, 
+                                      crash_xen_core_t *xen_core_regs)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+#endif /* _ASM_ELF_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-powerpc/kexec.h
@@ -0,0 +1,25 @@
+#ifndef _ASM_KEXEC_H__
+#define _ASM_KEXEC_H__
+
+#include <xen/lib.h>       /* for printk() used in stub */
+#include <xen/types.h>
+#include <public/xen.h>
+#include <xen/kexec.h>
+
+static inline void machine_kexec(xen_kexec_image_t *image)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+#endif /* _ASM_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/elf.h
@@ -0,0 +1,30 @@
+#ifndef __X86_ELF_H__
+#define __X86_ELF_H__
+
+#include <xen/lib.h>       /* for printk() used in stub */
+
+typedef struct {
+    unsigned long dummy;
+} ELF_Gregset;
+
+typedef struct {
+    unsigned long dummy;
+} crash_xen_core_t;
+
+extern inline void elf_core_save_regs(ELF_Gregset *core_regs, 
+                                      crash_xen_core_t *xen_core_regs)
+{
+    printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__);
+}
+
+#endif /* __X86_ELF_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
@@ -0,0 +1,24 @@
+#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>
+#include <xen/kexec.h>
+
+static inline void machine_kexec(xen_kexec_image_t *image)
+{
+    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:
+ */
--- 0001/xen/include/public/elfnote.h
+++ work/xen/include/public/elfnote.h
@@ -147,6 +147,25 @@
  */
 #define XEN_ELFNOTE_HV_START_LOW  12
 
+/*
+ * System information exported through crash notes.
+ *
+ * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_INFO 
+ * note in case of a system crash. This note will contain various
+ * information about the system, see xen/include/xen/elfcore.h.
+ */
+#define XEN_ELFNOTE_CRASH_INFO 0x1000001
+
+/*
+ * System registers exported through crash notes.
+ *
+ * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_REGS 
+ * note per cpu in case of a system crash. This note is architecture
+ * specific and will contain registers not saved in the "CORE" note.
+ * See xen/include/xen/elfcore.h for more information.
+ */
+#define XEN_ELFNOTE_CRASH_REGS 0x1000002
+
 #endif /* __XEN_PUBLIC_ELFNOTE_H__ */
 
 /*
--- /dev/null
+++ work/xen/include/public/kexec.h
@@ -0,0 +1,131 @@
+/******************************************************************************
+ * kexec.h - Public portion
+ * 
+ * Xen port written by:
+ * - Simon 'Horms' Horman <horms@xxxxxxxxxxxx>
+ * - Magnus Damm <magnus@xxxxxxxxxxxxx>
+ */
+
+#ifndef _XEN_PUBLIC_KEXEC_H
+#define _XEN_PUBLIC_KEXEC_H
+
+
+/* This file describes the Kexec / Kdump hypercall interface for Xen.
+ *
+ * Kexec under vanilla Linux allows a user to reboot the physical machine 
+ * into a new user-specified kernel. The Xen port extends this idea
+ * to allow rebooting of the machine from dom0. When kexec for dom0
+ * is used to reboot,  both the hypervisor and the domains get replaced
+ * with some other kernel. It is possible to kexec between vanilla
+ * Linux and Xen and back again. Xen to Xen works well too.
+ *
+ * The hypercall interface for kexec can be divided into three main
+ * types of hypercall operations:
+ *
+ * 1) Range information:
+ *    This is used by the dom0 kernel to ask the hypervisor about various 
+ *    address information. This information is needed to allow kexec-tools 
+ *    to fill in the ELF headers for /proc/vmcore properly.
+ *
+ * 2) Load and unload of images:
+ *    There are no big surprises here, the kexec binary from kexec-tools
+ *    runs in userspace in dom0. The tool loads/unloads data into the
+ *    dom0 kernel such as new kernel, initramfs and hypervisor. When
+ *    loaded the dom0 kernel performs a load hypercall operation, and
+ *    before releasing all page references the dom0 kernel calls unload.
+ *
+ * 3) Kexec operation:
+ *    This is used to start a previously loaded kernel.
+ */
+
+#include "xen.h"
+
+/*
+ * Prototype for this hypercall is:
+ *  int kexec_op(int cmd, void *args)
+ * @cmd  == KEXEC_CMD_... 
+ *          KEXEC operation to perform
+ * @args == Operation-specific extra arguments (NULL if none).
+ */
+
+/*
+ * Kexec supports two types of operation:
+ * - kexec into a regular kernel, very similar to a standard reboot
+ *   - KEXEC_TYPE_DEFAULT is used to specify this type
+ * - kexec into a special "crash kernel", aka kexec-on-panic
+ *   - KEXEC_TYPE_CRASH is used to specify this type
+ *   - parts of our system may be broken at kexec-on-panic time
+ *     - the code should be kept as simple and self-contained as possible
+ */
+
+#define KEXEC_TYPE_DEFAULT 0
+#define KEXEC_TYPE_CRASH   1
+
+
+/* The kexec implementation for Xen allows the user to load two
+ * types of kernels, KEXEC_TYPE_DEFAULT and KEXEC_TYPE_CRASH.
+ * All data needed for a kexec reboot is kept in one xen_kexec_image_t
+ * per "instance". The data mainly consists of machine address lists to pages
+ * together with destination addresses. The data in xen_kexec_image_t
+ * is passed to the "code page" which is one page of code that performs
+ * the final relocations before jumping to the new kernel.
+ */
+ 
+typedef struct xen_kexec_image {
+    unsigned long indirection_page;
+    unsigned long start_address;
+} xen_kexec_image_t;
+
+/*
+ * Perform kexec having previously loaded a kexec or kdump kernel
+ * as appropriate.
+ * type == KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH [in]
+ */
+#define KEXEC_CMD_kexec                 0
+typedef struct xen_kexec_exec {
+    int type;
+} xen_kexec_exec_t;
+
+/*
+ * Load/Unload kernel image for kexec or kdump.
+ * type  == KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH [in]
+ * image == relocation information for kexec (ignored for unload) [in]
+ */
+#define KEXEC_CMD_kexec_load            1
+#define KEXEC_CMD_kexec_unload          2
+typedef struct xen_kexec_load {
+    int type;
+    xen_kexec_image_t image;
+} xen_kexec_load_t;
+
+#define KEXEC_RANGE_MA_CRASH 0   /* machine address and size of crash area */
+#define KEXEC_RANGE_MA_XEN   1   /* machine address and size of Xen itself */
+#define KEXEC_RANGE_VA_XEN   2   /* virtual adrress and size of Xen itself */
+#define KEXEC_RANGE_MA_CPU   3   /* machine address and size of a CPU note */
+
+/*
+ * Find the address and size of certain memory areas
+ * range == KEXEC_RANGE_... [in]
+ * nr    == physical CPU number (starting from 0) if KEXEC_RANGE_MA_CPU [in]
+ * size  == number of bytes reserved in window [out]
+ * start == address of the first byte in the window [out]
+ */
+#define KEXEC_CMD_kexec_get_range       3
+typedef struct xen_kexec_range {
+    int range;
+    int nr;
+    unsigned long size;
+    unsigned long start;
+} xen_kexec_range_t;
+
+#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:
+ */
--- 0001/xen/include/xen/elf.h
+++ work/xen/include/xen/elf.h
@@ -452,18 +452,12 @@ unsigned int elf_hash(const unsigned cha
 /*
  * Note Definitions
  */
-typedef struct {
-       Elf32_Word namesz;
-       Elf32_Word descsz;
-       Elf32_Word type;
-} Elf32_Note;
 
 typedef struct {
-       Elf64_Half namesz;
-       Elf64_Half descsz;
-       Elf64_Half type;
-} Elf64_Note;
-
+       u32 namesz;
+       u32 descsz;
+       u32 type;
+} Elf_Note; /* same format for both 32-bit and 64-bit ELF */
 
 #if defined(ELFSIZE)
 #define CONCAT(x,y)    __CONCAT(x,y)
@@ -486,7 +480,6 @@ typedef struct {
 #define Elf_Addr       Elf32_Addr
 #define Elf_Off                Elf32_Off
 #define Elf_Nhdr       Elf32_Nhdr
-#define Elf_Note       Elf32_Note
 
 #define ELF_R_SYM      ELF32_R_SYM
 #define ELF_R_TYPE     ELF32_R_TYPE
@@ -511,7 +504,6 @@ typedef struct {
 #define Elf_Addr       Elf64_Addr
 #define Elf_Off                Elf64_Off
 #define Elf_Nhdr       Elf64_Nhdr
-#define Elf_Note       Elf64_Note
 
 #define ELF_R_SYM      ELF64_R_SYM
 #define ELF_R_TYPE     ELF64_R_TYPE
--- /dev/null
+++ work/xen/include/xen/elfcore.h
@@ -0,0 +1,137 @@
+/******************************************************************************
+ * elfcore.h
+ *
+ * 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 <asm/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;
+
+/*
+ * 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 - from asm header file */
+    int pr_fpvalid;              /* True if math co-processor being used.  */
+} ELF_Prstatus;
+
+/*
+ * The following data structures provide 64-bit ELF notes. In theory it should 
+ * be possible to support both 64-bit and 32-bit ELF files, but to keep it 
+ * simple we only do 64-bit.
+ *
+ * Please note that the current code aligns the 64-bit notes in the same
+ * way as Linux does. We are not following the 64-bit ELF spec, no one does.
+ *
+ * We are avoiding two problems by restricting us to 64-bit notes only:
+ * - Alignment of notes change with the word size. Ick.
+ * - We would need to tell kexec-tools which format we are using in the
+ *   hypervisor to make sure the right ELF format is generated.
+ *   That requires infrastructure. Let's not.
+ */
+
+#define ALIGN(x, n) ((x + ((1 << n) - 1)) / (1 << n))
+#define PAD32(x) u32 pad_data[ALIGN(x, 2)]
+
+#define TYPEDEF_NOTE(type, strlen, desctype)    \
+    typedef struct {                            \
+        union {                                 \
+            struct {                            \
+                Elf_Note note;                  \
+                unsigned char name[strlen];     \
+            } note;                             \
+            PAD32(sizeof(Elf_Note) + strlen);   \
+        } note;                                 \
+        union {                                 \
+            desctype desc;                      \
+            PAD32(sizeof(desctype));            \
+        } desc;                                 \
+    } __attribute__ ((packed)) type
+
+#define CORE_STR                "CORE"
+#define CORE_STR_LEN            5 /* including terminating zero */
+
+TYPEDEF_NOTE(crash_note_core_t, CORE_STR_LEN, ELF_Prstatus);
+
+#define XEN_STR                 "Xen"
+#define XEN_STR_LEN             4 /* including terminating zero */
+
+TYPEDEF_NOTE(crash_note_xen_core_t, XEN_STR_LEN, crash_xen_core_t);
+
+typedef struct {
+    unsigned long xen_major_version;
+    unsigned long xen_minor_version;
+    unsigned long xen_extra_version;
+    unsigned long xen_changeset;
+    unsigned long xen_compiler;
+    unsigned long xen_compile_date;
+    unsigned long xen_compile_time;
+    unsigned long tainted;
+} crash_xen_info_t;
+
+TYPEDEF_NOTE(crash_note_xen_info_t, XEN_STR_LEN, crash_xen_info_t);
+
+typedef struct {
+    crash_note_core_t core;
+    crash_note_xen_core_t xen_regs;
+    crash_note_xen_info_t xen_info;
+} __attribute__ ((packed)) crash_note_t;
+
+#define setup_crash_note(np, member, str, str_len, id) \
+  np->member.note.note.note.namesz = str_len; \
+  np->member.note.note.note.descsz = sizeof(np->member.desc.desc); \
+  np->member.note.note.note.type = id; \
+  memcpy(np->member.note.note.name, str, str_len)
+
+#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
@@ -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
@@ -0,0 +1,43 @@
+#ifndef __XEN_KEXEC_H__
+#define __XEN_KEXEC_H__
+
+#include <public/kexec.h>
+#include <asm/percpu.h>
+#include <xen/elfcore.h>
+
+extern int crashing_cpu;
+
+typedef struct xen_kexec_reserve {
+    unsigned long size;
+    unsigned long start;
+} xen_kexec_reserve_t;
+
+/* We have space for 4 images to support atomic update
+ * of images. This is important for CRASH images since
+ * a panic can happen at any time...
+ */
+
+#define KEXEC_IMAGE_DEFAULT_BASE 0
+#define KEXEC_IMAGE_CRASH_BASE   2
+#define KEXEC_IMAGE_NR           4
+
+int machine_kexec_load(int type, int slot, xen_kexec_image_t *image);
+void machine_kexec_unload(int type, int slot, xen_kexec_image_t *image);
+void machine_kexec_reserved(xen_kexec_reserve_t *reservation);
+void machine_shutdown(xen_kexec_image_t *image);
+void machine_crash_kexec(void);
+void machine_crash_save_cpu(void);
+crash_xen_info_t *machine_crash_save_info(void);
+void machine_crash_shutdown(void);
+
+#endif /* __XEN_KEXEC_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/mm.h
+++ work/xen/include/xen/mm.h
@@ -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