From: Horms Subject: Re: [PATCH] kexec: framework and i386 (Take XI) Date: Thu, 15 Jun 2006 16:29:30 +0900 Message-ID: <20060615072919.GA19174@verge.net.au> References: <3c347db5fc144e0809c47b5efe8f6582@cl.cam.ac.uk> <12c36e8e9c573c900cd75f27b3d650d3@cl.cam.ac.uk> <20060517024402.GA13874@verge.net.au> <20060517045322.GA24072@verge.net.au> <20060517095213.GA31686@verge.net.au> <805b0fdb70b2ca542d6f9f43c0936928@cl.cam.ac.uk> <20060518033753.GB13670@verge.net.au> <20060525072017.GA25881@verge.net.au> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="jI8keyz6grp/JLjh" Return-path: Content-Disposition: inline In-Reply-To: <20060525072017.GA25881@verge.net.au> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xensource.com Errors-To: xen-devel-bounces@lists.xensource.com To: Keir Fraser Cc: Ian Pratt , Kazuo Moriwaka , xen-devel@lists.xensource.com, Akio Takebe , Isaku Yamahata , Magnus Damm , Mark Williamson List-Id: xen-devel@lists.xenproject.org --jI8keyz6grp/JLjh Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Thu, May 25, 2006 at 04:20:19PM +0900, Horms wrote: > Hi, > > sorry for the somewhat long delay between sending updates. > I'm happy to announce tenth take of the kexec/kdump patch. > I'll address Keir's questions from the 9th release below, > but first I would like to quickly summarise the patches. > > Kexec/kdump is implemented by moving the privelaged portions > (and related plumbing where needed) from linux into the hypervisor. > This is primarily done by implementing kexec's architecture > independent hooks as hypercalls. > > Both Kexec is working for x86_32 and x86_64 for SMP and UP. > Kdump is also working for SMP and UP on x86_32. x86_64 may work, > but still needs more attention. In particular the register > saving code has not been implemented. > > These patches also include some reworking of kexec's internals in > order that the page table is not mangled on kdump. These changes > also make x86_64 kexec/kdump somewhat easier to implement. > Collectively this is the pagetable_a approach developed by my colleague > Magnus Damm, and he is working with the linux kexec maintainers to > get it merged there. > > The code is broken out into four patches. > They should apply cleanly to xen-unstable.hg 10151. > > 1. 51.1-kexec-generic-upstream.patch > * Common code for all architectures, > > the basic plumbing for kexec/kdump > 2. 51.2.1-kexec-x86-upstream.patch > * Glue between 1, and 3 and 4. > This would not be needed for ppc or ia64, but > neither have been written yet. > We are planning to commence work on ia64 soon. > * Depends on 1 > > 3. 51.2.1.1-kexec-x86_32-upstream.patch > * Kexec/kdump for x86_32 > * Depends on 2 (and 1) > > 4. 51.2.31.2-kexec-x86_64-upstream.patch > * * Kexec/kdump for x86_64 > * Depends on 2 (and 1) Hi, here is a modest update to the kexec patches, broken out as per the description above. The changes are: * Kconfig: don't allow kexec to be build for a non-privelaged domain as this makes no sense at this time. * fix a gcc compilation error that became apparent in gcc (GCC) 4.1.2 20060604 (prerelease) (Debian 4.1.1-2). There is a warning produced that causes the build to fail because of the use of -Werror when compiling the hypervisor. The warning relates to kexec's use of xchg as a simple locking mechanism and not always using the return value as it isn't of any value. * Record dom0's cr3 in vmcore for analysis by crash https://www.redhat.com/archives/crash-utility/2006-June/msg00015.html * Upport from xen-unstable.hg 10151 to 10352, which is the current tree at present. This involved fixing two minor diffing issues, nothing more. -- Horms http://www.vergenet.net/~horms/ --jI8keyz6grp/JLjh Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="51.1-kexec-generic-upstream.patch" kexec: framework This is an implementation of kexec for dom0/xen, that allows kexecing of the physical machine from xen. The approach taken is to move the architecture-dependant kexec code into a new hypercall. This patch only includes the framework, it cann't be used without architecture dependant hooks, however the code should compile as is. Signed-Off-By: Horms Signed-Off-By: Magnus Damm linux-2.6-xen-sparse/drivers/xen/core/Makefile | 1 linux-2.6-xen-sparse/drivers/xen/core/crash.c | 48 + linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c | 84 ++ linux-2.6-xen-sparse/drivers/xen/core/reboot.c | 4 patches/linux-2.6.16.13/0-linux-2.6.16-kexec_page_table_a_stubs.patch | 85 ++ patches/linux-2.6.16.13/kexec-generic.patch | 294 ++++++++++ xen/arch/x86/Makefile | 2 xen/arch/x86/crash.c | 26 xen/arch/x86/machine_kexec.c | 51 + xen/common/Makefile | 1 xen/common/kexec.c | 211 +++++++ xen/common/page_alloc.c | 33 - xen/drivers/char/console.c | 3 xen/include/asm-x86/kexec.h | 32 + xen/include/public/kexec.h | 85 ++ xen/include/public/xen.h | 1 xen/include/xen/elfcore.h | 73 ++ xen/include/xen/kexec.h | 33 + xen/include/xen/mm.h | 1 19 files changed, 1057 insertions(+), 11 deletions(-) --- x/linux-2.6-xen-sparse/drivers/xen/core/Makefile +++ x/linux-2.6-xen-sparse/drivers/xen/core/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_IA64) += xenia64_init.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 +++ x/linux-2.6-xen-sparse/drivers/xen/core/crash.c @@ -0,0 +1,48 @@ +/* + * Architecture independent functions for kexec based crash dumps in xen. + * + * Created by: Horms + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This passes the registers's down to the hypervisor and has it kexec() + * This is a bit different to the linux implementation which + * has this call save registers and stop CPUs and then goes into + * machine_kexec() later. But for Xen it makes more sense to + * have the kexec hypercall do everything, and this call + * has the registers parameter that is needed. + * to the hypervisor to allow the hypervisor to kdump itself + * on an internal panic + */ +void machine_crash_shutdown(struct pt_regs *regs) +{ + struct cpu_user_regs xen_regs; + printk("machine_crash_shutdown: %d\n", smp_processor_id()); + local_irq_disable(); +#ifdef CONFIG_X86_IO_APIC + disable_IO_APIC(); +#endif + crash_translate_regs(regs, &xen_regs); + HYPERVISOR_kexec(KEXEC_CMD_kexec, KEXEC_TYPE_CRASH, &xen_regs); +} + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ --- /dev/null +++ x/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c @@ -0,0 +1,84 @@ +/* + * drivers/xen/core/machine_kexec.c + * handle transition of Linux booting another kernel + * + * Created By: Horms + * + * Losely based on arch/i386/kernel/machine_kexec.c + */ + +#include +#include +#include +#include +#include + +const extern unsigned char relocate_new_kernel[]; +extern unsigned int relocate_new_kernel_size; + +static inline unsigned long machine_address(struct page *page) +{ + return pfn_to_mfn(page_to_pfn(page)) << PAGE_SHIFT; +} + +static void setup_hypercall_arg(xen_kexec_image_t *xki, struct kimage *image) +{ + memset(xki, 0, sizeof(*xki)); + + xki->indirection_page = image->head; + xki->reboot_code_buffer = + machine_address(image->control_code_page); + xki->start_address = image->start; +} + +/* + * Load the image into xen so xen can kdump itself + * This might have been done in prepare, but prepare + * is currently called too early. It might make sense + * to move prepare, but for now, just add an extra hook. + */ +int xen_machine_kexec_load(struct kimage *image) +{ + xen_kexec_image_t xki; + + setup_hypercall_arg(&xki, image); + return HYPERVISOR_kexec(KEXEC_CMD_kexec_load, image->type, &xki); +} + +/* + * Unload the image that was stored by machine_kexec_load() + * This might have been done in machine_kexec_cleanup() but it + * is called too late, and its possible xen could try and kdump + * using resources that have been freed. + */ +void xen_machine_kexec_unload(struct kimage *image) +{ + xen_kexec_image_t xki; + + setup_hypercall_arg(&xki, image); + HYPERVISOR_kexec(KEXEC_CMD_kexec_unload, image->type, &xki); +} + +/* + * Do not allocate memory (or fail in any way) in machine_kexec(). + * We are past the point of no return, committed to rebooting now. + * + * This has the hypervisor move to the prefered reboot CPU, + * stop all CPUs and kexec. That is it combines machine_shutdown() + * and machine_kexec() in Linux kexec terms. + */ +NORET_TYPE void xen_machine_kexec(struct kimage *image) +{ + HYPERVISOR_kexec(KEXEC_CMD_kexec, image->type, NULL); + panic("KEXEC_CMD_kexec hypercall should not return\n"); +} + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ --- x/linux-2.6-xen-sparse/drivers/xen/core/reboot.c +++ x/linux-2.6-xen-sparse/drivers/xen/core/reboot.c @@ -67,6 +67,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); --- x/xen/arch/x86/Makefile +++ x/xen/arch/x86/Makefile @@ -39,6 +39,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 ifneq ($(pae),n) obj-$(x86_32) += shadow.o shadow_public.o shadow_guest32.o --- /dev/null +++ x/xen/arch/x86/crash.c @@ -0,0 +1,26 @@ +/****************************************************************************** + * arch/x86/crash.c + * + * Created By: Horms + * + * Should be based heavily on arch/i386/kernel/crash.c from Linux 2.6.16 + */ + +#include /* for printk() used in stub */ +#include +#include + +void machine_crash_shutdown(struct cpu_user_regs *regs) +{ + printk("STUB: arch/x86/crash.c: machine_crash_shutdown: not implemented\n"); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --- /dev/null +++ x/xen/arch/x86/machine_kexec.c @@ -0,0 +1,51 @@ +/****************************************************************************** + * arch/x86/machine_kexec.c + * + * Created By: Horms + * + */ + +#include /* for printk() used in stubs */ +#include +#include + +int machine_kexec_load(int type, xen_kexec_image_t *image) +{ + printk("STUB: arch/x86/machine_kexec.c: machine_kexec_load: " + "not implemented\n"); + return -1; +} + +void machine_kexec_unload(int type, xen_kexec_image_t *image) +{ + printk("STUB: arch/x86/machine_kexec.c: machine_kexec_unload: " + "not implemented\n"); +} + +void machine_kexec_reserved(xen_kexec_reserve_t *reservation) +{ + printk("STUB: arch/x86/machine_kexec.c: machine_kexec_reserved: " + "not implemented\n"); +} + +void machine_kexec(xen_kexec_image_t *image) +{ + printk("STUB: arch/x86/machine_kexec.c: machine_kexec: " + "not implemented\n"); +} + +void machine_shutdown(xen_kexec_image_t *image) +{ + printk("STUB: arch/x86/machine_shutdown.c: machine_shutdown: " + "not implemented\n"); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --- x/xen/common/Makefile +++ x/xen/common/Makefile @@ -7,6 +7,7 @@ obj-y += event_channel.o obj-y += grant_table.o obj-y += kernel.o obj-y += keyhandler.o +obj-y += kexec.o obj-y += lib.o obj-y += memory.o obj-y += multicall.o --- /dev/null +++ x/xen/common/kexec.c @@ -0,0 +1,211 @@ +/* + * common/kexec.c - Achitecture independent kexec code for Xen + * + * Created By: Horms + * + * Based in part on Linux 2.6.16's kernel/kexec.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +DEFINE_PER_CPU (note_buf_t, crash_notes); + +static xen_kexec_image_t kexec_image; +static int kexec_image_set = 0; +static xen_kexec_image_t kexec_crash_image; +static int kexec_crash_image_set = 0; +static int kexec_crash_lock = 0; + +/* Must call with kexec_crash_lock held */ +void __crash_kexec(struct cpu_user_regs *regs) +{ + struct cpu_user_regs fixed_regs; + + if (!kexec_crash_image_set) + return; + crash_setup_regs(&fixed_regs, regs); + machine_crash_shutdown(&fixed_regs); + machine_kexec(&kexec_crash_image); /* Does not return */ +} + +void crash_kexec(struct cpu_user_regs *regs) +{ + int locked; + + locked = xchg(&kexec_crash_lock, 1); + if (locked) + return; + __crash_kexec(regs); + + /* The if() here is bogus, but gcc will throws a warning that the + * computed value is unused and xen compiles with -Werror. + * This seems like a viable work around. + * This did not seem to happen with slightly older gcc. + * Observed with: + * gcc version 4.1.2 20060604 (prerelease) (Debian * 4.1.1-2) */ + if (xchg(&kexec_crash_lock, 0)) ; + + return; +} + +static int get_crash_note(int vcpuid, XEN_GUEST_HANDLE(void) uarg) +{ + struct domain *domain = current->domain; + unsigned long crash_note; + struct vcpu *vcpu; + int locked; + + if (vcpuid < 0 || vcpuid > MAX_VIRT_CPUS) + return -EINVAL; + + if ( ! (vcpu = domain->vcpu[vcpuid]) ) + return -EINVAL; + + locked = xchg(&kexec_crash_lock, 1); + if (locked) + { + printk("do_kexec: (CMD_kexec_crash_note): dump is locked\n"); + return -EFAULT; + } + crash_note = __pa((unsigned long)per_cpu(crash_notes, vcpu->processor)); + + /* The if() here is bogus, but gcc will throws a warning that the + * computed value is unused and xen compiles with -Werror. + * This seems like a viable work around. + * This did not seem to happen with slightly older gcc. + * Observed with: + * gcc version 4.1.2 20060604 (prerelease) (Debian * 4.1.1-2) */ + if (xchg(&kexec_crash_lock, 0)) ; + + if ( unlikely(copy_to_guest(uarg, &crash_note, 1) != 0) ) + { + printk("do_kexec: (CMD_kexec_crash_note): copy_to_guest failed\n"); + return -EFAULT; + } + + return 0; +} + +static int get_reserve(XEN_GUEST_HANDLE(void) uarg) +{ + xen_kexec_reserve_t reservation; + + machine_kexec_reserved(&reservation); + if ( unlikely(copy_to_guest(uarg, &reservation, 1) != 0) ) + { + printk("do_kexec (CMD_kexec_reserve): copy_to_guest failed\n"); + return -EFAULT; + } + + return 0; +} + +static int __do_kexec(unsigned long type, XEN_GUEST_HANDLE(void) uarg, + xen_kexec_image_t *image) +{ + cpu_user_regs_t regs; + + if (type == KEXEC_TYPE_DEFAULT) + machine_shutdown(image); /* Does not return */ + else + { + if ( unlikely(copy_from_guest(®s, uarg, 1) != 0) ) + { + printk("do_kexec (CMD_kexec): copy_from_guest failed\n"); + return -EFAULT; + } + __crash_kexec(®s); /* Does not return */ + } + + return -EINVAL; +} + +int do_kexec(unsigned long op, int arg1, XEN_GUEST_HANDLE(void) uarg) +{ + xen_kexec_image_t *image; + int locked; + int *image_set; + int status = -EINVAL; + + if ( !IS_PRIV(current->domain) ) + return -EPERM; + + switch (op) + { + case KEXEC_CMD_kexec_crash_note: + return get_crash_note(arg1, uarg); + case KEXEC_CMD_kexec_reserve: + return get_reserve(uarg); + } + + /* For all other ops, arg1 is the type of kexec, that is + * KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH */ + if (arg1 == KEXEC_TYPE_CRASH) + { + image = &kexec_crash_image; + image_set = &kexec_crash_image_set; + locked = xchg(&kexec_crash_lock, 1); + if (locked) + { + printk("do_kexec: dump is locked\n"); + return -EFAULT; + } + } + else + { + image = &kexec_image; + image_set = &kexec_image_set; + } + + switch(op) { + case KEXEC_CMD_kexec: + BUG_ON(!*image_set); + status = __do_kexec(arg1, uarg, image); + break; + case KEXEC_CMD_kexec_load: + BUG_ON(*image_set); + if ( unlikely(copy_from_guest(image, uarg, 1) != 0) ) + { + printk("do_kexec (CMD_kexec_load): copy_from_guest failed\n"); + status = -EFAULT; + break; + } + *image_set = 1; + status = machine_kexec_load(arg1, image); + break; + case KEXEC_CMD_kexec_unload: + BUG_ON(!*image_set); + *image_set = 0; + machine_kexec_unload(arg1, image); + status = 0; + break; + } + + if (arg1 == KEXEC_TYPE_CRASH) + /* The if() here is bogus, but gcc will throws a warning that the + * computed value is unused and xen compiles with -Werror. + * This seems like a viable work around. + * This did not seem to happen with slightly older gcc. + * Observed with: + * gcc version 4.1.2 20060604 (prerelease) (Debian * 4.1.1-2) */ + if (xchg(&kexec_crash_lock, 0)) ; + + return status; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --- x/xen/common/page_alloc.c +++ x/xen/common/page_alloc.c @@ -212,24 +212,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; } --- x/xen/drivers/char/console.c +++ x/xen/drivers/char/console.c @@ -680,6 +680,7 @@ void panic(const char *fmt, ...) unsigned long flags; static DEFINE_SPINLOCK(lock); extern void machine_restart(char *); + extern void crash_kexec(struct cpu_user_regs *regs); debugtrace_dump(); @@ -699,6 +700,8 @@ void panic(const char *fmt, ...) debugger_trap_immediate(); + crash_kexec(NULL); + watchdog_disable(); mdelay(5000); machine_restart(0); --- /dev/null +++ x/xen/include/asm-x86/kexec.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * include/asm-x86/kexec.h + * + * Created By: Horms + * + */ + +#ifndef __X86_KEXEC_H__ +#define __X86_KEXEC_H__ + +#include /* for printk() used in stub */ +#include +#include + +static void crash_setup_regs(struct cpu_user_regs *newregs, + struct cpu_user_regs *oldregs) +{ + printk("STUB: include/asm-x86/kexec.h: crash_setup_regs: " + "not implemented\n"); +} + +#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 +++ x/xen/include/public/kexec.h @@ -0,0 +1,85 @@ +/* + * kexec.h - Public portion + * + * Created By: Horms + * + * Types based on those in ./vcpu.h on request from Keir Frasier + */ + +#ifndef _XEN_PUBLIC_KEXEC_H +#define _XEN_PUBLIC_KEXEC_H + +#include "xen.h" + +/* + * Prototype for this hypercall is: + * int kexec_op(int cmd, int type, void *extra_args) + * @cmd == KEXEC_CMD_... + * KEXEC operation to perform + * @arg1 == Operation-specific unsigned long argument + * This could be in extra_args, but by putting it here + * copy_from_user can be avoided, inparticular in + * KEXEC_CMD_kexec during a crash dump, which is a failry + * critical section of code.If this turns out not to be + * important then it can be collapsed into extra_args. + * @extra_args == Operation-specific extra arguments (NULL if none). + */ + +#define KEXEC_TYPE_DEFAULT 0 +#define KEXEC_TYPE_CRASH 1 + +/* + * Perform kexec having previously loaded a kexec or kdump kernel + * as appropritate. + * @arg1 == KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH + * @extra_arg == pointer to cpu_user_regs_t structure. + */ +#define KEXEC_CMD_kexec 0 + +/* + * Load kernel image in preperation for kexec or kdump. + * @arg1 == KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH + * @extra_arg == pointer to xen_kexec_image_t structure. + */ +#define KEXEC_CMD_kexec_load 1 +typedef struct xen_kexec_image { + unsigned long indirection_page; + unsigned long reboot_code_buffer; + unsigned long start_address; +} xen_kexec_image_t; + +/* + * Clean up image loaded by KEXEC_CMD_kexec_load + * @arg1 == KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH + */ +#define KEXEC_CMD_kexec_unload 2 + +/* + * Find the base pointer and size of the area that xen has + * reserved for use by the crash kernel. + * @extra_arg == pointer to xen_kexec_reserve_t structure. + */ +#define KEXEC_CMD_kexec_reserve 3 +typedef struct xen_kexec_reserve { + unsigned long size; + unsigned long start; +} xen_kexec_reserve_t; + +/* + * Find the base pointer of the area that xen has + * reserved for use by a crash note for a given VCPU + * @extra_arg == pointer to unsigned long. + */ +#define KEXEC_CMD_kexec_crash_note 4 + +#endif /* _XEN_PUBLIC_KEXEC_H */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --- x/xen/include/public/xen.h +++ x/xen/include/public/xen.h @@ -64,6 +64,7 @@ #define __HYPERVISOR_xenoprof_op 31 #define __HYPERVISOR_event_channel_op 32 #define __HYPERVISOR_physdev_op 33 +#define __HYPERVISOR_kexec_op 34 /* Architecture-specific hypercall definitions. */ #define __HYPERVISOR_arch_0 48 --- /dev/null +++ x/xen/include/xen/elfcore.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * include/xen/elfcore.h + * + * Created By: Horms + * + * Based heavily on include/linux/elfcore.h from Linux 2.6.16 + * Naming scheeme based on include/xen/elf.h (not include/linux/elfcore.h) + * + */ + +#ifndef __ELFCOREC_H__ +#define __ELFCOREC_H__ + +#include +#include +#include + +#define NT_PRSTATUS 1 + +typedef struct +{ + int signo; /* signal number */ + int code; /* extra code */ + int errno; /* errno */ +} ELF_Signifo; + +/* These seem to be the same length on all architectures on Linux */ +typedef int ELF_Pid; +typedef struct { + long tv_sec; + long tv_usec; +} ELF_Timeval; +typedef unsigned long ELF_Greg; +#define ELF_NGREG (sizeof (struct cpu_user_regs) / sizeof(ELF_Greg)) +typedef ELF_Greg ELF_Gregset[ELF_NGREG]; + +/* + * Definitions to generate Intel SVR4-like core files. + * These mostly have the same names as the SVR4 types with "elf_" + * tacked on the front to prevent clashes with linux definitions, + * and the typedef forms have been avoided. This is mostly like + * the SVR4 structure, but more Linuxy, with things that Linux does + * not support and which gdb doesn't really use excluded. + */ +typedef struct +{ + ELF_Signifo pr_info; /* Info associated with signal */ + short pr_cursig; /* Current signal */ + unsigned long pr_sigpend; /* Set of pending signals */ + unsigned long pr_sighold; /* Set of held signals */ + ELF_Pid pr_pid; + ELF_Pid pr_ppid; + ELF_Pid pr_pgrp; + ELF_Pid pr_sid; + ELF_Timeval pr_utime; /* User time */ + ELF_Timeval pr_stime; /* System time */ + ELF_Timeval pr_cutime; /* Cumulative user time */ + ELF_Timeval pr_cstime; /* Cumulative system time */ + ELF_Gregset pr_reg; /* GP registers */ + int pr_fpvalid; /* True if math co-processor being used. */ +} ELF_Prstatus; + +#endif /* __ELFCOREC_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --- /dev/null +++ x/xen/include/xen/kexec.h @@ -0,0 +1,33 @@ +/* + * include/xen/kexec.h - Internal archtecture independant portion + * + * Created By: Horms + * + */ + +#include + +#define MAX_NOTE_BYTES 1024 + +typedef u32 note_buf_t[MAX_NOTE_BYTES/4]; +DECLARE_PER_CPU (note_buf_t, crash_notes); + +int machine_kexec_load(int type, xen_kexec_image_t *image); +void machine_kexec_unload(int type, xen_kexec_image_t *image); +void machine_kexec_reserved(xen_kexec_reserve_t *reservation); +void machine_kexec(xen_kexec_image_t *image); +void machine_shutdown(xen_kexec_image_t *image); +void machine_crash_shutdown(cpu_user_regs_t *regs); + +extern unsigned int opt_kdump_megabytes; +extern unsigned int opt_kdump_megabytes_base; + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --- x/xen/include/xen/mm.h +++ x/xen/include/xen/mm.h @@ -40,6 +40,7 @@ struct page_info; paddr_t init_boot_allocator(paddr_t bitmap_start); void init_boot_pages(paddr_t ps, paddr_t pe); unsigned long alloc_boot_pages(unsigned long nr_pfns, unsigned long pfn_align); +unsigned long alloc_boot_pages_at(unsigned long nr_pfns, unsigned long pfn_at); void end_boot_allocator(void); /* Generic allocator. These functions are *not* interrupt-safe. */ --- /dev/null +++ x/patches/linux-2.6.16.13/kexec-generic.patch @@ -0,0 +1,294 @@ + drivers/base/cpu.c | 20 ++++++++++++++ + include/linux/kexec.h | 5 +++ + kernel/kexec.c | 68 ++++++++++++++++++++++++++++++++++++++++--------- + kernel/sys.c | 4 ++ + 4 files changed, 85 insertions(+), 12 deletions(-) + +--- x/drivers/base/cpu.c ++++ x/drivers/base/cpu.c +@@ -11,6 +11,10 @@ + + #include "base.h" + ++#ifdef CONFIG_XEN ++#include ++#endif ++ + struct sysdev_class cpu_sysdev_class = { + set_kset_name("cpu"), + }; +@@ -86,6 +90,18 @@ static inline void register_cpu_control( + #ifdef CONFIG_KEXEC + #include + ++#ifdef CONFIG_XEN ++static unsigned long get_crash_notes(int cpu) ++{ ++ unsigned long crash_note; ++ ++ if (HYPERVISOR_kexec(KEXEC_CMD_kexec_crash_note, cpu, &crash_note) < 0) ++ return 0UL; ++ return crash_note; ++} ++#endif ++ ++/* XXX: This only finds dom0's CPU's */ + static ssize_t show_crash_notes(struct sys_device *dev, char *buf) + { + struct cpu *cpu = container_of(dev, struct cpu, sysdev); +@@ -101,7 +117,11 @@ static ssize_t show_crash_notes(struct s + * boot up and this data does not change there after. Hence this + * operation should be safe. No locking required. + */ ++#ifndef CONFIG_XEN + addr = __pa(per_cpu_ptr(crash_notes, cpunum)); ++#else ++ addr = (unsigned long long)get_crash_notes(cpunum); ++#endif + rc = sprintf(buf, "%Lx\n", addr); + return rc; + } +--- x/include/linux/kexec.h ++++ x/include/linux/kexec.h +@@ -91,6 +91,11 @@ struct kimage { + extern NORET_TYPE void machine_kexec(struct kimage *image) ATTRIB_NORET; + extern int machine_kexec_prepare(struct kimage *image); + extern void machine_kexec_cleanup(struct kimage *image); ++#ifdef CONFIG_XEN ++extern int xen_machine_kexec_load(struct kimage *image); ++extern void xen_machine_kexec_unload(struct kimage *image); ++extern NORET_TYPE void xen_machine_kexec(struct kimage *image) ATTRIB_NORET; ++#endif + extern asmlinkage long sys_kexec_load(unsigned long entry, + unsigned long nr_segments, + struct kexec_segment __user *segments, +--- x/kernel/kexec.c ++++ x/kernel/kexec.c +@@ -38,6 +38,20 @@ struct resource crashk_res = { + .flags = IORESOURCE_BUSY | IORESOURCE_MEM + }; + ++/* Kexec needs to know about the actually physical addresss. ++ * But in xen, a physical address is a pseudo-physical addresss. */ ++#ifndef CONFIG_XEN ++#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) ++#else ++#define kexec_page_to_pfn(page) pfn_to_mfn(page_to_pfn(page)) ++#define kexec_pfn_to_page(pfn) pfn_to_page(mfn_to_pfn(pfn)) ++#define kexec_virt_to_phys(addr) virt_to_machine(addr) ++#define kexec_phys_to_virt(addr) phys_to_virt(machine_to_phys(addr)) ++#endif ++ + int kexec_should_crash(struct task_struct *p) + { + if (in_interrupt() || !p->pid || p->pid == 1 || panic_on_oops) +@@ -403,7 +417,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 +451,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 +505,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 +532,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 +554,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 +615,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 +633,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 +712,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 +727,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 +755,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 +805,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 +837,7 @@ out: + return result; + } + ++#ifndef CONFIG_XEN + static int kimage_load_crash_segment(struct kimage *image, + struct kexec_segment *segment) + { +@@ -833,7 +860,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 +908,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 +1025,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 +1084,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 +1099,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 +1122,4 @@ static int __init crash_notes_memory_ini + return 0; + } + module_init(crash_notes_memory_init) ++#endif +--- x/kernel/sys.c ++++ x/kernel/sys.c +@@ -435,8 +435,12 @@ void kernel_kexec(void) + kernel_restart_prepare(NULL); + printk(KERN_EMERG "Starting new kernel\n"); + machine_shutdown(); ++#ifdef CONFIG_XEN ++ xen_machine_kexec(image); ++#else + machine_kexec(image); + #endif ++#endif + } + EXPORT_SYMBOL_GPL(kernel_kexec); + --- /dev/null +++ x/patches/linux-2.6.16.13/0-linux-2.6.16-kexec_page_table_a_stubs.patch @@ -0,0 +1,85 @@ +kexec: Avoid overwriting the current pgd (V2, stubs) + +This patch adds an architecture specific structure "struct kimage_arch" to +struct kimage. This structure is filled in with members by the architecture +specific patches followed by this one. + +Signed-off-by: Magnus Damm +--- + + Applies on top of 2.6.16 and 2.6.17-rc4. + + include/asm-i386/kexec.h | 2 ++ + include/asm-powerpc/kexec.h | 2 ++ + include/asm-s390/kexec.h | 2 ++ + include/asm-sh/kexec.h | 2 ++ + include/asm-x86_64/kexec.h | 2 ++ + include/linux/kexec.h | 2 ++ + 6 files changed, 12 insertions(+) + +--- x/include/asm-i386/kexec.h ++++ x/include/asm-i386/kexec.h +@@ -29,6 +29,8 @@ + + #define MAX_NOTE_BYTES 1024 + ++struct kimage_arch {}; ++ + /* CPU does not save ss and esp on stack if execution is already + * running in kernel mode at the time of NMI occurrence. This code + * fixes it. +--- x/include/asm-powerpc/kexec.h ++++ x/include/asm-powerpc/kexec.h +@@ -108,6 +108,8 @@ static inline void crash_setup_regs(stru + + #define MAX_NOTE_BYTES 1024 + ++struct kimage_arch {}; ++ + #ifdef __powerpc64__ + extern void kexec_smp_wait(void); /* get and clear naca physid, wait for + master to copy new code to 0 */ +--- x/include/asm-s390/kexec.h ++++ x/include/asm-s390/kexec.h +@@ -36,6 +36,8 @@ + + #define MAX_NOTE_BYTES 1024 + ++struct kimage_arch {}; ++ + /* Provide a dummy definition to avoid build failures. */ + static inline void crash_setup_regs(struct pt_regs *newregs, + struct pt_regs *oldregs) { } +--- x/include/asm-sh/kexec.h ++++ x/include/asm-sh/kexec.h +@@ -25,6 +25,8 @@ + + #ifndef __ASSEMBLY__ + ++struct kimage_arch {}; ++ + extern void machine_shutdown(void); + extern void *crash_notes; + +--- x/include/asm-x86_64/kexec.h ++++ x/include/asm-x86_64/kexec.h +@@ -29,6 +29,8 @@ + + #define MAX_NOTE_BYTES 1024 + ++struct kimage_arch {}; ++ + /* + * Saving the registers of the cpu on which panic occured in + * crash_kexec to save a valid sp. The registers of other cpus +--- x/include/linux/kexec.h ++++ x/include/linux/kexec.h +@@ -69,6 +69,8 @@ struct kimage { + unsigned long start; + struct page *control_code_page; + ++ struct kimage_arch arch_data; ++ + unsigned long nr_segments; + struct kexec_segment segment[KEXEC_SEGMENT_MAX]; + --jI8keyz6grp/JLjh Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="51.2.1-kexec-x86-upstream.patch" kexec: x86 This is the x86 component of kexec for xen. The generic component is a prerequsite for this patch. The x86_64 or x86_32 (i386) patch is also needed in order to use this code, however the code should compile is. Signed-Off-By: Horms Signed-Off-By: Magnus Damm linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c | 14 + xen/arch/x86/crash.c | 171 ++++++++++++++++- xen/arch/x86/dom0_ops.c | 3 xen/arch/x86/machine_kexec.c | 150 +++++++++++++- xen/arch/x86/setup.c | 75 ++++++- xen/arch/x86/x86_32/Makefile | 1 xen/arch/x86/x86_32/machine_kexec.c | 27 ++ xen/arch/x86/x86_64/Makefile | 1 xen/arch/x86/x86_64/machine_kexec.c | 28 ++ xen/include/asm-x86/elf.h | 27 ++ xen/include/asm-x86/fixmap.h | 1 xen/include/asm-x86/hypercall.h | 5 xen/include/asm-x86/kexec.h | 14 - xen/include/asm-x86/x86_32/elf.h | 30 ++ xen/include/asm-x86/x86_32/kexec.h | 51 +++++ xen/include/asm-x86/x86_64/elf.h | 30 ++ xen/include/asm-x86/x86_64/kexec.h | 50 ++++ xen/include/public/kexec.h | 2 xen/include/xen/elfcore.h | 3 19 files changed, 652 insertions(+), 31 deletions(-) --- x/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c +++ x/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c @@ -23,7 +23,21 @@ static inline unsigned long machine_addr static void setup_hypercall_arg(xen_kexec_image_t *xki, struct kimage *image) { +#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64) + struct kimage_arch *arch = &image->arch_data; + int k, n = sizeof(arch->page_table_a) / sizeof(arch->page_table_a[0]); + + memset(xki, 0, sizeof(*xki)); + + for (k = 0; k < n; k++) + xki->page_table_a[k] = machine_address(arch->page_table_a[k]); + +#ifdef CONFIG_X86_64 + xki->page_table_b = machine_address(arch->page_table_b); +#endif +#else memset(xki, 0, sizeof(*xki)); +#endif xki->indirection_page = image->head; xki->reboot_code_buffer = --- x/xen/arch/x86/crash.c +++ x/xen/arch/x86/crash.c @@ -3,16 +3,181 @@ * * Created By: Horms * - * Should be based heavily on arch/i386/kernel/crash.c from Linux 2.6.16 + * Based heavily on arch/i386/kernel/crash.c from Linux 2.6.16 */ -#include /* for printk() used in stub */ +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +static int crashing_cpu; + +static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, + size_t data_len) +{ + Elf_Note note; + + note.namesz = strlen(name) + 1; + note.descsz = data_len; + note.type = type; + memcpy(buf, ¬e, sizeof(note)); + buf += (sizeof(note) +3)/4; + memcpy(buf, name, note.namesz); + buf += (note.namesz + 3)/4; + memcpy(buf, data, note.descsz); + buf += (note.descsz + 3)/4; + + return buf; +} + +static void final_note(u32 *buf) +{ + Elf_Note note; + + note.namesz = 0; + note.descsz = 0; + note.type = 0; + memcpy(buf, ¬e, sizeof(note)); +} + +static void crash_save_this_cpu(struct cpu_user_regs *regs, int cpu) +{ + ELF_Prstatus prstatus; + uint32_t *buf; + + printk("crash_save_this_cpu: %d\n", cpu); + + if ((cpu < 0) || (cpu >= NR_CPUS)) + return; + + /* Using ELF notes here is opportunistic. + * A well defined structure format with tags is needed + * ELF notes happen to provide this and there is infastructure + * in the Linux kernel to supprot them. In order to make + * crash dumps produced by xen the same, the same + * technique is used here. + */ + + /* It should be safe to use per_cpu() here instead of per_cpu_ptr() + * (which does not exist in xen) as kexecing_lock must be held in + * order to get anywhere near here */ + buf = (uint32_t *)per_cpu(crash_notes, cpu); + if (!buf) /* XXX: Can this ever occur? */ + return; + memset(&prstatus, 0, sizeof(prstatus)); + /* XXX: Xen does not have processes. For the crashing CPU on a dom0 + * crash this could be pased down from dom0, but is this + * neccessary? + * prstatus.pr_pid = current->pid; */ + ELF_CORE_COPY_REGS(prstatus.pr_reg, regs); + buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, + sizeof(prstatus)); + final_note(buf); +} + +static void crash_save_self(struct cpu_user_regs *regs) +{ + crash_save_this_cpu(regs, smp_processor_id()); +} + +#ifdef CONFIG_SMP +static atomic_t waiting_for_crash_ipi; + +static int crash_nmi_callback(struct cpu_user_regs *regs, int cpu) +{ + struct cpu_user_regs fixed_regs; + + /* Don't do anything if this handler is invoked on crashing cpu. + * Otherwise, system will completely hang. Crashing cpu can get + * an NMI if system was initially booted with nmi_watchdog parameter. + */ + if (cpu == crashing_cpu) + return 1; + local_irq_disable(); + + if (!user_mode(regs)) { + crash_fixup_ss_esp(&fixed_regs, regs); + regs = &fixed_regs; + } + crash_save_this_cpu(regs, cpu); + disable_local_APIC(); + atomic_dec(&waiting_for_crash_ipi); + /* Assume hlt works */ + __asm__ __volatile__ ( "hlt" ); + for(;;); + + return 1; + + /* Need to use this somewhere as Xen builds with -Werror */ + crash_setup_regs(&fixed_regs, regs); +} + +/* + * By using the NMI code instead of a vector we just sneak thru the + * word generator coming out with just what we want. AND it does + * not matter if clustered_apic_mode is set or not. + */ +static void smp_send_nmi_allbutself(void) +{ + cpumask_t allbutself = cpu_online_map; + cpu_clear(smp_processor_id(), allbutself); + send_IPI_mask(allbutself, APIC_DM_NMI); +} + +static void nmi_shootdown_cpus(void) +{ + unsigned long msecs; + + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); + /* Would it be better to replace the trap vector here? */ + set_nmi_callback(crash_nmi_callback); + /* Ensure the new callback function is set before sending + * out the NMI + */ + wmb(); + + smp_send_nmi_allbutself(); + + msecs = 1000; /* Wait at most a second for the other cpus to stop */ + while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { + mdelay(1); + msecs--; + } + + /* Leave the nmi callback set */ + disable_local_APIC(); +} +#else +static void nmi_shootdown_cpus(void) +{ + /* There are no cpus to shootdown */ +} +#endif + void machine_crash_shutdown(struct cpu_user_regs *regs) { - printk("STUB: arch/x86/crash.c: machine_crash_shutdown: not implemented\n"); + printk("machine_crash_shutdown: %d\n", smp_processor_id()); + local_irq_disable(); + + crashing_cpu = smp_processor_id(); + nmi_shootdown_cpus(); +#ifdef CONFIG_X86_IO_APIC + disable_IO_APIC(); +#endif + crash_save_self(regs); } /* --- x/xen/arch/x86/dom0_ops.c +++ x/xen/arch/x86/dom0_ops.c @@ -29,6 +29,9 @@ #include #include "cpu/mtrr/mtrr.h" +extern unsigned int opt_kdump_megabytes; +extern unsigned int opt_kdump_megabytes_base; + #define TRC_DOM0OP_ENTER_BASE 0x00020000 #define TRC_DOM0OP_LEAVE_BASE 0x00030000 --- x/xen/arch/x86/machine_kexec.c +++ x/xen/arch/x86/machine_kexec.c @@ -6,38 +6,164 @@ */ #include /* for printk() used in stubs */ +#include +#include +#include +#include +#include +#include #include +#include +#include #include +#include +#include + +#define create_level_mapping(lvl, next, pages, nopages, k, va) \ +{ \ + lvl##_pgentry_t *table; \ + void *old = next; \ + \ + table = (lvl##_pgentry_t *)next + lvl##_table_offset(va); \ + if (!(lvl##e_get_flags(*table) & _PAGE_PRESENT)) { \ + if (k >= nopages || pages[k] == 0) \ + return -1; \ + *table = lvl##e_from_pfn(pages[k++]>>PAGE_SHIFT, __PAGE_HYPERVISOR); \ + } \ + next = map_domain_page(lvl##e_get_pfn(*table)); \ + unmap_domain_page(old); \ +} + +#define create_level_1_mapping(next, nopages, va, pa) \ +{ \ + l1_pgentry_t *table; \ + \ + table = (l1_pgentry_t *)next + l1_table_offset(va); \ + if (!(l1e_get_flags(*table) & _PAGE_PRESENT)) { \ + *table = l1e_from_pfn(pa >> PAGE_SHIFT, __PAGE_HYPERVISOR); \ + } \ + unmap_domain_page(next); \ +} + +static int create_mapping(unsigned long root, + unsigned long *pages, int nopages, + unsigned long va, unsigned long pa) +{ + void *next = map_domain_page(root >> PAGE_SHIFT); + int k = 0; + +#if CONFIG_PAGING_LEVELS >= 4 + create_level_mapping(l4, next, pages, nopages, k, va); +#endif +#if CONFIG_PAGING_LEVELS >= 3 + create_level_mapping(l3, next, pages, nopages, k, va); +#endif + create_level_mapping(l2, next, pages, nopages, k, va); + + create_level_1_mapping(next, nopages, va, pa); + + return k; +} + +static int setup_page_table_a(xen_kexec_image_t *image) +{ + void *page; + int k, n = sizeof(image->page_table_a) / sizeof(image->page_table_a[0]); + + /* clear page_table_a pages */ + + for (k = 0; k < n; k++) { + if (!image->page_table_a[k]) + break; + + page = map_domain_page(image->page_table_a[k] >> PAGE_SHIFT); + clear_page(page); + unmap_domain_page(page); + } + + /* check that the first page (root page) is actually non-zero */ + + if (k == 0) + return -1; + + /* setup fixmap to point to our control page */ + + set_fixmap(FIX_KEXEC_PAGE, image->reboot_code_buffer); + + /* fill in page_table_a: create mapping at fixmap address */ + + k = create_mapping(image->page_table_a[0], + &image->page_table_a[1], + n - 1, fix_to_virt(FIX_KEXEC_PAGE), + image->reboot_code_buffer); + if (k < 0) + return -1; + + /* fill in page_table_a: create identity mapping */ + + k = create_mapping(image->page_table_a[0], + &image->page_table_a[1 + k], + n - (1 + k), image->reboot_code_buffer, + image->reboot_code_buffer); + if (k < 0) + return -1; + + return 0; +} int machine_kexec_load(int type, xen_kexec_image_t *image) { - printk("STUB: arch/x86/machine_kexec.c: machine_kexec_load: " - "not implemented\n"); - return -1; + return setup_page_table_a(image); } void machine_kexec_unload(int type, xen_kexec_image_t *image) { - printk("STUB: arch/x86/machine_kexec.c: machine_kexec_unload: " - "not implemented\n"); } void machine_kexec_reserved(xen_kexec_reserve_t *reservation) { - printk("STUB: arch/x86/machine_kexec.c: machine_kexec_reserved: " - "not implemented\n"); + reservation->size = opt_kdump_megabytes << 20; + reservation->start = opt_kdump_megabytes_base << 20; } -void machine_kexec(xen_kexec_image_t *image) +static void __machine_shutdown(void *data) { - printk("STUB: arch/x86/machine_kexec.c: machine_kexec: " - "not implemented\n"); + xen_kexec_image_t *image = (xen_kexec_image_t *)data; + + printk("__machine_shutdown: cpu=%u\n", smp_processor_id()); + + watchdog_disable(); + console_start_sync(); + + smp_send_stop(); + +#ifdef CONFIG_X86_IO_APIC + disable_IO_APIC(); +#endif + + machine_kexec(image); } void machine_shutdown(xen_kexec_image_t *image) { - printk("STUB: arch/x86/machine_shutdown.c: machine_shutdown: " - "not implemented\n"); + int reboot_cpu_id; + cpumask_t reboot_cpu; + + reboot_cpu_id = 0; + + if (!cpu_isset(reboot_cpu_id, cpu_online_map)) + reboot_cpu_id = smp_processor_id(); + + if (reboot_cpu_id != smp_processor_id()) { + cpus_clear(reboot_cpu); + cpu_set(reboot_cpu_id, reboot_cpu); + on_selected_cpus(reboot_cpu, __machine_shutdown, image, 1, 0); + for (;;) + ; /* nothing */ + } + else + __machine_shutdown(image); + BUG(); } /* --- x/xen/arch/x86/setup.c +++ x/xen/arch/x86/setup.c @@ -38,6 +38,11 @@ static unsigned int opt_xenheap_megabyte integer_param("xenheap_megabytes", opt_xenheap_megabytes); #endif +unsigned int opt_kdump_megabytes = 0; +integer_param("kdump_megabytes", opt_kdump_megabytes); +unsigned int opt_kdump_megabytes_base = 0; +integer_param("kdump_megabytes_base", opt_kdump_megabytes_base); + /* opt_nosmp: If true, secondary processors are ignored. */ static int opt_nosmp = 0; boolean_param("nosmp", opt_nosmp); @@ -192,6 +197,20 @@ static void percpu_free_unused_areas(voi __pa(__per_cpu_end)); } +void __init move_memory(unsigned long dst, + unsigned long src_start, unsigned long src_end) +{ +#if defined(CONFIG_X86_32) + memmove((void *)dst, /* use low mapping */ + (void *)src_start, /* use low mapping */ + src_end - src_start); +#elif defined(CONFIG_X86_64) + memmove(__va(dst), + __va(src_start), + src_end - src_start); +#endif +} + void __init __start_xen(multiboot_info_t *mbi) { char __cmdline[] = "", *cmdline = __cmdline; @@ -327,15 +346,8 @@ void __init __start_xen(multiboot_info_t initial_images_start = xenheap_phys_end; initial_images_end = initial_images_start + modules_length; -#if defined(CONFIG_X86_32) - memmove((void *)initial_images_start, /* use low mapping */ - (void *)mod[0].mod_start, /* use low mapping */ - mod[mbi->mods_count-1].mod_end - mod[0].mod_start); -#elif defined(CONFIG_X86_64) - memmove(__va(initial_images_start), - __va(mod[0].mod_start), - mod[mbi->mods_count-1].mod_end - mod[0].mod_start); -#endif + move_memory(initial_images_start, + mod[0].mod_start, mod[mbi->mods_count-1].mod_end); /* Initialise boot-time allocator with all RAM situated after modules. */ xenheap_phys_start = init_boot_allocator(__pa(&_end)); @@ -383,6 +395,51 @@ void __init __start_xen(multiboot_info_t #endif } + if (opt_kdump_megabytes) { + unsigned long kdump_start, kdump_size, k; + + /* mark images pages as free for now */ + + init_boot_pages(initial_images_start, initial_images_end); + + kdump_start = opt_kdump_megabytes_base << 20; + kdump_size = opt_kdump_megabytes << 20; + + printk("Kdump: %luMB (%lukB) at 0x%lx\n", + kdump_size >> 20, + kdump_size >> 10, + kdump_start); + + if ((kdump_start & ~PAGE_MASK) || (kdump_size & ~PAGE_MASK)) + panic("Kdump parameters not page aligned\n"); + + kdump_start >>= PAGE_SHIFT; + kdump_size >>= PAGE_SHIFT; + + /* allocate pages for Kdump memory area */ + + k = alloc_boot_pages_at(kdump_size, kdump_start); + + if (k != kdump_start) + panic("Unable to reserve Kdump memory\n"); + + /* allocate pages for relocated initial images */ + + k = ((initial_images_end - initial_images_start) & ~PAGE_MASK) ? 1 : 0; + k += (initial_images_end - initial_images_start) >> PAGE_SHIFT; + + k = alloc_boot_pages(k, 1); + + if (!k) + panic("Unable to allocate initial images memory\n"); + + move_memory(k << PAGE_SHIFT, initial_images_start, initial_images_end); + + initial_images_end -= initial_images_start; + initial_images_start = k << PAGE_SHIFT; + initial_images_end += initial_images_start; + } + memguard_init(); printk("System RAM: %luMB (%lukB)\n", --- x/xen/arch/x86/x86_32/Makefile +++ x/xen/arch/x86/x86_32/Makefile @@ -3,5 +3,6 @@ obj-y += entry.o obj-y += mm.o obj-y += seg_fixup.o obj-y += traps.o +obj-y += machine_kexec.o obj-$(supervisor_mode_kernel) += supervisor_mode_kernel.o --- /dev/null +++ x/xen/arch/x86/x86_32/machine_kexec.c @@ -0,0 +1,27 @@ +/* + * arch/x86/x86_32/machine_kexec.c + * Handle transition of Linux booting another kernel + * + * Created By: Horms + * + * Should be losely based on arch/i386/kernel/machine_kexec.c + */ + +#include /* for printk() used in stub */ +#include + +void machine_kexec(xen_kexec_image_t *image) +{ + printk("STUB: arch/x86/x86_32/machine_kexec.c: machine_kexec: " + "not implemented\n"); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --- x/xen/arch/x86/x86_64/Makefile +++ x/xen/arch/x86/x86_64/Makefile @@ -1,3 +1,4 @@ obj-y += entry.o obj-y += mm.o obj-y += traps.o +obj-y += machine_kexec.o --- /dev/null +++ x/xen/arch/x86/x86_64/machine_kexec.c @@ -0,0 +1,28 @@ +/* + * arch/x86/x86_64/machine_kexec.c + * Handle transition of Linux booting another kernel + * + * Created By: Horms + * + * Should be losely based on arch/x86_64/kernel/machine_kexec.c + */ + +#include /* for printk() used in stubs */ +#include +#include + +void machine_kexec(xen_kexec_image_t *image) +{ + printk("STUB: arch/x86/x86_64/machine_kexec.c: machine_kexec: " + "not implemented\n"); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --- /dev/null +++ x/xen/include/asm-x86/elf.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * include/asm-x86/elf.h + * + * Created By: Horms + * + */ + +#ifndef __X86_ELF_H__ +#define __X86_ELF_H__ + +#ifdef __x86_64__ +#include +#else +#include +#endif + +#endif /* __X86_ELF_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --- x/xen/include/asm-x86/fixmap.h +++ x/xen/include/asm-x86/fixmap.h @@ -32,6 +32,7 @@ enum fixed_addresses { FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1, FIX_HPET_BASE, FIX_CYCLONE_TIMER, + FIX_KEXEC_PAGE, __end_of_fixed_addresses }; --- x/xen/include/asm-x86/hypercall.h +++ x/xen/include/asm-x86/hypercall.h @@ -6,6 +6,7 @@ #define __ASM_X86_HYPERCALL_H__ #include +#include extern long do_event_channel_op_compat( @@ -87,6 +88,10 @@ extern long arch_do_vcpu_op( int cmd, struct vcpu *v, XEN_GUEST_HANDLE(void) arg); +extern int +do_kexec( + unsigned long op, unsigned arg1, XEN_GUEST_HANDLE(void) uarg); + #ifdef __x86_64__ extern long --- x/xen/include/asm-x86/kexec.h +++ x/xen/include/asm-x86/kexec.h @@ -8,16 +8,16 @@ #ifndef __X86_KEXEC_H__ #define __X86_KEXEC_H__ -#include /* for printk() used in stub */ +#include #include +#include #include -static void crash_setup_regs(struct cpu_user_regs *newregs, - struct cpu_user_regs *oldregs) -{ - printk("STUB: include/asm-x86/kexec.h: crash_setup_regs: " - "not implemented\n"); -} +#ifdef __x86_64__ +#include +#else +#include +#endif #endif /* __X86_KEXEC_H__ */ --- /dev/null +++ x/xen/include/asm-x86/x86_32/elf.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * include/asm-x86/x86_32/elf.h + * + * Created By: Horms + * + * Should pull be based on include/asm-i386/elf.h:ELF_CORE_COPY_REGS + * from Linux 2.6.16 + */ + +#ifndef __X86_ELF_X86_32_H__ +#define __X86_ELF_X86_32_H__ + +#include /* for printk() used in stub */ + +#define ELF_CORE_COPY_REGS(pr_reg, regs) \ + printk("STUB: include/asm-x86/x86_32/kexec.h: ELF_CORE_COPY_REGS: " \ + "not implemented\n") + + +#endif /* __X86_ELF_X86_32_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --- /dev/null +++ x/xen/include/asm-x86/x86_32/kexec.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * include/asm-x86/x86_32/kexec.h + * + * Created By: Horms + * + * Should be based heavily on include/asm-i386/kexec.h from Linux 2.6.16 + * + */ + +#ifndef __X86_32_KEXEC_H__ +#define __X86_32_KEXEC_H__ + +#include /* for printk() used in stub */ +#include +#include + +static void crash_fixup_ss_esp(struct cpu_user_regs *newregs, + struct cpu_user_regs *oldregs) +{ + printk("STUB: include/asm-x86/x86_32/kexec.h: crash_fixup_ss_esp: " + "not implemented\n"); + return; + crash_fixup_ss_esp(newregs, oldregs); +} + +static void crash_setup_regs(struct cpu_user_regs *newregs, + struct cpu_user_regs *oldregs) +{ + printk("STUB: include/asm-x86/x86_32/kexec.h: crash_setup_regs: " + "not implemented\n"); +} + +static inline int user_mode(struct cpu_user_regs *regs) +{ + printk("STUB: include/asm-x86/x86_32/kexec.h: user_mode: " + "not implemented\n"); + return -1; +} + + +#endif /* __X86_32_KEXEC_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --- /dev/null +++ x/xen/include/asm-x86/x86_64/elf.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * include/asm-x86/x86_64/elf.h + * + * Created By: Horms + * + * Should pull be based on include/asm-x86_64/elf.h:ELF_CORE_COPY_REGS + * from Linux 2.6.16 + */ + +#ifndef __X86_ELF_X86_64_H__ +#define __X86_ELF_X86_64_H__ + +#include /* for printk() used in stub */ + +#define ELF_CORE_COPY_REGS(pr_reg, regs) \ + printk("STUB: include/asm-x86/x86_64/kexec.h: ELF_CORE_COPY_REGS: " \ + "not implemented\n") + + +#endif /* __X86_ELF_X86_64_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --- /dev/null +++ x/xen/include/asm-x86/x86_64/kexec.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * include/asm-x86/x86_64/kexec.h + * + * Created By: Horms + * + * Should be based heavily on include/asm-x86_64/kexec.h from Linux 2.6.16 + * + */ + +#ifndef __X86_64_KEXEC_H__ +#define __X86_64_KEXEC_H__ + +#include /* for printk() used in stub */ +#include +#include + +static void crash_fixup_ss_esp(struct cpu_user_regs *newregs, + struct cpu_user_regs *oldregs) +{ + printk("STUB: include/asm-x86/x86_64/kexec.h: crash_fixup_ss_esp: " + "not implemented\n"); +} + +static void crash_setup_regs(struct cpu_user_regs *newregs, + struct cpu_user_regs *oldregs) +{ + printk("STUB: include/asm-x86/x86_64/kexec.h: crash_setup_regs: " + "not implemented\n"); + return; + crash_fixup_ss_esp(newregs, oldregs); +} + +static inline int user_mode(struct cpu_user_regs *regs) +{ + printk("STUB: include/asm-x86/x86_64/kexec.h: user_mode: " + "not implemented\n"); + return -1; +} + +#endif /* __X86_64_KEXEC_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --- x/xen/include/public/kexec.h +++ x/xen/include/public/kexec.h @@ -43,6 +43,8 @@ */ #define KEXEC_CMD_kexec_load 1 typedef struct xen_kexec_image { + unsigned long page_table_a[7]; + unsigned long page_table_b; unsigned long indirection_page; unsigned long reboot_code_buffer; unsigned long start_address; --- x/xen/include/xen/elfcore.h +++ x/xen/include/xen/elfcore.h @@ -16,6 +16,9 @@ #include #define NT_PRSTATUS 1 +#define NT_XEN_DOM0_CR3 0x10000001 /* XXX: Hopefully this is unused, + feel free to change to a + better/different value */ typedef struct { --jI8keyz6grp/JLjh Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="51.2.1.1-kexec-x86_32-upstream.patch" kexec: x86_32 This is the x86_32 component of kexec for xen. The x86 component is a prerequsite for this patch. Signed-Off-By: Horms Signed-Off-By: Magnus Damm buildconfigs/linux-defconfig_xen_x86_32 | 4 linux-2.6-xen-sparse/arch/i386/Kconfig | 2 linux-2.6-xen-sparse/arch/i386/kernel/Makefile | 2 linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c | 29 linux-2.6-xen-sparse/include/asm-i386/kexec-xen.h | 42 linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h | 8 patches/linux-2.6.16.13/1-linux-2.6.16-kexec_page_table_a_i386.patch | 457 ++++++++++ xen/arch/x86/crash.c | 47 + xen/arch/x86/x86_32/entry.S | 2 xen/arch/x86/x86_32/machine_kexec.c | 28 xen/include/asm-x86/x86_32/elf.h | 34 xen/include/asm-x86/x86_32/kexec.h | 68 + 12 files changed, 683 insertions(+), 40 deletions(-) --- x/buildconfigs/linux-defconfig_xen_x86_32 +++ x/buildconfigs/linux-defconfig_xen_x86_32 @@ -184,10 +184,11 @@ CONFIG_MTRR=y CONFIG_REGPARM=y CONFIG_SECCOMP=y CONFIG_HZ_100=y +CONFIG_KEXEC=y # CONFIG_HZ_250 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=100 -# CONFIG_CRASH_DUMP is not set +CONFIG_CRASH_DUMP=y CONFIG_PHYSICAL_START=0x100000 CONFIG_HOTPLUG_CPU=y @@ -2774,6 +2775,7 @@ CONFIG_NTFS_FS=m # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +# CONFIG_PROC_VMCORE is not set CONFIG_SYSFS=y CONFIG_TMPFS=y # CONFIG_HUGETLB_PAGE is not set --- x/linux-2.6-xen-sparse/arch/i386/Kconfig +++ x/linux-2.6-xen-sparse/arch/i386/Kconfig @@ -726,7 +726,7 @@ source kernel/Kconfig.hz config KEXEC bool "kexec system call (EXPERIMENTAL)" - depends on EXPERIMENTAL && !X86_XEN + depends on EXPERIMENTAL && !XEN_UNPRIVILEGED_GUEST help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot --- x/linux-2.6-xen-sparse/arch/i386/kernel/Makefile +++ x/linux-2.6-xen-sparse/arch/i386/kernel/Makefile @@ -89,7 +89,7 @@ include $(srctree)/scripts/Makefile.xen obj-y += fixup.o microcode-$(subst m,y,$(CONFIG_MICROCODE)) := microcode-xen.o -n-obj-xen := i8259.o timers/ reboot.o smpboot.o trampoline.o +n-obj-xen := i8259.o timers/ reboot.o smpboot.o trampoline.o crash.o obj-y := $(call filterxen, $(obj-y), $(n-obj-xen)) obj-y := $(call cherrypickxen, $(obj-y)) --- x/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c +++ x/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c @@ -68,6 +68,10 @@ #include "setup_arch_pre.h" #include +#ifdef CONFIG_XEN +#include +#endif + /* Forward Declaration. */ void __init find_max_pfn(void); @@ -941,6 +945,7 @@ static void __init parse_cmdline_early ( * after a kernel panic. */ else if (!memcmp(from, "crashkernel=", 12)) { +#ifndef CONFIG_XEN unsigned long size, base; size = memparse(from+12, &from); if (*from == '@') { @@ -951,6 +956,10 @@ static void __init parse_cmdline_early ( crashk_res.start = base; crashk_res.end = base + size - 1; } +#else + printk("Ignoring crashkernel command line, " + "parameter will be supplied by xen\n"); +#endif } #endif #ifdef CONFIG_PROC_VMCORE @@ -1320,9 +1329,22 @@ void __init setup_bootmem_allocator(void } #endif #ifdef CONFIG_KEXEC +#ifndef CONFIG_XEN if (crashk_res.start != crashk_res.end) reserve_bootmem(crashk_res.start, crashk_res.end - crashk_res.start + 1); +#else + { + xen_kexec_reserve_t reservation; + BUG_ON(HYPERVISOR_kexec(KEXEC_CMD_kexec_reserve, 0, + &reservation)); + if (reservation.size) { + crashk_res.start = reservation.start; + crashk_res.end = reservation.start + + reservation.size - 1; + } + } +#endif #endif if (!xen_feature(XENFEAT_auto_translated_physmap)) @@ -1378,6 +1400,10 @@ legacy_init_iomem_resources(struct e820e res->end = res->start + e820[i].size - 1; res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; request_resource(&iomem_resource, res); +#ifdef CONFIG_KEXEC + request_resource(res, &crashk_res); +#endif + if (e820[i].type == E820_RAM) { /* * We don't know which RAM region contains kernel data, @@ -1386,9 +1412,6 @@ legacy_init_iomem_resources(struct e820e */ request_resource(res, code_resource); request_resource(res, data_resource); -#ifdef CONFIG_KEXEC - request_resource(res, &crashk_res); -#endif } } } --- /dev/null +++ x/linux-2.6-xen-sparse/include/asm-i386/kexec-xen.h @@ -0,0 +1,42 @@ +/* + * include/asm-i386/kexec-xen.h + * + * Created By: Horms + */ + +#ifndef _I386_KEXEC_XEN_H +#define _I386_KEXEC_XEN_H + +#include +#include +#include + +static inline void crash_translate_regs(struct pt_regs *linux_regs, + struct cpu_user_regs *xen_regs) +{ + xen_regs->ebx = linux_regs->ebx; + xen_regs->ecx = linux_regs->ecx; + xen_regs->edx = linux_regs->edx; + xen_regs->esi = linux_regs->esi; + xen_regs->edi = linux_regs->edi; + xen_regs->ebp = linux_regs->ebp; + xen_regs->eax = linux_regs->eax; + xen_regs->esp = linux_regs->esp; + xen_regs->ss = linux_regs->xss; + xen_regs->cs = linux_regs->xcs; + xen_regs->ds = linux_regs->xds; + xen_regs->es = linux_regs->xes; + xen_regs->eflags = linux_regs->eflags; +} + +#endif /* _I386_KEXEC_XEN_H */ + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ --- x/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h +++ x/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h @@ -368,5 +368,13 @@ HYPERVISOR_xenoprof_op( return _hypercall2(int, xenoprof_op, op, arg); } +static inline int +HYPERVISOR_kexec( + unsigned long op, unsigned int arg1, void * extra_args) +{ + return _hypercall3(int, kexec_op, op, arg1, extra_args); +} + + #endif /* __HYPERCALL_H__ */ --- x/xen/arch/x86/crash.c +++ x/xen/arch/x86/crash.c @@ -21,6 +21,7 @@ #include #include #include +#include #include static int crashing_cpu; @@ -167,6 +168,51 @@ static void nmi_shootdown_cpus(void) } #endif +/* The cr3 for dom0 on each of its vcpus + * It is added as ELF_Prstatus prstatus.pr_reg[ELF_NGREG-1)], where + * prstatus is the data of the elf note, and ELF_NGREG was extended + * by one to allow extra space. + * This code runs after all cpus except the crashing one have + * been shutdown so as to avoid having to hold domlist_lock, + * as locking after a crash is playing with fire */ +void find_dom0_cr3(void) +{ + struct domain *d; + struct vcpu *v; + uint32_t *buf; + uint32_t cr3; + Elf_Note note; + + /* Don't need to grab domlist_lock as we are the only thing running */ + + /* No need to traverse domain_list, as dom0 is always first */ + d = domain_list; + BUG_ON(d->domain_id); + + for_each_vcpu ( d, v ) { + if ( test_bit(_VCPUF_down, &v->vcpu_flags) ) + continue; + buf = (uint32_t *)per_cpu(crash_notes, v->processor); + if (!buf) /* XXX: Can this ever occur? */ + continue; + + memcpy(¬e, buf, sizeof(Elf_Note)); + buf += (sizeof(Elf_Note) +3)/4 + (note.namesz + 3)/4 + + (note.descsz + 3)/4; + + /* XXX: This probably doesn't take into account shadow mode, + * but that might not be a problem */ + cr3 = pagetable_get_pfn(v->arch.guest_table); + + buf = append_elf_note(buf, "Xen Domanin-0 CR3", + NT_XEN_DOM0_CR3, &cr3, 4); + final_note(buf); + + printk("domain:%i vcpu:%u processor:%u cr3:%08x\n", + d->domain_id, v->vcpu_id, v->processor, cr3); + } +} + void machine_crash_shutdown(struct cpu_user_regs *regs) { printk("machine_crash_shutdown: %d\n", smp_processor_id()); @@ -178,6 +224,7 @@ void machine_crash_shutdown(struct cpu_u disable_IO_APIC(); #endif crash_save_self(regs); + find_dom0_cr3(); } /* --- x/xen/arch/x86/x86_32/entry.S +++ x/xen/arch/x86/x86_32/entry.S @@ -656,6 +656,7 @@ ENTRY(hypercall_table) .long do_xenoprof_op .long do_event_channel_op .long do_physdev_op + .long do_kexec .rept NR_hypercalls-((.-hypercall_table)/4) .long do_ni_hypercall .endr @@ -695,6 +696,7 @@ ENTRY(hypercall_args_table) .byte 2 /* do_xenoprof_op */ .byte 2 /* do_event_channel_op */ .byte 2 /* do_physdev_op */ + .byte 3 /* do_kexec */ .rept NR_hypercalls-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr --- x/xen/arch/x86/x86_32/machine_kexec.c +++ x/xen/arch/x86/x86_32/machine_kexec.c @@ -1,19 +1,31 @@ -/* +/****************************************************************************** * arch/x86/x86_32/machine_kexec.c - * Handle transition of Linux booting another kernel - * - * Created By: Horms + * + * Created By: Horms * - * Should be losely based on arch/i386/kernel/machine_kexec.c + * Based heavily on arch/i386/machine_kexec.c from Linux 2.6.16 */ -#include /* for printk() used in stub */ +#include #include +#include +#include + +typedef asmlinkage void (*relocate_new_kernel_t)( + unsigned long indirection_page, + unsigned long reboot_code_buffer, + unsigned long start_address, + unsigned long page_table_a, + unsigned long has_pae); void machine_kexec(xen_kexec_image_t *image) { - printk("STUB: arch/x86/x86_32/machine_kexec.c: machine_kexec: " - "not implemented\n"); + relocate_new_kernel_t rnk; + + rnk = (relocate_new_kernel_t) fix_to_virt(FIX_KEXEC_PAGE); + (*rnk)(image->indirection_page, image->reboot_code_buffer, + image->start_address, image->page_table_a[0], + (unsigned long)cpu_has_pae); } /* --- x/xen/include/asm-x86/x86_32/elf.h +++ x/xen/include/asm-x86/x86_32/elf.h @@ -3,19 +3,39 @@ * * Created By: Horms * - * Should pull be based on include/asm-i386/elf.h:ELF_CORE_COPY_REGS - * from Linux 2.6.16 + * Based heavily on include/asm-i386/elf.h and + * include/asm-i386/system.h from Linux 2.6.16 */ #ifndef __X86_ELF_X86_32_H__ #define __X86_ELF_X86_32_H__ -#include /* for printk() used in stub */ +/* XXX: Xen doesn't have orig_eax. For kdump, on a dom0 crash, the values + * for the crashing CPU could could be passed down from dom0, but is that + * neccessary? + * Also, I'm not sure why fs and gs are derived from the CPU + * rather than regs */ -#define ELF_CORE_COPY_REGS(pr_reg, regs) \ - printk("STUB: include/asm-x86/x86_32/kexec.h: ELF_CORE_COPY_REGS: " \ - "not implemented\n") - +#define ELF_CORE_COPY_REGS(pr_reg, regs) do { \ + unsigned i; \ + pr_reg[0] = regs->ebx; \ + pr_reg[1] = regs->ecx; \ + pr_reg[2] = regs->edx; \ + pr_reg[3] = regs->esi; \ + pr_reg[4] = regs->edi; \ + pr_reg[5] = regs->ebp; \ + pr_reg[6] = regs->eax; \ + pr_reg[7] = regs->ds; \ + pr_reg[8] = regs->es; \ + asm volatile("mov %%fs,%0":"=rm" (i)); pr_reg[9] = i; \ + asm volatile("mov %%gs,%0":"=rm" (i)); pr_reg[10] = i; \ + pr_reg[11] = 0; /* regs->orig_eax; */ \ + pr_reg[12] = regs->eip; \ + pr_reg[13] = regs->cs; \ + pr_reg[14] = regs->eflags; \ + pr_reg[15] = regs->esp; \ + pr_reg[16] = regs->ss; \ +} while(0); #endif /* __X86_ELF_X86_32_H__ */ --- x/xen/include/asm-x86/x86_32/kexec.h +++ x/xen/include/asm-x86/x86_32/kexec.h @@ -3,42 +3,72 @@ * * Created By: Horms * - * Should be based heavily on include/asm-i386/kexec.h from Linux 2.6.16 - * + * Based heavily on include/asm-i386/kexec.h from Linux 2.6.16 */ -#ifndef __X86_32_KEXEC_H__ -#define __X86_32_KEXEC_H__ - -#include /* for printk() used in stub */ -#include -#include +#ifndef __X86_KEXEC_X86_32_H__ +#define __X86_KEXEC_X86_32_H__ +/* CPU does not save ss and esp on stack if execution is already + * running in kernel mode at the time of NMI occurrence. This code + * fixes it. + */ static void crash_fixup_ss_esp(struct cpu_user_regs *newregs, - struct cpu_user_regs *oldregs) + struct cpu_user_regs *oldregs) { - printk("STUB: include/asm-x86/x86_32/kexec.h: crash_fixup_ss_esp: " - "not implemented\n"); - return; - crash_fixup_ss_esp(newregs, oldregs); + memcpy(newregs, oldregs, sizeof(*newregs)); + newregs->esp = (unsigned long)&(oldregs->esp); + __asm__ __volatile__( + "xorl %%eax, %%eax\n\t" + "movw %%ss, %%ax\n\t" + :"=a"(newregs->ss)); } +/* + * This function is responsible for capturing register states if coming + * via panic otherwise just fix up the ss and esp if coming via kernel + * mode exception. + */ static void crash_setup_regs(struct cpu_user_regs *newregs, struct cpu_user_regs *oldregs) { - printk("STUB: include/asm-x86/x86_32/kexec.h: crash_setup_regs: " - "not implemented\n"); + if (oldregs) + crash_fixup_ss_esp(newregs, oldregs); + else { + __asm__ __volatile__("movl %%ebx,%0" : "=m"(newregs->ebx)); + __asm__ __volatile__("movl %%ecx,%0" : "=m"(newregs->ecx)); + __asm__ __volatile__("movl %%edx,%0" : "=m"(newregs->edx)); + __asm__ __volatile__("movl %%esi,%0" : "=m"(newregs->esi)); + __asm__ __volatile__("movl %%edi,%0" : "=m"(newregs->edi)); + __asm__ __volatile__("movl %%ebp,%0" : "=m"(newregs->ebp)); + __asm__ __volatile__("movl %%eax,%0" : "=m"(newregs->eax)); + __asm__ __volatile__("movl %%esp,%0" : "=m"(newregs->esp)); + __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(newregs->ss)); + __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(newregs->cs)); + __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(newregs->ds)); + __asm__ __volatile__("movw %%es, %%ax;" :"=a"(newregs->es)); + __asm__ __volatile__("pushfl; popl %0" :"=m"(newregs->eflags)); + + newregs->eip = (unsigned long)current_text_addr(); + } } +/* + * From Linux 2.6.16's include/asm-i386/mach-xen/asm/ptrace.h + * + * user_mode_vm(regs) determines whether a register set came from user mode. + * This is true if V8086 mode was enabled OR if the register set was from + * protected mode with RPL-3 CS value. This tricky test checks that with + * one comparison. Many places in the kernel can bypass this full check + * if they have already ruled out V8086 mode, so user_mode(regs) can be used. + */ static inline int user_mode(struct cpu_user_regs *regs) { - printk("STUB: include/asm-x86/x86_32/kexec.h: user_mode: " - "not implemented\n"); - return -1; + return (regs->cs & 2) != 0; } -#endif /* __X86_32_KEXEC_H__ */ +#endif /* __X86_KEXEC_X86_32_H__ */ /* * Local variables: --- /dev/null +++ x/patches/linux-2.6.16.13/1-linux-2.6.16-kexec_page_table_a_i386.patch @@ -0,0 +1,457 @@ +kexec: Avoid overwriting the current pgd (V2, i386) + +This patch upgrades the i386-specific kexec code to avoid overwriting the +current pgd. Overwriting the current pgd is bad when CONFIG_CRASH_DUMP is used +to start a secondary kernel that dumps the memory of the previous kernel. + +The code introduces a new set of page tables called "page_table_a". These +tables are used to provide an executable identity mapping without overwriting +the current pgd. This updated version of the patch fixes a PAE bug and moves +the segment handling code into the reloacte_kernel.S. + +Signed-off-by: Magnus Damm +--- + + The patch has been tested with regular kexec and CONFIG_CRASH_DUMP. + Both PAE and non-PAE configurations work well. + Applies on top of 2.6.16 and 2.6.17-rc4. + + arch/i386/kernel/machine_kexec.c | 230 ++++++++++++++---------------------- + arch/i386/kernel/relocate_kernel.S | 92 ++++++++++++++ + include/asm-i386/kexec.h | 12 + + 3 files changed, 192 insertions(+), 142 deletions(-) + +--- x/arch/i386/kernel/machine_kexec.c ++++ x/arch/i386/kernel/machine_kexec.c +@@ -2,6 +2,10 @@ + * machine_kexec.c - handle transition of Linux booting another kernel + * Copyright (C) 2002-2005 Eric Biederman + * ++ * 2006-05-19 Magnus Damm : ++ * - rewrote identity map code to avoid overwriting current pgd ++ * - moved segment handling code into relocate_kernel.S ++ * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ +@@ -19,123 +23,73 @@ + #include + #include + +-#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) +- +-#define L0_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) +-#define L1_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) +-#define L2_ATTR (_PAGE_PRESENT) +- +-#define LEVEL0_SIZE (1UL << 12UL) ++typedef asmlinkage NORET_TYPE void (*relocate_new_kernel_t)( ++ unsigned long indirection_page, ++ unsigned long reboot_code_buffer, ++ unsigned long start_address, ++ unsigned long page_table_a, ++ unsigned long has_pae) ATTRIB_NORET; + +-#ifndef CONFIG_X86_PAE +-#define LEVEL1_SIZE (1UL << 22UL) +-static u32 pgtable_level1[1024] PAGE_ALIGNED; ++const extern unsigned char relocate_new_kernel[]; ++extern void relocate_new_kernel_end(void); ++const extern unsigned int relocate_new_kernel_size; + +-static void identity_map_page(unsigned long address) ++static int allocate_page_table_a(struct kimage *image) + { +- unsigned long level1_index, level2_index; +- u32 *pgtable_level2; +- +- /* Find the current page table */ +- pgtable_level2 = __va(read_cr3()); ++ struct kimage_arch *arch = &image->arch_data; ++ struct page *page; ++ int k = sizeof(arch->page_table_a) / sizeof(arch->page_table_a[0]); ++ ++ for (; k > 0; k--) { ++ page = kimage_alloc_control_pages(image, 0); ++ if (!page) ++ return -ENOMEM; ++ ++ clear_page(page_address(page)); ++ arch->page_table_a[k - 1] = page; ++ } + +- /* Find the indexes of the physical address to identity map */ +- level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE; +- level2_index = address / LEVEL1_SIZE; +- +- /* Identity map the page table entry */ +- pgtable_level1[level1_index] = address | L0_ATTR; +- pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR; +- +- /* Flush the tlb so the new mapping takes effect. +- * Global tlb entries are not flushed but that is not an issue. +- */ +- load_cr3(pgtable_level2); ++ return 0; + } + +-#else +-#define LEVEL1_SIZE (1UL << 21UL) +-#define LEVEL2_SIZE (1UL << 30UL) +-static u64 pgtable_level1[512] PAGE_ALIGNED; +-static u64 pgtable_level2[512] PAGE_ALIGNED; +- +-static void identity_map_page(unsigned long address) +-{ +- unsigned long level1_index, level2_index, level3_index; +- u64 *pgtable_level3; ++/* workaround for include/asm-i386/pgtable-3level.h */ + +- /* Find the current page table */ +- pgtable_level3 = __va(read_cr3()); +- +- /* Find the indexes of the physical address to identity map */ +- level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE; +- level2_index = (address % LEVEL2_SIZE)/LEVEL1_SIZE; +- level3_index = address / LEVEL2_SIZE; +- +- /* Identity map the page table entry */ +- pgtable_level1[level1_index] = address | L0_ATTR; +- pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR; +- set_64bit(&pgtable_level3[level3_index], +- __pa(pgtable_level2) | L2_ATTR); +- +- /* Flush the tlb so the new mapping takes effect. +- * Global tlb entries are not flushed but that is not an issue. +- */ +- load_cr3(pgtable_level3); +-} ++#ifdef CONFIG_X86_PAE ++#undef pgd_present ++#define pgd_present(pgd) (pgd_val(pgd) & _PAGE_PRESENT) ++#define _PGD_ATTR _PAGE_PRESENT ++#else ++#define _PGD_ATTR _KERNPG_TABLE + #endif + +-static void set_idt(void *newidt, __u16 limit) +-{ +- struct Xgt_desc_struct curidt; +- +- /* ia32 supports unaliged loads & stores */ +- curidt.size = limit; +- curidt.address = (unsigned long)newidt; +- +- load_idt(&curidt); +-}; ++#define pa_page(page) __pa(page_address(page)) + +- +-static void set_gdt(void *newgdt, __u16 limit) ++static int create_mapping(struct page *root, struct page **pages, ++ unsigned long va, unsigned long pa) + { +- struct Xgt_desc_struct curgdt; +- +- /* ia32 supports unaligned loads & stores */ +- curgdt.size = limit; +- curgdt.address = (unsigned long)newgdt; ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ int k = 0; + +- load_gdt(&curgdt); +-}; ++ pgd = (pgd_t *)page_address(root) + pgd_index(va); ++ if (!pgd_present(*pgd)) ++ set_pgd(pgd, __pgd(pa_page(pages[k++]) | _PGD_ATTR)); + +-static void load_segments(void) +-{ +-#define __STR(X) #X +-#define STR(X) __STR(X) ++ pud = pud_offset(pgd, va); ++ if (!pud_present(*pud)) ++ set_pud(pud, __pud(pa_page(pages[k++]) | _KERNPG_TABLE)); + +- __asm__ __volatile__ ( +- "\tljmp $"STR(__KERNEL_CS)",$1f\n" +- "\t1:\n" +- "\tmovl $"STR(__KERNEL_DS)",%%eax\n" +- "\tmovl %%eax,%%ds\n" +- "\tmovl %%eax,%%es\n" +- "\tmovl %%eax,%%fs\n" +- "\tmovl %%eax,%%gs\n" +- "\tmovl %%eax,%%ss\n" +- ::: "eax", "memory"); +-#undef STR +-#undef __STR +-} ++ pmd = pmd_offset(pud, va); ++ if (!pmd_present(*pmd)) ++ set_pmd(pmd, __pmd(pa_page(pages[k++]) | _KERNPG_TABLE)); + +-typedef asmlinkage NORET_TYPE void (*relocate_new_kernel_t)( +- unsigned long indirection_page, +- unsigned long reboot_code_buffer, +- unsigned long start_address, +- unsigned int has_pae) ATTRIB_NORET; ++ pte = (pte_t *)page_address(pmd_page(*pmd)) + pte_index(va); ++ set_pte(pte, __pte(pa | _PAGE_KERNEL_EXEC)); + +-const extern unsigned char relocate_new_kernel[]; +-extern void relocate_new_kernel_end(void); +-const extern unsigned int relocate_new_kernel_size; ++ return k; ++} + + /* + * A architecture hook called to validate the +@@ -147,11 +101,38 @@ const extern unsigned int relocate_new_k + * Do what every setup is needed on image and the + * reboot code buffer to allow us to avoid allocations + * later. +- * +- * Currently nothing. + */ + int machine_kexec_prepare(struct kimage *image) + { ++ void *control_page; ++ unsigned long pa; ++ int k; ++ ++ memset(&image->arch_data, 0, sizeof(image->arch_data)); ++ ++ k = allocate_page_table_a(image); ++ if (k) ++ return k; ++ ++ /* fill in control_page with assembly code */ ++ ++ control_page = page_address(image->control_code_page); ++ memcpy(control_page, relocate_new_kernel, relocate_new_kernel_size); ++ ++ /* map the control_page at the virtual address of relocate_kernel.S */ ++ ++ pa = __pa(control_page); ++ ++ k = create_mapping(image->arch_data.page_table_a[0], ++ &image->arch_data.page_table_a[1], ++ (unsigned long)relocate_new_kernel, pa); ++ ++ /* identity map the control_page */ ++ ++ create_mapping(image->arch_data.page_table_a[0], ++ &image->arch_data.page_table_a[k + 1], ++ pa, pa); ++ + return 0; + } + +@@ -170,45 +151,16 @@ void machine_kexec_cleanup(struct kimage + NORET_TYPE void machine_kexec(struct kimage *image) + { + unsigned long page_list; +- unsigned long reboot_code_buffer; +- ++ unsigned long control_code; ++ unsigned long page_table_a; + relocate_new_kernel_t rnk; + +- /* Interrupts aren't acceptable while we reboot */ +- local_irq_disable(); +- +- /* Compute some offsets */ +- reboot_code_buffer = page_to_pfn(image->control_code_page) +- << PAGE_SHIFT; + page_list = image->head; +- +- /* Set up an identity mapping for the reboot_code_buffer */ +- identity_map_page(reboot_code_buffer); +- +- /* copy it out */ +- memcpy((void *)reboot_code_buffer, relocate_new_kernel, +- relocate_new_kernel_size); +- +- /* The segment registers are funny things, they are +- * automatically loaded from a table, in memory wherever you +- * set them to a specific selector, but this table is never +- * accessed again you set the segment to a different selector. +- * +- * The more common model is are caches where the behide +- * the scenes work is done, but is also dropped at arbitrary +- * times. +- * +- * I take advantage of this here by force loading the +- * segments, before I zap the gdt with an invalid value. +- */ +- load_segments(); +- /* The gdt & idt are now invalid. +- * If you want to load them you must set up your own idt & gdt. +- */ +- set_gdt(phys_to_virt(0),0); +- set_idt(phys_to_virt(0),0); ++ control_code = __pa(page_address(image->control_code_page)); ++ page_table_a = __pa(page_address(image->arch_data.page_table_a[0])); + + /* now call it */ +- rnk = (relocate_new_kernel_t) reboot_code_buffer; +- (*rnk)(page_list, reboot_code_buffer, image->start, cpu_has_pae); ++ rnk = (relocate_new_kernel_t) relocate_new_kernel; ++ (*rnk)(page_list, control_code, image->start, ++ page_table_a, (unsigned long)cpu_has_pae); + } +--- x/arch/i386/kernel/relocate_kernel.S ++++ x/arch/i386/kernel/relocate_kernel.S +@@ -2,12 +2,20 @@ + * relocate_kernel.S - put the kernel image in place to boot + * Copyright (C) 2002-2004 Eric Biederman + * ++ * 2006-05-19 Magnus Damm : ++ * - moved segment handling code from machine_kexec.c ++ * - gdt tables stolen from arch/i386/boot/setup.S ++ * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + + #include ++#include + ++.text ++.align (1 << PAGE_SHIFT) ++ + /* + * Must be relocatable PIC code callable as a C function, that once + * it starts can not use the previous processes stack. +@@ -18,18 +26,68 @@ relocate_new_kernel: + movl 4(%esp), %ebx /* page_list */ + movl 8(%esp), %ebp /* reboot_code_buffer */ + movl 12(%esp), %edx /* start address */ +- movl 16(%esp), %ecx /* cpu_has_pae */ ++ movl 16(%esp), %edi /* page_table_a */ ++ movl 20(%esp), %ecx /* cpu_has_pae */ + + /* zero out flags, and disable interrupts */ + pushl $0 + popfl + ++ /* switch to page_table_a */ ++ movl %edi, %eax ++ movl %eax, %cr3 ++ ++ /* setup idt */ ++ ++ movl %ebp, %eax ++ addl $(idt_48 - relocate_new_kernel), %eax ++ lidtl (%eax) ++ ++ /* setup gdt */ ++ ++ movl %ebp, %eax ++ addl $(gdt - relocate_new_kernel), %eax ++ movl %ebp, %esi ++ addl $((gdt_48 - relocate_new_kernel) + 2), %esi ++ movl %eax, (%esi) ++ ++ movl %ebp, %eax ++ addl $(gdt_48 - relocate_new_kernel), %eax ++ lgdtl (%eax) ++ ++ /* setup data segment registers */ ++ ++ mov $(gdt_ds - gdt), %eax ++ mov %eax, %ds ++ mov %eax, %es ++ mov %eax, %fs ++ mov %eax, %gs ++ mov %eax, %ss ++ + /* set a new stack at the bottom of our page... */ + lea 4096(%ebp), %esp + ++ /* load new code segment */ ++ ++ movl %ebp, %esi ++ xorl %eax, %eax ++ pushl %eax ++ pushl %esi ++ pushl %eax ++ ++ movl $(gdt_cs - gdt), %eax ++ pushl %eax ++ ++ movl %ebp, %eax ++ addl $(identity_mapped - relocate_new_kernel),%eax ++ pushl %eax ++ iretl ++ ++identity_mapped: ++ + /* store the parameters back on the stack */ + pushl %edx /* store the start address */ +- ++ + /* Set cr0 to a known state: + * 31 0 == Paging disabled + * 18 0 == Alignment check disabled +@@ -113,6 +171,36 @@ relocate_new_kernel: + xorl %edi, %edi + xorl %ebp, %ebp + ret ++ ++ .align 16 ++gdt: ++ .fill 1,8,0 ++ ++gdt_cs: ++ .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) ++ .word 0 # base address = 0 ++ .word 0x9A00 # code read/exec ++ .word 0x00CF # granularity = 4096, 386 ++ # (+5th nibble of limit) ++gdt_ds: ++ .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) ++ .word 0 # base address = 0 ++ .word 0x9200 # data read/write ++ .word 0x00CF # granularity = 4096, 386 ++ # (+5th nibble of limit) ++gdt_end: ++ .align 4 ++ ++ .word 0 # alignment byte ++idt_48: ++ .word 0 # idt limit = 0 ++ .word 0, 0 # idt base = 0L ++ ++ .word 0 # alignment byte ++gdt_48: ++ .word gdt_end - gdt - 1 # gdt limit ++ .word 0, 0 # gdt base (filled in later) ++ + relocate_new_kernel_end: + + .globl relocate_new_kernel_size +--- x/include/asm-i386/kexec.h ++++ x/include/asm-i386/kexec.h +@@ -29,7 +29,17 @@ + + #define MAX_NOTE_BYTES 1024 + +-struct kimage_arch {}; ++struct kimage_arch { ++ /* page_table_a[] holds enough pages to create a new page table ++ * that maps the control page twice.. ++ */ ++ ++#if defined(CONFIG_X86_PAE) ++ struct page *page_table_a[5]; /* (2 * pte) + (2 * pmd) + pgd */ ++#else ++ struct page *page_table_a[3]; /* (2 * pte) + pgd */ ++#endif ++}; + + /* CPU does not save ss and esp on stack if execution is already + * running in kernel mode at the time of NMI occurrence. This code --jI8keyz6grp/JLjh Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="51.2.1.2-kexec-x86_64-upstream.patch" kexec: x86_64 This is the x86_64 component of kexec for xen. The x86 component is a prerequsite for this patch. Signed-Off-By: Magnus Damm Signed-Off-By: Horms buildconfigs/linux-defconfig_xen_x86_64 | 2 linux-2.6-xen-sparse/arch/x86_64/Kconfig | 2 linux-2.6-xen-sparse/arch/x86_64/kernel/Makefile | 2 linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c | 26 linux-2.6-xen-sparse/include/asm-x86_64/kexec-xen.h | 30 linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h | 7 linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/ptrace.h | 2 patches/linux-2.6.16.13/2-linux-2.6.16-kexec_page_table_a_x86_64.patch | 421 ++++++++++ patches/linux-2.6.16.13/3-linux-2.6.16-kexec_page_table_a_x86_64-xen.patch | 116 ++ xen/arch/x86/x86_64/entry.S | 2 xen/arch/x86/x86_64/machine_kexec.c | 16 11 files changed, 621 insertions(+), 5 deletions(-) --- x/buildconfigs/linux-defconfig_xen_x86_64 +++ x/buildconfigs/linux-defconfig_xen_x86_64 @@ -139,6 +139,8 @@ CONFIG_SWIOTLB=y CONFIG_PHYSICAL_START=0x100000 CONFIG_SECCOMP=y CONFIG_HZ_100=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y # CONFIG_HZ_250 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=100 --- x/linux-2.6-xen-sparse/arch/x86_64/Kconfig +++ x/linux-2.6-xen-sparse/arch/x86_64/Kconfig @@ -433,7 +433,7 @@ config X86_MCE_AMD config KEXEC bool "kexec system call (EXPERIMENTAL)" - depends on EXPERIMENTAL && !X86_64_XEN + depends on EXPERIMENTAL && !XEN_UNPRIVILEGED_GUEST help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot --- x/linux-2.6-xen-sparse/arch/x86_64/kernel/Makefile +++ x/linux-2.6-xen-sparse/arch/x86_64/kernel/Makefile @@ -59,7 +59,7 @@ pci-dma-y += ../../i386/kernel/pci-dma microcode-$(subst m,y,$(CONFIG_MICROCODE)) := ../../i386/kernel/microcode-xen.o quirks-y := ../../i386/kernel/quirks-xen.o -n-obj-xen := i8259.o reboot.o i8237.o smpboot.o trampoline.o +n-obj-xen := i8259.o reboot.o i8237.o smpboot.o trampoline.o crash.o include $(srctree)/scripts/Makefile.xen --- x/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c +++ x/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c @@ -79,6 +79,10 @@ #include #include +#ifdef CONFIG_XEN +#include +#endif + extern unsigned long start_pfn; extern struct edid_info edid_info; @@ -446,6 +450,7 @@ static __init void parse_cmdline_early ( * after a kernel panic. */ else if (!memcmp(from, "crashkernel=", 12)) { +#ifndef CONFIG_XEN unsigned long size, base; size = memparse(from+12, &from); if (*from == '@') { @@ -456,6 +461,10 @@ static __init void parse_cmdline_early ( crashk_res.start = base; crashk_res.end = base + size - 1; } +#else + printk("Ignoring crashkernel command line, " + "parameter will be supplied by xen\n"); +#endif } #endif @@ -810,10 +819,23 @@ void __init setup_arch(char **cmdline_p) #endif #endif /* !CONFIG_XEN */ #ifdef CONFIG_KEXEC +#ifndef CONFIG_XEN if (crashk_res.start != crashk_res.end) { reserve_bootmem(crashk_res.start, crashk_res.end - crashk_res.start + 1); } +#else + { + xen_kexec_reserve_t reservation; + BUG_ON(HYPERVISOR_kexec(KEXEC_CMD_kexec_reserve, 0, + &reservation)); + if (reservation.size) { + crashk_res.start = reservation.start; + crashk_res.end = reservation.start + + reservation.size - 1; + } + } +#endif #endif paging_init(); @@ -972,6 +994,10 @@ void __init setup_arch(char **cmdline_p) iommu_hole_init(); #endif +#ifdef CONFIG_KEXEC + request_resource(&ioport_resource, &crashk_res); +#endif + #ifdef CONFIG_XEN { struct physdev_set_iopl set_iopl; --- /dev/null +++ x/linux-2.6-xen-sparse/include/asm-x86_64/kexec-xen.h @@ -0,0 +1,30 @@ +/* + * include/asm-x86_64/kexec-xen.h + * + * Created By: Horms + */ + +#ifndef _X86_64_KEXEC_XEN_H +#define _X86_64_KEXEC_XEN_H + +#include +#include +#include + +static inline void crash_translate_regs(struct pt_regs *linux_regs, + struct cpu_user_regs *xen_regs) +{ +#warning Implement me! +} + +#endif /* _X86_64_KEXEC_XEN_H */ + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ --- x/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h +++ x/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h @@ -360,4 +360,11 @@ HYPERVISOR_xenoprof_op( return _hypercall2(int, xenoprof_op, op, arg); } +static inline int +HYPERVISOR_kexec( + unsigned long op, unsigned int arg1, void * extra_args) +{ + return _hypercall3(int, kexec_op, op, arg1, extra_args); +} + #endif /* __HYPERCALL_H__ */ --- x/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/ptrace.h +++ x/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/ptrace.h @@ -90,6 +90,8 @@ extern unsigned long profile_pc(struct p #define profile_pc(regs) instruction_pointer(regs) #endif +#include + void signal_fault(struct pt_regs *regs, void __user *frame, char *where); struct task_struct; --- x/xen/arch/x86/x86_64/entry.S +++ x/xen/arch/x86/x86_64/entry.S @@ -556,6 +556,7 @@ ENTRY(hypercall_table) .quad do_xenoprof_op .quad do_event_channel_op .quad do_physdev_op + .quad do_kexec .rept NR_hypercalls-((.-hypercall_table)/8) .quad do_ni_hypercall .endr @@ -595,6 +596,7 @@ ENTRY(hypercall_args_table) .byte 2 /* do_xenoprof_op */ .byte 2 /* do_event_channel_op */ .byte 2 /* do_physdev_op */ + .byte 3 /* do_kexec */ .rept NR_hypercalls-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr --- x/xen/arch/x86/x86_64/machine_kexec.c +++ x/xen/arch/x86/x86_64/machine_kexec.c @@ -7,14 +7,24 @@ * Should be losely based on arch/x86_64/kernel/machine_kexec.c */ -#include /* for printk() used in stubs */ #include #include +#include + +typedef void (*relocate_new_kernel_t)(unsigned long indirection_page, + unsigned long control_code_buffer, + unsigned long start_address, + unsigned long page_table_a, + unsigned long page_table_b); void machine_kexec(xen_kexec_image_t *image) { - printk("STUB: arch/x86/x86_64/machine_kexec.c: machine_kexec: " - "not implemented\n"); + relocate_new_kernel_t rnk; + + rnk = (relocate_new_kernel_t) fix_to_virt(FIX_KEXEC_PAGE); + (*rnk)(image->indirection_page, image->reboot_code_buffer, + image->start_address, image->page_table_a[0], + image->page_table_b); } /* --- /dev/null +++ x/patches/linux-2.6.16.13/2-linux-2.6.16-kexec_page_table_a_x86_64.patch @@ -0,0 +1,421 @@ +kexec: Avoid overwriting the current pgd (V2, x86_64) + +This patch upgrades the x86_64-specific kexec code to avoid overwriting the +current pgd. Overwriting the current pgd is bad when CONFIG_CRASH_DUMP is used +to start a secondary kernel that dumps the memory of the previous kernel. + +The code introduces a new set of page tables called "page_table_a". These +tables are used to provide an executable identity mapping without overwriting +the current pgd. The already existing page table is renamed to "page_table_b". + +KEXEC_CONTROL_CODE_SIZE is changed into a single page. This updated version of +the patch also moves the segment handling code into the reloacte_kernel.S. + +Signed-off-by: Magnus Damm +--- + + The patch has been tested with regular kexec and CONFIG_CRASH_DUMP. + Applies on top of 2.6.16 and 2.6.17-rc4. + + arch/x86_64/kernel/machine_kexec.c | 193 +++++++++++++++++----------------- + arch/x86_64/kernel/relocate_kernel.S | 84 +++++++++++++- + include/asm-x86_64/kexec.h | 15 ++ + 3 files changed, 189 insertions(+), 103 deletions(-) + +--- x/arch/x86_64/kernel/machine_kexec.c ++++ x/arch/x86_64/kernel/machine_kexec.c +@@ -2,6 +2,10 @@ + * machine_kexec.c - handle transition of Linux booting another kernel + * Copyright (C) 2002-2005 Eric Biederman + * ++ * 2006-05-19 Magnus Damm : ++ * - rewrote identity map code to avoid overwriting current pgd ++ * - moved segment handling code into relocate_kernel.S ++ * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ +@@ -96,81 +100,110 @@ out: + } + + +-static int init_pgtable(struct kimage *image, unsigned long start_pgtable) ++static int create_page_table_b(struct kimage *image) + { +- pgd_t *level4p; +- level4p = (pgd_t *)__va(start_pgtable); +- return init_level4_page(image, level4p, 0, end_pfn << PAGE_SHIFT); +-} ++ struct kimage_arch *arch = &image->arch_data; + +-static void set_idt(void *newidt, u16 limit) +-{ +- struct desc_ptr curidt; ++ arch->page_table_b = kimage_alloc_control_pages(image, 0); + +- /* x86-64 supports unaliged loads & stores */ +- curidt.size = limit; +- curidt.address = (unsigned long)newidt; ++ if (!arch->page_table_b) ++ return -ENOMEM; + +- __asm__ __volatile__ ( +- "lidtq %0\n" +- : : "m" (curidt) +- ); +-}; ++ return init_level4_page(image, page_address(arch->page_table_b), ++ 0, end_pfn << PAGE_SHIFT); ++} + ++typedef NORET_TYPE void (*relocate_new_kernel_t)(unsigned long indirection_page, ++ unsigned long control_code_buffer, ++ unsigned long start_address, ++ unsigned long page_table_a, ++ unsigned long page_table_b) ATTRIB_NORET; ++ ++const extern unsigned char relocate_new_kernel[]; ++const extern unsigned long relocate_new_kernel_size; + +-static void set_gdt(void *newgdt, u16 limit) ++static int allocate_page_table_a(struct kimage *image) + { +- struct desc_ptr curgdt; ++ struct kimage_arch *arch = &image->arch_data; ++ struct page *page; ++ int k = sizeof(arch->page_table_a) / sizeof(arch->page_table_a[0]); + +- /* x86-64 supports unaligned loads & stores */ +- curgdt.size = limit; +- curgdt.address = (unsigned long)newgdt; ++ for (; k > 0; k--) { ++ page = kimage_alloc_control_pages(image, 0); ++ if (!page) ++ return -ENOMEM; + +- __asm__ __volatile__ ( +- "lgdtq %0\n" +- : : "m" (curgdt) +- ); +-}; ++ clear_page(page_address(page)); ++ arch->page_table_a[k - 1] = page; ++ } + +-static void load_segments(void) +-{ +- __asm__ __volatile__ ( +- "\tmovl %0,%%ds\n" +- "\tmovl %0,%%es\n" +- "\tmovl %0,%%ss\n" +- "\tmovl %0,%%fs\n" +- "\tmovl %0,%%gs\n" +- : : "a" (__KERNEL_DS) : "memory" +- ); ++ return 0; + } + +-typedef NORET_TYPE void (*relocate_new_kernel_t)(unsigned long indirection_page, +- unsigned long control_code_buffer, +- unsigned long start_address, +- unsigned long pgtable) ATTRIB_NORET; ++#define _PAGE_KERNEL_EXEC __PAGE_KERNEL_EXEC ++#define pa_page(page) __pa_symbol(page_address(page)) /* __pa() miscompiles */ + +-const extern unsigned char relocate_new_kernel[]; +-const extern unsigned long relocate_new_kernel_size; ++static int create_mapping(struct page *root, struct page **pages, ++ unsigned long va, unsigned long pa) ++{ ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ int k = 0; ++ ++ pgd = (pgd_t *)page_address(root) + pgd_index(va); ++ if (!pgd_present(*pgd)) ++ set_pgd(pgd, __pgd(pa_page(pages[k++]) | _KERNPG_TABLE)); ++ ++ pud = pud_offset(pgd, va); ++ if (!pud_present(*pud)) ++ set_pud(pud, __pud(pa_page(pages[k++]) | _KERNPG_TABLE)); ++ ++ pmd = pmd_offset(pud, va); ++ if (!pmd_present(*pmd)) ++ set_pmd(pmd, __pmd(pa_page(pages[k++]) | _KERNPG_TABLE)); ++ ++ pte = (pte_t *)page_address(pmd_page(*pmd)) + pte_index(va); ++ set_pte(pte, __pte(pa | _PAGE_KERNEL_EXEC)); ++ ++ return k; ++} + + int machine_kexec_prepare(struct kimage *image) + { +- unsigned long start_pgtable, control_code_buffer; +- int result; ++ void *control_page; ++ unsigned long pa; ++ int k; + +- /* Calculate the offsets */ +- start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT; +- control_code_buffer = start_pgtable + PAGE_SIZE; +- +- /* Setup the identity mapped 64bit page table */ +- result = init_pgtable(image, start_pgtable); +- if (result) +- return result; +- +- /* Place the code in the reboot code buffer */ +- memcpy(__va(control_code_buffer), relocate_new_kernel, +- relocate_new_kernel_size); ++ memset(&image->arch_data, 0, sizeof(image->arch_data)); + +- return 0; ++ k = allocate_page_table_a(image); ++ if (k) ++ return k; ++ ++ /* fill in control_page with assembly code */ ++ ++ control_page = page_address(image->control_code_page); ++ memcpy(control_page, relocate_new_kernel, relocate_new_kernel_size); ++ ++ /* map the control_page at the virtual address of relocate_kernel.S */ ++ ++ pa = __pa(control_page); ++ ++ k = create_mapping(image->arch_data.page_table_a[0], ++ &image->arch_data.page_table_a[1], ++ (unsigned long)relocate_new_kernel, pa); ++ ++ /* identity map the control_page */ ++ ++ create_mapping(image->arch_data.page_table_a[0], ++ &image->arch_data.page_table_a[k + 1], ++ pa, pa); ++ ++ /* create identity mapped page table aka page_table_b */ ++ ++ return create_page_table_b(image); + } + + void machine_kexec_cleanup(struct kimage *image) +@@ -185,47 +218,17 @@ void machine_kexec_cleanup(struct kimage + NORET_TYPE void machine_kexec(struct kimage *image) + { + unsigned long page_list; +- unsigned long control_code_buffer; +- unsigned long start_pgtable; ++ unsigned long control_code; ++ unsigned long page_table_a; ++ unsigned long page_table_b; + relocate_new_kernel_t rnk; + +- /* Interrupts aren't acceptable while we reboot */ +- local_irq_disable(); +- +- /* Calculate the offsets */ + page_list = image->head; +- start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT; +- control_code_buffer = start_pgtable + PAGE_SIZE; ++ control_code = __pa(page_address(image->control_code_page)); ++ page_table_a = __pa(page_address(image->arch_data.page_table_a[0])); ++ page_table_b = __pa(page_address(image->arch_data.page_table_b)); + +- /* Set the low half of the page table to my identity mapped +- * page table for kexec. Leave the high half pointing at the +- * kernel pages. Don't bother to flush the global pages +- * as that will happen when I fully switch to my identity mapped +- * page table anyway. +- */ +- memcpy(__va(read_cr3()), __va(start_pgtable), PAGE_SIZE/2); +- __flush_tlb(); +- +- +- /* The segment registers are funny things, they are +- * automatically loaded from a table, in memory wherever you +- * set them to a specific selector, but this table is never +- * accessed again unless you set the segment to a different selector. +- * +- * The more common model are caches where the behide +- * the scenes work is done, but is also dropped at arbitrary +- * times. +- * +- * I take advantage of this here by force loading the +- * segments, before I zap the gdt with an invalid value. +- */ +- load_segments(); +- /* The gdt & idt are now invalid. +- * If you want to load them you must set up your own idt & gdt. +- */ +- set_gdt(phys_to_virt(0),0); +- set_idt(phys_to_virt(0),0); + /* now call it */ +- rnk = (relocate_new_kernel_t) control_code_buffer; +- (*rnk)(page_list, control_code_buffer, image->start, start_pgtable); ++ rnk = (relocate_new_kernel_t) relocate_new_kernel; ++ (*rnk)(page_list, control_code, image->start, page_table_a, page_table_b); + } +--- x/arch/x86_64/kernel/relocate_kernel.S ++++ x/arch/x86_64/kernel/relocate_kernel.S +@@ -2,11 +2,18 @@ + * relocate_kernel.S - put the kernel image in place to boot + * Copyright (C) 2002-2005 Eric Biederman + * ++ * 2006-05-19 Magnus Damm : ++ * - moved segment handling code from machine_kexec.c ++ * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + + #include ++#include ++ ++.text ++.align (1 << PAGE_SHIFT) + + /* + * Must be relocatable PIC code callable as a C function, that once +@@ -18,21 +25,69 @@ relocate_new_kernel: + /* %rdi page_list + * %rsi reboot_code_buffer + * %rdx start address +- * %rcx page_table +- * %r8 arg5 ++ * %rcx page_table_a ++ * %r8 page_table_b + * %r9 arg6 + */ +- ++ + /* zero out flags, and disable interrupts */ + pushq $0 + popfq + ++ /* switch to page_table_a */ ++ movq %rcx, %cr3 ++ ++ /* setup idt */ ++ ++ movq %rsi, %rax ++ addq $(idt_48 - relocate_new_kernel), %rax ++ lidtq (%rax) ++ ++ /* setup gdt */ ++ ++ movq %rsi, %rax ++ addq $(gdt - relocate_new_kernel), %rax ++ movq %rsi, %r9 ++ addq $((gdt_48 - relocate_new_kernel) + 2), %r9 ++ movq %rax, (%r9) ++ ++ movq %rsi, %rax ++ addq $(gdt_48 - relocate_new_kernel), %rax ++ lgdtq (%rax) ++ ++ /* setup data segment registers */ ++ ++ xorl %eax,%eax ++ movl %eax, %ds ++ movl %eax, %es ++ movl %eax, %fs ++ movl %eax, %gs ++ movl %eax, %ss ++ + /* set a new stack at the bottom of our page... */ + lea 4096(%rsi), %rsp + ++ /* load new code segment */ ++ ++ movq %rsp, %rcx ++ xorq %rax, %rax ++ pushq %rax /* SS */ ++ pushq %rcx /* ESP */ ++ pushq %rax /* RFLAGS */ ++ ++ movq $(gdt_code - gdt), %rax ++ pushq %rax /* CS */ ++ ++ movq %rsi, %rax ++ addq $(identity_mapped - relocate_new_kernel), %rax ++ pushq %rax /* RIP */ ++ ++ iretq ++ ++identity_mapped: + /* store the parameters back on the stack */ + pushq %rdx /* store the start address */ +- ++ + /* Set cr0 to a known state: + * 31 1 == Paging enabled + * 18 0 == Alignment check disabled +@@ -69,7 +124,7 @@ relocate_new_kernel: + /* Switch to the identity mapped page tables, + * and flush the TLB. + */ +- movq %rcx, %cr3 ++ movq %r8, %cr3 + + /* Do the copies */ + movq %rdi, %rcx /* Put the page_list in %rcx */ +@@ -136,6 +191,25 @@ relocate_new_kernel: + xorq %r15, %r15 + + ret ++ .align 16 ++gdt: ++ .long 0x00000000 /* NULL descriptor */ ++ .long 0x00000000 ++gdt_code: ++ .long 0x00000000 /* code descriptor */ ++ .long 0x00209800 ++ ++gdt_end: ++ .align 4 ++ ++idt_48: ++ .word 0 # idt limit = 0 ++ .quad 0, 0 # idt base = 0L ++ ++gdt_48: ++ .word gdt_end - gdt - 1 # gdt limit ++ .quad 0, 0 # gdt base (filled in later) ++ + relocate_new_kernel_end: + + .globl relocate_new_kernel_size +--- x/include/asm-x86_64/kexec.h ++++ x/include/asm-x86_64/kexec.h +@@ -21,15 +21,24 @@ + /* Maximum address we can use for the control pages */ + #define KEXEC_CONTROL_MEMORY_LIMIT (0xFFFFFFFFFFUL) + +-/* Allocate one page for the pdp and the second for the code */ +-#define KEXEC_CONTROL_CODE_SIZE (4096UL + 4096UL) ++#define KEXEC_CONTROL_CODE_SIZE 4096 + + /* The native architecture */ + #define KEXEC_ARCH KEXEC_ARCH_X86_64 + + #define MAX_NOTE_BYTES 1024 + +-struct kimage_arch {}; ++struct kimage_arch { ++ /* page_table_a[] holds enough pages to create a new page table ++ * that maps the control page twice.. ++ * ++ * page_table_b points to the root page of a page table which is used ++ * to provide identity mapping of all ram. ++ */ ++ ++ struct page *page_table_a[7]; /* 2 * (pte + pud + pmd) + pgd */ ++ struct page *page_table_b; ++}; + + /* + * Saving the registers of the cpu on which panic occured in --- /dev/null +++ x/patches/linux-2.6.16.13/3-linux-2.6.16-kexec_page_table_a_x86_64-xen.patch @@ -0,0 +1,116 @@ + arch/x86_64/kernel/machine_kexec.c | 61 ++++++++++++++++++++++++++++++++---- + 1 file changed, 55 insertions(+), 6 deletions(-) + +--- x/arch/x86_64/kernel/machine_kexec.c ++++ x/arch/x86_64/kernel/machine_kexec.c +@@ -19,6 +19,48 @@ + #include + #include + ++#ifdef CONFIG_XEN ++#include ++#define x__pmd(x) ((pmd_t) { (x) } ) ++#define x__pud(x) ((pud_t) { (x) } ) ++#define x__pgd(x) ((pgd_t) { (x) } ) ++ ++#define x_pmd_val(x) ((x).pmd) ++#define x_pud_val(x) ((x).pud) ++#define x_pgd_val(x) ((x).pgd) ++ ++static inline void x_set_pmd(pmd_t *dst, pmd_t val) ++{ ++ x_pmd_val(*dst) = x_pmd_val(val); ++} ++ ++static inline void x_set_pud(pud_t *dst, pud_t val) ++{ ++ x_pud_val(*dst) = phys_to_machine(x_pud_val(val)); ++} ++ ++static inline void x_pud_clear (pud_t *pud) ++{ ++ x_pud_val(*pud) = 0; ++} ++ ++static inline void x_set_pgd(pgd_t *dst, pgd_t val) ++{ ++ x_pgd_val(*dst) = phys_to_machine(x_pgd_val(val)); ++} ++ ++static inline void x_pgd_clear (pgd_t * pgd) ++{ ++ x_pgd_val(*pgd) = 0; ++} ++ ++#define MY_LARGE_EXEC _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_PSE ++#define MY_TABLE _PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY ++#else ++#define MY_LARGE_EXEC __PAGE_KERNEL_LARGE_EXEC ++#define MY_TABLE _KERNPG_TABLE ++#endif ++ + static void init_level2_page(pmd_t *level2p, unsigned long addr) + { + unsigned long end_addr; +@@ -26,7 +68,7 @@ + addr &= PAGE_MASK; + end_addr = addr + PUD_SIZE; + while (addr < end_addr) { +- set_pmd(level2p++, __pmd(addr | __PAGE_KERNEL_LARGE_EXEC)); ++ x_set_pmd(level2p++, x__pmd(addr | MY_LARGE_EXEC)); + addr += PMD_SIZE; + } + } +@@ -51,12 +93,12 @@ + } + level2p = (pmd_t *)page_address(page); + init_level2_page(level2p, addr); +- set_pud(level3p++, __pud(__pa(level2p) | _KERNPG_TABLE)); ++ x_set_pud(level3p++, x__pud(__pa(level2p) | MY_TABLE)); + addr += PUD_SIZE; + } + /* clear the unused entries */ + while (addr < end_addr) { +- pud_clear(level3p++); ++ x_pud_clear(level3p++); + addr += PUD_SIZE; + } + out: +@@ -87,12 +129,12 @@ + if (result) { + goto out; + } +- set_pgd(level4p++, __pgd(__pa(level3p) | _KERNPG_TABLE)); ++ x_set_pgd(level4p++, x__pgd(__pa(level3p) | MY_TABLE)); + addr += PGDIR_SIZE; + } + /* clear the unused entries */ + while (addr < end_addr) { +- pgd_clear(level4p++); ++ x_pgd_clear(level4p++); + addr += PGDIR_SIZE; + } + out: +@@ -103,14 +145,21 @@ + static int create_page_table_b(struct kimage *image) + { + struct kimage_arch *arch = &image->arch_data; ++ unsigned long last_page; + + arch->page_table_b = kimage_alloc_control_pages(image, 0); + + if (!arch->page_table_b) + return -ENOMEM; + ++#ifdef CONFIG_XEN ++ last_page = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL); ++#else ++ last_page = end_pfn; ++#endif ++ + return init_level4_page(image, page_address(arch->page_table_b), +- 0, end_pfn << PAGE_SHIFT); ++ 0, last_page << PAGE_SHIFT); + } + + typedef NORET_TYPE void (*relocate_new_kernel_t)(unsigned long indirection_page, --jI8keyz6grp/JLjh Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel --jI8keyz6grp/JLjh--