--- include/linux/kexec.h | 22 +++++++++++- kernel/kexec.c | 85 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 89 insertions(+), 18 deletions(-) Index: kexec-2.6.16/include/linux/kexec.h =================================================================== --- kexec-2.6.16.orig/include/linux/kexec.h +++ kexec-2.6.16/include/linux/kexec.h @@ -85,12 +85,30 @@ struct kimage { #define KEXEC_TYPE_CRASH 1 }; - - /* kexec interface functions */ +extern unsigned long (*kexec_page_to_pfn)(struct page *page); +extern struct page* (*kexec_pfn_to_page)(unsigned long pfn); +extern unsigned long (*kexec_virt_to_phys)(void *addr); +extern void* (*kexec_phys_to_virt)(unsigned long addr); + +#ifdef KEXEC_ARCH_USES_HOOKS +extern NORET_TYPE void (*machine_kexec)(struct kimage *image) ATTRIB_NORET; +extern int (*machine_kexec_prepare)(struct kimage *image); +extern int (*machine_kexec_load)(struct kimage *image); +extern void (*machine_kexec_unload)(struct kimage *image); +extern void (*machine_kexec_cleanup)(struct kimage *image); +#else extern NORET_TYPE void machine_kexec(struct kimage *image) ATTRIB_NORET; extern int machine_kexec_prepare(struct kimage *image); +static inline int machine_kexec_load(struct kimage *image) { return 0; } +static inline void machine_kexec_unload(struct kimage *image) { } extern void machine_kexec_cleanup(struct kimage *image); +#endif + +#ifdef CONFIG_XEN +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, Index: kexec-2.6.16/kernel/kexec.c =================================================================== --- kexec-2.6.16.orig/kernel/kexec.c +++ kexec-2.6.16/kernel/kexec.c @@ -27,6 +27,31 @@ #include #include +static unsigned long default_page_to_pfn(struct page *page) +{ + return page_to_pfn(page); +} + +static struct page* default_pfn_to_page(unsigned long pfn) +{ + return pfn_to_page(pfn); +} + +static unsigned long default_virt_to_phys(void *addr) +{ + return virt_to_phys(addr); +} + +static void* default_phys_to_virt(unsigned long addr) +{ + return phys_to_virt(addr); +} + +unsigned long (*kexec_page_to_pfn)(struct page *page) = default_page_to_pfn; +struct page* (*kexec_pfn_to_page)(unsigned long pfn) = default_pfn_to_page; +unsigned long (*kexec_virt_to_phys)(void *addr) = default_virt_to_phys; +void* (*kexec_phys_to_virt)(unsigned long addr) = default_phys_to_virt; + /* Per cpu memory for storing cpu states in case of system crash. */ note_buf_t* crash_notes; @@ -403,7 +428,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 +462,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 +516,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 +543,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 +565,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 +626,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 +644,9 @@ static void kimage_free(struct kimage *i if (!image) return; + if (machine_kexec_unload) + machine_kexec_unload(image); + kimage_free_extra_pages(image); for_each_kimage_entry(image, ptr, entry) { if (entry & IND_INDIRECTION) { @@ -630,7 +666,8 @@ static void kimage_free(struct kimage *i kimage_free_entry(ind); /* Handle any machine specific cleanup */ - machine_kexec_cleanup(image); + if (machine_kexec_cleanup) + machine_kexec_cleanup(image); /* Free the kexec control pages... */ kimage_free_page_list(&image->control_pages); @@ -686,7 +723,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 +738,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 +766,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 +816,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 +848,7 @@ out: return result; } +#ifndef CONFIG_XEN static int kimage_load_crash_segment(struct kimage *image, struct kexec_segment *segment) { @@ -833,7 +871,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 +919,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. @@ -978,9 +1023,11 @@ asmlinkage long sys_kexec_load(unsigned if (result) goto out; - result = machine_kexec_prepare(image); - if (result) - goto out; + if (machine_kexec_prepare) { + result = machine_kexec_prepare(image); + if (result) + goto out; + } for (i = 0; i < nr_segments; i++) { result = kimage_load_segment(image, &image->segment[i]); @@ -991,6 +1038,13 @@ asmlinkage long sys_kexec_load(unsigned if (result) goto out; } + + if (machine_kexec_load) { + result = machine_kexec_load(image); + if (result) + goto out; + } + /* Install the new kernel, and Uninstall the old */ image = xchg(dest_image, image); @@ -1045,7 +1099,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.