[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-11856. linux-2.6-xen-sparse/drivers/xen/core/Makefile | 1 linux-2.6-xen-sparse/drivers/xen/core/crash.c | 44 ++ linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c | 80 ++++ linux-2.6-xen-sparse/drivers/xen/core/reboot.c | 4 patches/linux-2.6.16.29/kexec-generic.patch | 281 ++++++++++++++++ patches/linux-2.6.16.29/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 | 288 +++++++++++++++++ xen/common/page_alloc.c | 33 + xen/drivers/char/console.c | 3 xen/include/asm-ia64/elf.h | 23 + xen/include/asm-ia64/kexec.h | 31 + xen/include/asm-powerpc/elf.h | 23 + xen/include/asm-powerpc/kexec.h | 31 + xen/include/asm-x86/elf.h | 23 + xen/include/asm-x86/kexec.h | 30 + xen/include/public/kexec.h | 88 +++++ xen/include/xen/elfcore.h | 71 ++++ xen/include/xen/hypercall.h | 6 xen/include/xen/kexec.h | 37 ++ xen/include/xen/mm.h | 1 30 files changed, 1254 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-23 11:36:13.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-23 11:36:14.000000000 +0900 @@ -0,0 +1,44 @@ +#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) +{ + xen_kexec_exec_t xke; + + printk("machine_crash_shutdown: %d\n", smp_processor_id()); + + local_irq_disable(); + memset(&xke, 0, sizeof(xke)); + xke.type = KEXEC_TYPE_CRASH; + crash_translate_regs(regs, &xke.regs); + + HYPERVISOR_kexec_op(KEXEC_CMD_kexec, &xke); + 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: + */ --- /dev/null +++ work/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c 2006-10-23 11:36:14.000000000 +0900 @@ -0,0 +1,80 @@ +/* + * 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 <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) +{ + 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"); +} + +/* + * 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-23 11:36:13.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-23 11:36:14.000000000 +0900 @@ -0,0 +1,281 @@ +--- 0002/drivers/base/cpu.c ++++ work/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,22 @@ static inline void register_cpu_control( + #ifdef CONFIG_KEXEC + #include <linux/kexec.h> + ++#ifdef CONFIG_XEN ++static unsigned long get_crash_notes(int cpu) ++{ ++ xen_kexec_note_t note; ++ ++ memset(¬e, 0, sizeof(note)); ++ note.vcpu = cpu; ++ ++ if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_crash_note, ¬e) < 0) ++ return 0UL; ++ ++ return note.address; ++} ++#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 +121,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; + } +--- 0001/include/linux/kexec.h ++++ work/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, +--- 0001/kernel/kexec.c ++++ work/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 +--- 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.29/series +++ work/patches/linux-2.6.16.29/series 2006-10-23 11:36:13.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-23 11:36:13.000000000 +0900 @@ -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 2006-10-23 11:36:14.000000000 +0900 @@ -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(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-23 11:36:14.000000000 +0900 @@ -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 2006-10-23 11:36:13.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-23 11:36:14.000000000 +0900 @@ -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(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-23 11:36:14.000000000 +0900 @@ -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 2006-10-23 11:36:13.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-23 11:36:14.000000000 +0900 @@ -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(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-23 11:36:14.000000000 +0900 @@ -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 2006-10-23 11:36:13.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-23 11:36:14.000000000 +0900 @@ -0,0 +1,288 @@ +/****************************************************************************** + * 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 <asm/atomic.h> +#include <xen/spinlock.h> + +static char opt_crashkernel[32] = ""; +string_param("crashkernel", opt_crashkernel); + +DEFINE_PER_CPU (note_buf_t, crash_notes); + +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); + } +} + +void crash_kexec(struct cpu_user_regs *regs) +{ + int pos; + xen_kexec_image_t *image; + struct cpu_user_regs fixed_regs; + + one_cpu_only(); + + crash_setup_regs(&fixed_regs, regs); + machine_crash_shutdown(&fixed_regs); + + 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"); + 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 kexec_get_crash_note(XEN_GUEST_HANDLE(void) uarg) +{ + xen_kexec_note_t note; + struct domain *domain = current->domain; + struct vcpu *vcpu; + + if (unlikely(copy_from_guest(¬e, uarg, 1))) + return -EFAULT; + + if (note.vcpu < 0 || note.vcpu >= MAX_VIRT_CPUS) + return -EINVAL; + + if (!(vcpu = domain->vcpu[note.vcpu])) + return -EINVAL; + + note.address = __pa((unsigned long)per_cpu(crash_notes, vcpu->processor)); + + if (unlikely(copy_to_guest(uarg, ¬e, 1))) + 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 kexec_get_reserve(XEN_GUEST_HANDLE(void) uarg) +{ + xen_kexec_reserve_t reservation; + + machine_kexec_reserved(&reservation); + + if (unlikely(copy_to_guest(uarg, &reservation, 1))) + return -EFAULT; + + return 0; +} + +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: + crash_kexec(&exec.regs); /* 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_crash_note: + spin_lock_irqsave(&kexec_lock, flags); + ret = kexec_get_crash_note(uarg); + spin_unlock_irqrestore(&kexec_lock, flags); + break; + case KEXEC_CMD_kexec_reserve: + ret = kexec_get_reserve(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 2006-10-23 11:36:13.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-23 11:36:13.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/elf.h 2006-10-23 11:36:14.000000000 +0900 @@ -0,0 +1,23 @@ +#ifndef __IA64_ELF_H__ +#define __IA64_ELF_H__ + +#include <xen/lib.h> /* for printk() used in stub */ + +#define ELF_NGREG 1 /* XXX: Define to be at least as large as + however many register slots are needed when + crash notes are written during crash dump */ + +#define ELF_CORE_COPY_REGS(pr_reg, 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 2006-10-23 11:36:14.000000000 +0900 @@ -0,0 +1,31 @@ +#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 void crash_setup_regs(struct cpu_user_regs *newregs, + struct cpu_user_regs *oldregs) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +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 2006-10-23 11:36:14.000000000 +0900 @@ -0,0 +1,23 @@ +#ifndef _ASM_ELF_H__ +#define _ASM_ELF_H__ + +#include <xen/lib.h> /* for printk() used in stub */ + +#define ELF_NGREG 1 /* XXX: Define to be at least as large as + however many register slots are needed when + crash notes are written during crash dump */ + +#define ELF_CORE_COPY_REGS(pr_reg, 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 2006-10-23 11:36:14.000000000 +0900 @@ -0,0 +1,31 @@ +#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 void crash_setup_regs(struct cpu_user_regs *newregs, + struct cpu_user_regs *oldregs) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +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 2006-10-23 11:36:14.000000000 +0900 @@ -0,0 +1,23 @@ +#ifndef __X86_ELF_H__ +#define __X86_ELF_H__ + +#include <xen/lib.h> /* for printk() used in stub */ + +#define ELF_NGREG 1 /* XXX: Define to be at least as large as + however many register slots are needed when + crash notes are written during crash dump */ + +#define ELF_CORE_COPY_REGS(pr_reg, 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 2006-10-23 11:36:14.000000000 +0900 @@ -0,0 +1,30 @@ +#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 void crash_setup_regs(struct cpu_user_regs *newregs, + struct cpu_user_regs *oldregs) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +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: + */ --- /dev/null +++ work/xen/include/public/kexec.h 2006-10-23 11:36:14.000000000 +0900 @@ -0,0 +1,88 @@ +/****************************************************************************** + * 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 + +#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). + */ + +#define KEXEC_TYPE_DEFAULT 0 +#define KEXEC_TYPE_CRASH 1 + +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] + * regs == pointer to cpu_user_regs_t structure (ignored for default) [in] + */ +#define KEXEC_CMD_kexec 0 +typedef struct xen_kexec_exec { + int type; + cpu_user_regs_t regs; +} 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; + +/* + * Find the base pointer and size of the area that xen has + * reserved for use by the crash kernel. + * size == number of bytes reserved in window [out] + * start == machine address of the first byte in the window [out] + */ +#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 + * vcpu == VCPU number to look up [in] + * address == VCPU crash note machine address [out] + */ +#define KEXEC_CMD_kexec_crash_note 4 +typedef struct xen_kexec_note { + int vcpu; + unsigned long address; +} xen_kexec_note_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: + */ --- /dev/null +++ work/xen/include/xen/elfcore.h 2006-10-23 11:36:14.000000000 +0900 @@ -0,0 +1,71 @@ +/****************************************************************************** + * 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; +typedef unsigned long 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-23 11:36:13.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-23 11:36:14.000000000 +0900 @@ -0,0 +1,37 @@ +#ifndef __XEN_KEXEC_H__ +#define __XEN_KEXEC_H__ + +#include <public/kexec.h> +#include <asm/percpu.h> + +#define MAX_NOTE_BYTES 1024 + +typedef u32 note_buf_t[MAX_NOTE_BYTES/4]; +DECLARE_PER_CPU (note_buf_t, crash_notes); + +/* 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_shutdown(cpu_user_regs_t *regs); + +#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 2006-10-23 11:36:13.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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |