[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [XEN] Kexec / Kdump: Generic code
# HG changeset patch # User Ian Campbell <ian.campbell@xxxxxxxxxxxxx> # Node ID c988f781817daa646828262eb8ff02f60a3a4f2e # Parent d1b0a5adaeabffa3a1a68ae08bc974f5fb28d2c7 [XEN] 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> --- 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 | 167 ++++++++ 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 | 37 + 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 | 20 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, 1409 insertions(+), 27 deletions(-) diff -r d1b0a5adaeab -r c988f781817d linux-2.6-xen-sparse/drivers/xen/core/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/core/Makefile Wed Nov 29 23:40:40 2006 +0000 +++ b/linux-2.6-xen-sparse/drivers/xen/core/Makefile Thu Nov 30 12:38:50 2006 +0000 @@ -11,3 +11,4 @@ obj-$(CONFIG_XEN_SKBUFF) += skbuff.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 diff -r d1b0a5adaeab -r c988f781817d patches/linux-2.6.16.33/series --- a/patches/linux-2.6.16.33/series Wed Nov 29 23:40:40 2006 +0000 +++ b/patches/linux-2.6.16.33/series Thu Nov 30 12:38:50 2006 +0000 @@ -1,3 +1,4 @@ blktap-aio-16_03_06.patch +kexec-generic.patch blktap-aio-16_03_06.patch device_bind.patch fix-hz-suspend.patch diff -r d1b0a5adaeab -r c988f781817d xen/arch/ia64/xen/Makefile --- a/xen/arch/ia64/xen/Makefile Wed Nov 29 23:40:40 2006 +0000 +++ b/xen/arch/ia64/xen/Makefile Thu Nov 30 12:38:50 2006 +0000 @@ -1,3 +1,5 @@ obj-y += acpi.o +obj-y += machine_kexec.o +obj-y += crash.o obj-y += acpi.o obj-y += dom0_ops.o obj-y += domain.o diff -r d1b0a5adaeab -r c988f781817d xen/arch/powerpc/Makefile --- a/xen/arch/powerpc/Makefile Wed Nov 29 23:40:40 2006 +0000 +++ b/xen/arch/powerpc/Makefile Thu Nov 30 12:38:50 2006 +0000 @@ -40,6 +40,8 @@ obj-y += sysctl.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 diff -r d1b0a5adaeab -r c988f781817d xen/arch/x86/Makefile --- a/xen/arch/x86/Makefile Wed Nov 29 23:40:40 2006 +0000 +++ b/xen/arch/x86/Makefile Thu Nov 30 12:38:50 2006 +0000 @@ -43,6 +43,8 @@ obj-y += traps.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 diff -r d1b0a5adaeab -r c988f781817d xen/common/Makefile --- a/xen/common/Makefile Wed Nov 29 23:40:40 2006 +0000 +++ b/xen/common/Makefile Thu Nov 30 12:38:50 2006 +0000 @@ -7,6 +7,7 @@ obj-y += grant_table.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 diff -r d1b0a5adaeab -r c988f781817d xen/common/page_alloc.c --- a/xen/common/page_alloc.c Wed Nov 29 23:40:40 2006 +0000 +++ b/xen/common/page_alloc.c Thu Nov 30 12:38:50 2006 +0000 @@ -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; - } - } - - return 0; + i = alloc_boot_pages_at(nr_pfns, pg); + if (i != 0) + break; + } + + return i; } diff -r d1b0a5adaeab -r c988f781817d xen/drivers/char/console.c --- a/xen/drivers/char/console.c Wed Nov 29 23:40:40 2006 +0000 +++ b/xen/drivers/char/console.c Thu Nov 30 12:38:50 2006 +0000 @@ -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(); diff -r d1b0a5adaeab -r c988f781817d xen/include/public/elfnote.h --- a/xen/include/public/elfnote.h Wed Nov 29 23:40:40 2006 +0000 +++ b/xen/include/public/elfnote.h Thu Nov 30 12:38:50 2006 +0000 @@ -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__ */ /* diff -r d1b0a5adaeab -r c988f781817d xen/include/xen/elf.h --- a/xen/include/xen/elf.h Wed Nov 29 23:40:40 2006 +0000 +++ b/xen/include/xen/elf.h Thu Nov 30 12:38:50 2006 +0000 @@ -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; - + +typedef struct { + 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 diff -r d1b0a5adaeab -r c988f781817d xen/include/xen/hypercall.h --- a/xen/include/xen/hypercall.h Wed Nov 29 23:40:40 2006 +0000 +++ b/xen/include/xen/hypercall.h Thu Nov 30 12:38:50 2006 +0000 @@ -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__ */ diff -r d1b0a5adaeab -r c988f781817d xen/include/xen/mm.h --- a/xen/include/xen/mm.h Wed Nov 29 23:40:40 2006 +0000 +++ b/xen/include/xen/mm.h Thu Nov 30 12:38:50 2006 +0000 @@ -40,6 +40,7 @@ paddr_t init_boot_allocator(paddr_t bitm 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. */ diff -r d1b0a5adaeab -r c988f781817d linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ diff -r d1b0a5adaeab -r c988f781817d patches/linux-2.6.16.33/kexec-generic.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/patches/linux-2.6.16.33/kexec-generic.patch Thu Nov 30 12:38:50 2006 +0000 @@ -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); + diff -r d1b0a5adaeab -r c988f781817d xen/arch/ia64/xen/crash.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/ia64/xen/crash.c Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ + diff -r d1b0a5adaeab -r c988f781817d xen/arch/ia64/xen/machine_kexec.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/ia64/xen/machine_kexec.c Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ diff -r d1b0a5adaeab -r c988f781817d xen/arch/powerpc/crash.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/powerpc/crash.c Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ + diff -r d1b0a5adaeab -r c988f781817d xen/arch/powerpc/machine_kexec.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/powerpc/machine_kexec.c Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ diff -r d1b0a5adaeab -r c988f781817d xen/arch/x86/crash.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/crash.c Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ + diff -r d1b0a5adaeab -r c988f781817d xen/arch/x86/machine_kexec.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/machine_kexec.c Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ diff -r d1b0a5adaeab -r c988f781817d xen/common/kexec.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/common/kexec.c Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ diff -r d1b0a5adaeab -r c988f781817d xen/include/asm-ia64/elf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-ia64/elf.h Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ diff -r d1b0a5adaeab -r c988f781817d xen/include/asm-ia64/kexec.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-ia64/kexec.h Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ + diff -r d1b0a5adaeab -r c988f781817d xen/include/asm-powerpc/elf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-powerpc/elf.h Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ diff -r d1b0a5adaeab -r c988f781817d xen/include/asm-powerpc/kexec.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-powerpc/kexec.h Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ + diff -r d1b0a5adaeab -r c988f781817d xen/include/asm-x86/elf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-x86/elf.h Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ diff -r d1b0a5adaeab -r c988f781817d xen/include/asm-x86/kexec.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-x86/kexec.h Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ diff -r d1b0a5adaeab -r c988f781817d xen/include/public/kexec.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/public/kexec.h Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ diff -r d1b0a5adaeab -r c988f781817d xen/include/xen/elfcore.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/xen/elfcore.h Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ diff -r d1b0a5adaeab -r c988f781817d xen/include/xen/kexec.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/xen/kexec.h Thu Nov 30 12:38:50 2006 +0000 @@ -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: + */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |