kexec: ia64 This is the ia64 component of kexec for ia64. The generic component is a prerequsite for this patch. Signed-Off-By: Magnus Damm Signed-Off-By: Horms buildconfigs/linux-defconfig_xen0_ia64 | 3 linux-2.6-xen-sparse/arch/ia64/Kconfig | 23 linux-2.6-xen-sparse/arch/ia64/kernel/entry.S | 2 linux-2.6-xen-sparse/include/asm-ia64/hypercall.h | 7 linux-2.6-xen-sparse/include/asm-ia64/kexec-xen.h | 36 patches/linux-2.6.16.13/kexec-ia64-1.patch | 767 +++++++++++++++++++++ patches/linux-2.6.16.13/kexec-ia64-2.patch | 596 ++++++++++++++++ patches/linux-2.6.16.13/kexec-ia64-xen.patch | 266 +++++++ patches/linux-2.6.16.13/series | 3 xen/arch/ia64/asm-offsets.c | 2 xen/arch/ia64/linux-xen/smp.c | 32 xen/arch/ia64/xen/crash.c | 110 ++- xen/arch/ia64/xen/hypercall.c | 2 xen/arch/ia64/xen/machine_kexec.c | 60 + xen/include/asm-ia64/kexec.h | 62 + xen/include/asm-ia64/linux-xen/asm/smp.h | 9 xen/include/public/kexec.h | 3 17 files changed, 1965 insertions(+), 18 deletions(-) --- x/buildconfigs/linux-defconfig_xen0_ia64 +++ x/buildconfigs/linux-defconfig_xen0_ia64 @@ -138,6 +138,8 @@ CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_IA64_MCA_RECOVERY=y CONFIG_PERFMON=y CONFIG_IA64_PALINFO=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y # # Firmware Drivers @@ -1304,6 +1306,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # 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/ia64/Kconfig +++ x/linux-2.6-xen-sparse/arch/ia64/Kconfig @@ -390,6 +390,29 @@ config IA64_PALINFO config SGI_SN def_bool y if (IA64_SGI_SN2 || IA64_GENERIC) +config KEXEC + bool "kexec system call (EXPERIMENTAL)" + depends on EXPERIMENTAL + 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 + but it is indepedent of the system firmware. And like a reboot + you can start any kernel with it, not just Linux. + + The name comes from the similiarity to the exec system call. + + It is an ongoing process to be certain the hardware in a machine + is properly shutdown, so do not be surprised if this code does not + initially work for you. It may help to enable device hotplugging + support. As of this writing the exact hardware interface is + strongly in flux, so no good recommendation can be made. + +config CRASH_DUMP + bool "kernel crash dumps (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + Generate crash dump after being started by kexec. + source "drivers/firmware/Kconfig" source "fs/Kconfig.binfmt" --- x/linux-2.6-xen-sparse/arch/ia64/kernel/entry.S +++ x/linux-2.6-xen-sparse/arch/ia64/kernel/entry.S @@ -1596,7 +1596,7 @@ sys_call_table: data8 sys_mq_timedreceive // 1265 data8 sys_mq_notify data8 sys_mq_getsetattr - data8 sys_ni_syscall // reserved for kexec_load + data8 sys_kexec_load data8 sys_ni_syscall // reserved for vserver data8 sys_waitid // 1270 data8 sys_add_key --- x/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h +++ x/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h @@ -416,4 +416,11 @@ HYPERVISOR_add_physmap(unsigned long gpf // for balloon driver #define HYPERVISOR_update_va_mapping(va, new_val, flags) (0) +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__ */ --- /dev/null +++ x/linux-2.6-xen-sparse/include/asm-ia64/kexec-xen.h @@ -0,0 +1,36 @@ +/* + * include/asm-ia64/kexec-xen.h + * + * Created By: Horms + */ + +#ifndef _IA64_KEXEC_XEN_H +#define _IA64_KEXEC_XEN_H + +#include /* for printk() used in stub */ + +static inline void crash_translate_regs(struct pt_regs *linux_regs, + struct cpu_user_regs *xen_regs) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +/* Kexec needs to know about the actual physical addresss. + * But in xen, on some architectures, a physical address is a + * pseudo-physical addresss. */ +#define kexec_page_to_pfn(page) page_to_pfn(page) +#define kexec_pfn_to_page(pfn) pfn_to_page(pfn) +#define kexec_virt_to_phys(addr) virt_to_phys(addr) +#define kexec_phys_to_virt(addr) phys_to_virt(addr) + +#endif /* _IA64_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/xen/arch/ia64/asm-offsets.c +++ x/xen/arch/ia64/asm-offsets.c @@ -195,6 +195,8 @@ void foo(void) BLANK(); DEFINE(IA64_CPUINFO_NSEC_PER_CYC_OFFSET, offsetof (struct cpuinfo_ia64, nsec_per_cyc)); + DEFINE(IA64_CPUINFO_PTCE_BASE_OFFSET, offsetof (struct cpuinfo_ia64, ptce_base)); + DEFINE(IA64_CPUINFO_PTCE_COUNT_OFFSET, offsetof (struct cpuinfo_ia64, ptce_count)); DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET, offsetof (struct timespec, tv_nsec)); --- x/xen/arch/ia64/linux-xen/smp.c +++ x/xen/arch/ia64/linux-xen/smp.c @@ -113,6 +113,38 @@ unlock_ipi_calllock(void) spin_unlock_irq(&call_lock); } +#ifdef XEN +/* + * Stop the CPU and put it in fake SAL rendezvous. This allows CPU to wake + * up with IPI from boot processor + */ +void +kexec_stop_this_cpu (void *data) +{ + void *pal_addr; + struct kexec_stop_this_cpu_arg *arg = + (struct kexec_stop_this_cpu_arg *)data; + + if (pal_vaddr) + pal_addr = pal_vaddr; + else + pal_addr = efi_get_pal_addr(); + + /* + * Remove this CPU by putting it into fake SAL rendezvous + */ + cpu_clear(smp_processor_id(), cpu_online_map); + max_xtp(); + ia64_eoi(); + + /* Disable VHPT */ + ia64_disable_vhpt(); + + local_irq_disable(); + arg->fake_sal_rendez(arg->func, ap_wakeup_vector, pal_addr); +} +#endif + static void stop_this_cpu (void) { --- x/xen/arch/ia64/xen/crash.c +++ x/xen/arch/ia64/xen/crash.c @@ -1,17 +1,113 @@ -/********************************************************************** - * arch/ia64/xen/crash.c - * - * Created By: Horms +/****************************************************************************** + * arch/ia64/crash.c * + * Created By: Horms + * + * Based heavily on arch/ia64/kernel/crash.c from + * Tony Luck's ia64 test tree, circa Linux 2.6.17 */ -#include /* for printk() used in stub */ +#include +#include +#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void device_shootdown(void) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +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) +{ + uint64_t *buf; + ELF_Prstatus prstatus; + int cpu = smp_processor_id(); + ELF_Greg *dst = (ELF_Greg *)&prstatus.pr_reg; + + dst[1] = regs->r1; + dst[12] = regs->r12; + dst[13] = regs->r13; + + dst[42] = regs->cr_iip; + dst[45] = regs->ar_rsc; + + ia64_setreg(_IA64_REG_AR_RSC, 0); + ia64_srlz_i(); + + dst[46] = regs->r30; + dst[47] = regs->ar_bspstore; + + dst[48] = regs->ar_rnat; + dst[49] = regs->ar_ccv; + dst[50] = regs->ar_unat; + + dst[51] = regs->ar_fpsr; + dst[52] = regs->ar_pfs; + dst[53] = regs->r31; + + dst[54] = regs->r31; + dst[55] = regs->ar_csd; + dst[56] = regs->ar_ssd; + + buf = (uint64_t *) per_cpu(crash_notes, cpu); + if (!buf) + return; + buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, + sizeof(prstatus)); + final_note(buf); +} void machine_crash_shutdown(struct cpu_user_regs *regs) { - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); + printk("machine_crash_shutdown: %d\n", smp_processor_id()); + + if (in_interrupt()) { + ia64_eoi(); + } + crash_save_this_cpu(regs); + device_shootdown(); +#ifdef CONFIG_SMP + smp_send_stop(); +#endif + } /* --- x/xen/arch/ia64/xen/hypercall.c +++ x/xen/arch/ia64/xen/hypercall.c @@ -75,7 +75,7 @@ const hypercall_t ia64_hypercall_table[N (hypercall_t)do_hvm_op, /* */ (hypercall_t)do_sysctl, /* */ /* 35 */ (hypercall_t)do_domctl, /* */ - (hypercall_t)do_ni_hypercall, /* */ + (hypercall_t)do_kexec_op, /* */ /* 35 */ (hypercall_t)do_ni_hypercall, /* */ (hypercall_t)do_ni_hypercall, /* */ (hypercall_t)do_ni_hypercall, /* */ /* 40 */ --- x/xen/arch/ia64/xen/machine_kexec.c +++ x/xen/arch/ia64/xen/machine_kexec.c @@ -5,19 +5,32 @@ * */ +#include #include /* for printk() used in stubs */ #include +#include #include +#include +#include +#include + +typedef asmlinkage NORET_TYPE void (*relocate_new_kernel_t)( + unsigned long indirection_page, + unsigned long start_address, + struct ia64_boot_param *boot_param, + unsigned long pal_addr, + unsigned long cpu_data_pa, + unsigned long kernel_start, + unsigned long page_offset) + ATTRIB_NORET; int machine_kexec_load(int type, xen_kexec_image_t *image) { - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); - return -1; + return 0; } void machine_kexec_unload(int type, xen_kexec_image_t *image) { - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); } void machine_kexec_reserved(xen_kexec_reserve_t *reservation) @@ -27,12 +40,49 @@ void machine_kexec_reserved(xen_kexec_re void machine_kexec(xen_kexec_image_t *image) { - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); + relocate_new_kernel_t rnk; + void *pal_addr; + unsigned long code_addr = (unsigned long)__va(image->reboot_code_buffer); + unsigned long cpu_data_pa = (unsigned long) + __pa(cpu_data(smp_processor_id())); + + printk(__FILE__ ": %s: call unw_init_running()?\n", __FUNCTION__); + + if (pal_vaddr) + pal_addr = pal_vaddr; + else + pal_addr = efi_get_pal_addr(); + + /* Interrupts aren't acceptable while we reboot */ + ia64_set_itv(1<<16); + local_irq_disable(); + rnk = (relocate_new_kernel_t)&code_addr; + (*rnk)(image->indirection_page, image->start_address, ia64_boot_param, + GRANULEROUNDDOWN((unsigned long) pal_addr), + cpu_data_pa, KERNEL_START, PAGE_OFFSET); + BUG(); } +#ifdef CONFIG_SMP +static void machine_shutdown_smp(xen_kexec_image_t *image) +{ + struct kexec_stop_this_cpu_arg arg; + unsigned long code_addr = (unsigned long)__va(image->fake_sal_rendez); + + arg.func = (void *)image->start_address; + arg.fake_sal_rendez = (kexec_fake_sal_rendez_t)&code_addr; + smp_call_function(kexec_stop_this_cpu, (void *)&arg, 0, 0); +} +#else /* !CONFIG_SMP */ +static void machine_shutdown_smp(xen_kexec_image_t *image) { } +#endif /* CONFIG_SMP */ + + void machine_shutdown(xen_kexec_image_t *image) { - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); + printk(__FILE__ ": %s: need to shutdown pci devices\n", __FUNCTION__); + machine_shutdown_smp(image); + machine_kexec(image); } /* --- x/xen/include/asm-ia64/kexec.h +++ x/xen/include/asm-ia64/kexec.h @@ -6,16 +6,70 @@ */ #ifndef __IA64_KEXEC_H__ -#define __IA64_KEXEC_H__ -#include /* for printk() used in stub */ +#include +#include +#include +#include #include #include +#define pte_bits 3 +#define vmlpt_bits (impl_va_bits - PAGE_SHIFT + pte_bits) +#define POW2(n) (1ULL << (n)) + +DECLARE_PER_CPU(u64, ia64_mca_pal_base); +const extern unsigned int relocate_new_kernel_size; +volatile extern long kexec_rendez; +extern void relocate_new_kernel(unsigned long, unsigned long, + struct ia64_boot_param *, unsigned long); +extern void kexec_fake_sal_rendez(void *start, unsigned long wake_up, + unsigned long pal_base); + +/* + * Saving the registers of the cpu on which panic occured in + * crash_kexec to save a valid sp. The registers of other cpus + * will be saved in machine_crash_shutdown while shooting down them. + */ static void crash_setup_regs(struct cpu_user_regs *newregs, - struct cpu_user_regs *oldregs) + struct cpu_user_regs *oldregs) { - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); + if (oldregs) { + memcpy(newregs, oldregs, sizeof(*newregs)); + return; + } + + newregs->r1 = ia64_getreg(_IA64_REG_GP); + newregs->r12 = ia64_getreg(_IA64_REG_SP); + newregs->r13 = ia64_getreg(_IA64_REG_TP); + + newregs->cr_iip = ia64_getreg(_IA64_REG_IP); + newregs->ar_rsc = ia64_getreg(_IA64_REG_AR_RSC); + + ia64_setreg(_IA64_REG_AR_RSC, 0); + ia64_srlz_i(); + + /* struct cpu_user_regs does not have a ar_bsp element, + * so just use the otherwise unused r30 instead. + * This decision is arbiatry, r30 is not related to ar_bsp in + * any way */ + newregs->r30 = ia64_getreg(_IA64_REG_AR_BSP); + newregs->ar_bspstore = ia64_getreg(_IA64_REG_AR_BSPSTORE); + + newregs->ar_rnat = ia64_getreg(_IA64_REG_AR_RNAT); + newregs->ar_ccv = ia64_getreg(_IA64_REG_AR_CCV); + newregs->ar_unat = ia64_getreg(_IA64_REG_AR_UNAT); + + newregs->ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR); + newregs->ar_pfs = ia64_getreg(_IA64_REG_AR_PFS); + + /* struct cpu_user_regs does not have a ar_lc element, + * so just use the otherwise unused r31 instead. + * This decision is arbiatry, r31 is not related to ar_lc in + * any way */ + newregs->r31 = ia64_getreg(_IA64_REG_AR_LC); + newregs->ar_csd = ia64_getreg(_IA64_REG_AR_CSD); + newregs->ar_ssd = ia64_getreg(_IA64_REG_AR_SSD); } #endif /* __IA64_KEXEC_H__ */ --- x/xen/include/asm-ia64/linux-xen/asm/smp.h +++ x/xen/include/asm-ia64/linux-xen/asm/smp.h @@ -133,6 +133,15 @@ extern void smp_send_reschedule (int cpu extern void lock_ipi_calllock(void); extern void unlock_ipi_calllock(void); extern void identify_siblings (struct cpuinfo_ia64 *); +#ifdef XEN +typedef void (*kexec_fake_sal_rendez_t) (void *start, unsigned long wake_up, + unsigned long pal_base); +struct kexec_stop_this_cpu_arg { + void *func; + kexec_fake_sal_rendez_t fake_sal_rendez; +}; +extern void kexec_stop_this_cpu(void *data); +#endif /* XEN */ #else --- x/xen/include/public/kexec.h +++ x/xen/include/public/kexec.h @@ -49,6 +49,9 @@ typedef struct xen_kexec_image { #if defined(__x86_64__) unsigned long page_table_b; #endif +#if defined(__ia64__) + unsigned long fake_sal_rendez; +#endif unsigned long indirection_page; unsigned long reboot_code_buffer; unsigned long start_address; --- x/patches/linux-2.6.16.13/series +++ x/patches/linux-2.6.16.13/series @@ -4,6 +4,9 @@ linux-2.6.16-kexec_page_table_a_i386.pat linux-2.6.16-kexec_page_table_a_i386-xen.patch linux-2.6.16-kexec_page_table_a_x86_64.patch linux-2.6.16-kexec_page_table_a_x86_64-xen.patch +kexec-ia64-1.patch +kexec-ia64-2.patch +kexec-ia64-xen.patch blktap-aio-16_03_06.patch device_bind.patch fix-hz-suspend.patch --- /dev/null +++ x/patches/linux-2.6.16.13/kexec-ia64-1.patch @@ -0,0 +1,767 @@ +commit b373e385743597f576b67c423807bbdfe3b862e7 +tree c1e50c5f8f38e934cd3595fe9cb01b06549b4fac +parent 3cd73eedde34c5fd88d62d8523c4260970fdc6fb +author Khalid Aziz 1147215202 -0700 +committer Tony Luck 1147215202 -0700 + +[IA64] kexec for ia64 + +Enable kexec for ia64. + +Signed-off-by: Khalid Aziz +Signed-off-by: Nanhai Zou +Signed-off-by: Tony Luck + +This patch is from Tony Luck's ia64 test git tree circa 2.6.17. +It has been rediffed and trivially backported to xen 2.6.16.3 + +Signed-Off-By: Magnus Damm +Signed-Off-By: Horms + + arch/ia64/Kconfig | 17 + + arch/ia64/hp/common/sba_iommu.c | 22 ++ + arch/ia64/kernel/Makefile | 1 + arch/ia64/kernel/crash.c | 43 ++++ + arch/ia64/kernel/entry.S | 2 + arch/ia64/kernel/machine_kexec.c | 140 ++++++++++++++ + arch/ia64/kernel/relocate_kernel.S | 359 ++++++++++++++++++++++++++++++++++++ + arch/ia64/kernel/smp.c | 29 ++ + include/asm-ia64/kexec.h | 36 +++ + include/asm-ia64/machvec_hpzx1.h | 2 + include/asm-ia64/smp.h | 3 + 11 files changed, 653 insertions(+), 1 deletion(-) + +--- x/arch/ia64/Kconfig ++++ x/arch/ia64/Kconfig +@@ -376,6 +376,23 @@ config IA64_PALINFO + config SGI_SN + def_bool y if (IA64_SGI_SN2 || IA64_GENERIC) + ++config KEXEC ++ bool "kexec system call (EXPERIMENTAL)" ++ depends on EXPERIMENTAL ++ 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 ++ but it is indepedent of the system firmware. And like a reboot ++ you can start any kernel with it, not just Linux. ++ ++ The name comes from the similiarity to the exec system call. ++ ++ It is an ongoing process to be certain the hardware in a machine ++ is properly shutdown, so do not be surprised if this code does not ++ initially work for you. It may help to enable device hotplugging ++ support. As of this writing the exact hardware interface is ++ strongly in flux, so no good recommendation can be made. ++ + source "drivers/firmware/Kconfig" + + source "fs/Kconfig.binfmt" +--- x/arch/ia64/hp/common/sba_iommu.c ++++ x/arch/ia64/hp/common/sba_iommu.c +@@ -1624,6 +1624,28 @@ ioc_iova_init(struct ioc *ioc) + READ_REG(ioc->ioc_hpa + IOC_IBASE); + } + ++#ifdef CONFIG_KEXEC ++void ++ioc_iova_disable(void) ++{ ++ struct ioc *ioc; ++ ++ ioc = ioc_list; ++ ++ while (ioc != NULL) { ++ /* Disable IOVA translation */ ++ WRITE_REG(ioc->ibase & 0xfffffffffffffffe, ioc->ioc_hpa + IOC_IBASE); ++ READ_REG(ioc->ioc_hpa + IOC_IBASE); ++ ++ /* Clear I/O TLB of any possible entries */ ++ WRITE_REG(ioc->ibase | (get_iovp_order(ioc->iov_size) + iovp_shift), ioc->ioc_hpa + IOC_PCOM); ++ READ_REG(ioc->ioc_hpa + IOC_PCOM); ++ ++ ioc = ioc->next; ++ } ++} ++#endif ++ + static void __init + ioc_resource_init(struct ioc *ioc) + { +--- x/arch/ia64/kernel/Makefile ++++ x/arch/ia64/kernel/Makefile +@@ -28,6 +28,7 @@ obj-$(CONFIG_IA64_CYCLONE) += cyclone.o + obj-$(CONFIG_CPU_FREQ) += cpufreq/ + obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o + obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o ++obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o + obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o + mca_recovery-y += mca_drv.o mca_drv_asm.o + +--- x//dev/null ++++ x/arch/ia64/kernel/crash.c +@@ -0,0 +1,43 @@ ++/* ++ * arch/ia64/kernel/crash.c ++ * ++ * Architecture specific (ia64) functions for kexec based crash dumps. ++ * ++ * Created by: Khalid Aziz ++ * ++ * Copyright (C) 2005 Hewlett-Packard Development Company, L.P. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++void ++machine_crash_shutdown(struct pt_regs *pt) ++{ ++ /* This function is only called after the system ++ * has paniced or is otherwise in a critical state. ++ * The minimum amount of code to allow a kexec'd kernel ++ * to run successfully needs to happen here. ++ * ++ * In practice this means shooting down the other cpus in ++ * an SMP system. ++ */ ++ if (in_interrupt()) ++ ia64_eoi(); ++#ifdef CONFIG_SMP ++ smp_send_stop(); ++#endif ++#ifdef CONFIG_IA64_HP_ZX1 ++ ioc_iova_disable(); ++#endif ++} +--- x/arch/ia64/kernel/entry.S ++++ x/arch/ia64/kernel/entry.S +@@ -1590,7 +1590,7 @@ sys_call_table: + data8 sys_mq_timedreceive // 1265 + data8 sys_mq_notify + data8 sys_mq_getsetattr +- data8 sys_ni_syscall // reserved for kexec_load ++ data8 sys_kexec_load + data8 sys_ni_syscall // reserved for vserver + data8 sys_waitid // 1270 + data8 sys_add_key +--- x//dev/null ++++ x/arch/ia64/kernel/machine_kexec.c +@@ -0,0 +1,140 @@ ++/* ++ * arch/ia64/kernel/machine_kexec.c ++ * ++ * Handle transition of Linux booting another kernel ++ * Copyright (C) 2005 Hewlett-Packard Development Comapny, L.P. ++ * Copyright (C) 2005 Khalid Aziz ++ * Copyright (C) 2006 Intel Corp, Zou Nan hai ++ * ++ * This source code is licensed under the GNU General Public License, ++ * Version 2. See the file COPYING for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++extern unsigned long ia64_iobase; ++ ++typedef void (*relocate_new_kernel_t)( unsigned long, unsigned long, ++ struct ia64_boot_param *, unsigned long); ++ ++/* ++ * Do what every setup is needed on image and the ++ * reboot code buffer to allow us to avoid allocations ++ * later. ++ */ ++int machine_kexec_prepare(struct kimage *image) ++{ ++ void *control_code_buffer; ++ const unsigned long *func; ++ ++ func = (unsigned long *)&relocate_new_kernel; ++ /* Pre-load control code buffer to minimize work in kexec path */ ++ control_code_buffer = page_address(image->control_code_page); ++ memcpy((void *)control_code_buffer, (const void *)func[0], ++ relocate_new_kernel_size); ++ flush_icache_range((unsigned long)control_code_buffer, ++ (unsigned long)control_code_buffer + relocate_new_kernel_size); ++ ++ return 0; ++} ++ ++void machine_kexec_cleanup(struct kimage *image) ++{ ++} ++ ++void machine_shutdown(void) ++{ ++#ifdef CONFIG_PCI ++ struct pci_dev *dev = NULL; ++ irq_desc_t *idesc; ++ cpumask_t mask = CPU_MASK_NONE; ++ ++ /* Disable all PCI devices */ ++ while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { ++ if (!(dev->is_enabled)) ++ continue; ++ idesc = irq_descp(dev->irq); ++ if (!idesc) ++ continue; ++ cpu_set(0, mask); ++ disable_irq_nosync(dev->irq); ++ idesc->handler->end(dev->irq); ++ idesc->handler->set_affinity(dev->irq, mask); ++ idesc->action = NULL; ++ pci_disable_device(dev); ++ } ++#endif ++ ++#ifdef CONFIG_HOTPLUG_CPU ++ { ++ int cpu; ++ ++ for_each_online_cpu(cpu) { ++ if (cpu != smp_processor_id()) ++ cpu_down(cpu); ++ } ++ } ++#elif defined(CONFIG_SMP) ++ smp_call_function(kexec_stop_this_cpu, (void *)image->start, 0, 0); ++#endif ++ ++ ia64_set_itv(1<<16); ++ ++#ifdef CONFIG_IA64_HP_ZX1 ++ ioc_iova_disable(); ++#endif ++} ++ ++/* ++ * Do not allocate memory (or fail in any way) in machine_kexec(). ++ * We are past the point of no return, committed to rebooting now. ++ */ ++void machine_kexec(struct kimage *image) ++{ ++ unsigned long indirection_page; ++ relocate_new_kernel_t rnk; ++ unsigned long pta, impl_va_bits; ++ void *pal_addr = efi_get_pal_addr(); ++ unsigned long code_addr = (unsigned long)page_address(image->control_code_page); ++ ++ /* Interrupts aren't acceptable while we reboot */ ++ local_irq_disable(); ++ ++ /* Disable VHPT */ ++ impl_va_bits = ffz(~(local_cpu_data->unimpl_va_mask | (7UL << 61))); ++ pta = POW2(61) - POW2(vmlpt_bits); ++ ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | 0); ++ ++ /* now execute the control code. ++ * We will start by executing the control code linked into the ++ * kernel as opposed to the code we copied in control code buffer * page. When this code switches to physical mode, we will start ++ * executing the code in control code buffer page. Reason for ++ * doing this is we start code execution in virtual address space. ++ * If we were to try to execute the newly copied code in virtual ++ * address space, we will need to make an ITLB entry to avoid ITLB ++ * miss. By executing the code linked into kernel, we take advantage ++ * of the ITLB entry already in place for kernel and avoid making ++ * a new entry. ++ */ ++ indirection_page = image->head & PAGE_MASK; ++ ++ rnk = (relocate_new_kernel_t)&code_addr; ++ (*rnk)(indirection_page, image->start, ia64_boot_param, ++ GRANULEROUNDDOWN((unsigned long) pal_addr)); ++ BUG(); ++ for (;;) ++ ; ++} +--- x//dev/null ++++ x/arch/ia64/kernel/relocate_kernel.S +@@ -0,0 +1,359 @@ ++/* ++ * arch/ia64/kernel/relocate_kernel.S ++ * ++ * Relocate kexec'able kernel and start it ++ * ++ * Copyright (C) 2005 Hewlett-Packard Development Company, L.P. ++ * Copyright (C) 2005 Khalid Aziz ++ * Copyright (C) 2005 Intel Corp, Zou Nan hai ++ * ++ * This source code is licensed under the GNU General Public License, ++ * Version 2. See the file COPYING for more details. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ /* Must be relocatable PIC code callable as a C function, that once ++ * it starts can not use the previous processes stack. ++ * ++ */ ++GLOBAL_ENTRY(relocate_new_kernel) ++ .prologue ++ alloc r31=ar.pfs,4,0,0,0 ++ .body ++.reloc_entry: ++{ ++ rsm psr.i| psr.ic ++ mov r2=ip ++} ++ ;; ++{ ++ flushrs // must be first insn in group ++ srlz.i ++} ++ ;; ++ ++ //first switch to physical mode ++ add r3=1f-.reloc_entry, r2 ++ movl r16 = IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_IC|IA64_PSR_MFL ++ mov ar.rsc=0 // put RSE in enforced lazy mode ++ ;; ++ add r2=(memory_stack-.reloc_entry), r2 ++ ;; ++ add sp=(memory_stack_end - .reloc_entry),r2 ++ add r8=(register_stack - .reloc_entry),r2 ++ ;; ++ tpa sp=sp ++ tpa r3=r3 ++ ;; ++ loadrs ++ ;; ++ mov r18=ar.rnat ++ mov ar.bspstore=r8 ++ ;; ++ mov cr.ipsr=r16 ++ mov cr.iip=r3 ++ mov cr.ifs=r0 ++ srlz.i ++ ;; ++ mov ar.rnat=r18 ++ rfi ++ ;; ++1: ++ //physical mode code begin ++ mov b6=in1 ++ tpa r28=in2 // tpa must before TLB purge ++ ++ // purge all TC entries ++#define O(member) IA64_CPUINFO_##member##_OFFSET ++ GET_THIS_PADDR(r2, cpu_info) // load phys addr of cpu_info into r2 ++ ;; ++ addl r17=O(PTCE_STRIDE),r2 ++ addl r2=O(PTCE_BASE),r2 ++ ;; ++ ld8 r18=[r2],(O(PTCE_COUNT)-O(PTCE_BASE));; // r18=ptce_base ++ ld4 r19=[r2],4 // r19=ptce_count[0] ++ ld4 r21=[r17],4 // r21=ptce_stride[0] ++ ;; ++ ld4 r20=[r2] // r20=ptce_count[1] ++ ld4 r22=[r17] // r22=ptce_stride[1] ++ mov r24=r0 ++ ;; ++ adds r20=-1,r20 ++ ;; ++#undef O ++2: ++ cmp.ltu p6,p7=r24,r19 ++(p7) br.cond.dpnt.few 4f ++ mov ar.lc=r20 ++3: ++ ptc.e r18 ++ ;; ++ add r18=r22,r18 ++ br.cloop.sptk.few 3b ++ ;; ++ add r18=r21,r18 ++ add r24=1,r24 ++ ;; ++ br.sptk.few 2b ++4: ++ srlz.i ++ ;; ++ //purge TR entry for kernel text and data ++ movl r16=KERNEL_START ++ mov r18=KERNEL_TR_PAGE_SHIFT<<2 ++ ;; ++ ptr.i r16, r18 ++ ptr.d r16, r18 ++ ;; ++ srlz.i ++ ;; ++ ++ // purge TR entry for percpu data ++ movl r16=PERCPU_ADDR ++ mov r18=PERCPU_PAGE_SHIFT<<2 ++ ;; ++ ptr.d r16,r18 ++ ;; ++ srlz.d ++ ;; ++ ++ // purge TR entry for pal code ++ mov r16=in3 ++ mov r18=IA64_GRANULE_SHIFT<<2 ++ ;; ++ ptr.i r16,r18 ++ ;; ++ srlz.i ++ ;; ++ ++ // purge TR entry for stack ++ mov r16=IA64_KR(CURRENT_STACK) ++ ;; ++ shl r16=r16,IA64_GRANULE_SHIFT ++ movl r19=PAGE_OFFSET ++ ;; ++ add r16=r19,r16 ++ mov r18=IA64_GRANULE_SHIFT<<2 ++ ;; ++ ptr.d r16,r18 ++ ;; ++ srlz.i ++ ;; ++ ++ // copy kexec kernel segments ++ movl r16=PAGE_MASK ++ ld8 r30=[in0],8;; // in0 is page_list ++ br.sptk.few .dest_page ++ ;; ++.loop: ++ ld8 r30=[in0], 8;; ++.dest_page: ++ tbit.z p0, p6=r30, 0;; // 0x1 dest page ++(p6) and r17=r30, r16 ++(p6) br.cond.sptk.few .loop;; ++ ++ tbit.z p0, p6=r30, 1;; // 0x2 indirect page ++(p6) and in0=r30, r16 ++(p6) br.cond.sptk.few .loop;; ++ ++ tbit.z p0, p6=r30, 2;; // 0x4 end flag ++(p6) br.cond.sptk.few .end_loop;; ++ ++ tbit.z p6, p0=r30, 3;; // 0x8 source page ++(p6) br.cond.sptk.few .loop ++ ++ and r18=r30, r16 ++ ++ // simple copy page, may optimize later ++ movl r14=PAGE_SIZE/8 - 1;; ++ mov ar.lc=r14;; ++1: ++ ld8 r14=[r18], 8;; ++ st8 [r17]=r14, 8;; ++ fc.i r17 ++ br.ctop.sptk.few 1b ++ br.sptk.few .loop ++ ;; ++ ++.end_loop: ++ sync.i // for fc.i ++ ;; ++ srlz.i ++ ;; ++ srlz.d ++ ;; ++ br.call.sptk.many b0=b6;; ++memory_stack: ++ .fill 8192, 1, 0 ++memory_stack_end: ++register_stack: ++ .fill 8192, 1, 0 ++register_stack_end: ++relocate_new_kernel_end: ++END(relocate_new_kernel) ++ ++GLOBAL_ENTRY(kexec_fake_sal_rendez) ++ .prologue ++ alloc r31=ar.pfs,3,0,0,0 ++ .body ++.rendez_entry: ++ rsm psr.i | psr.ic ++ mov r25=ip ++ ;; ++ { ++ flushrs ++ srlz.i ++ } ++ ;; ++ /* See where I am running, and compute gp */ ++ { ++ mov ar.rsc = 0 /* Put RSE in enforce lacy, LE mode */ ++ mov gp = ip /* gp == relocate_new_kernel */ ++ } ++ ++ movl r8=0x00000100000000 ++ ;; ++ mov cr.iva=r8 ++ /* Transition from virtual to physical mode */ ++ srlz.i ++ ;; ++ add r17=5f-.rendez_entry, r25 ++ movl r16=(IA64_PSR_AC | IA64_PSR_BN | IA64_PSR_IC | IA64_PSR_MFL) ++ ;; ++ tpa r17=r17 ++ mov cr.ipsr=r16 ++ ;; ++ mov cr.iip=r17 ++ mov cr.ifs=r0 ++ ;; ++ rfi ++ ;; ++5: ++ mov b6=in0 /* _start addr */ ++ mov r8=in1 /* ap_wakeup_vector */ ++ mov r26=in2 /* PAL addr */ ++ ;; ++ /* Purge kernel TRs */ ++ movl r16=KERNEL_START ++ mov r18=KERNEL_TR_PAGE_SHIFT<<2 ++ ;; ++ ptr.i r16,r18 ++ ptr.d r16,r18 ++ ;; ++ srlz.i ++ ;; ++ srlz.d ++ ;; ++ /* Purge percpu TR */ ++ movl r16=PERCPU_ADDR ++ mov r18=PERCPU_PAGE_SHIFT<<2 ++ ;; ++ ptr.d r16,r18 ++ ;; ++ srlz.d ++ ;; ++ /* Purge PAL TR */ ++ mov r18=IA64_GRANULE_SHIFT<<2 ++ ;; ++ ptr.i r26,r18 ++ ;; ++ srlz.i ++ ;; ++ /* Purge stack TR */ ++ mov r16=IA64_KR(CURRENT_STACK) ++ ;; ++ shl r16=r16,IA64_GRANULE_SHIFT ++ movl r19=PAGE_OFFSET ++ ;; ++ add r16=r19,r16 ++ mov r18=IA64_GRANULE_SHIFT<<2 ++ ;; ++ ptr.d r16,r18 ++ ;; ++ srlz.i ++ ;; ++ ++ /* Ensure we can read and clear external interrupts */ ++ mov cr.tpr=r0 ++ srlz.d ++ ++ shr.u r9=r8,6 /* which irr */ ++ ;; ++ and r8=63,r8 /* bit offset into irr */ ++ ;; ++ mov r10=1;; ++ ;; ++ shl r10=r10,r8 /* bit mask off irr we want */ ++ cmp.eq p6,p0=0,r9 ++ ;; ++(p6) br.cond.sptk.few check_irr0 ++ cmp.eq p7,p0=1,r9 ++ ;; ++(p7) br.cond.sptk.few check_irr1 ++ cmp.eq p8,p0=2,r9 ++ ;; ++(p8) br.cond.sptk.few check_irr2 ++ cmp.eq p9,p0=3,r9 ++ ;; ++(p9) br.cond.sptk.few check_irr3 ++ ++check_irr0: ++ mov r8=cr.irr0 ++ ;; ++ and r8=r8,r10 ++ ;; ++ cmp.eq p6,p0=0,r8 ++(p6) br.cond.sptk.few check_irr0 ++ br.few call_start ++ ++check_irr1: ++ mov r8=cr.irr1 ++ ;; ++ and r8=r8,r10 ++ ;; ++ cmp.eq p6,p0=0,r8 ++(p6) br.cond.sptk.few check_irr1 ++ br.few call_start ++ ++check_irr2: ++ mov r8=cr.irr2 ++ ;; ++ and r8=r8,r10 ++ ;; ++ cmp.eq p6,p0=0,r8 ++(p6) br.cond.sptk.few check_irr2 ++ br.few call_start ++ ++check_irr3: ++ mov r8=cr.irr3 ++ ;; ++ and r8=r8,r10 ++ ;; ++ cmp.eq p6,p0=0,r8 ++(p6) br.cond.sptk.few check_irr3 ++ br.few call_start ++ ++call_start: ++ mov cr.eoi=r0 ++ ;; ++ srlz.d ++ ;; ++ mov r8=cr.ivr ++ ;; ++ srlz.d ++ ;; ++ cmp.eq p0,p6=15,r8 ++(p6) br.cond.sptk.few call_start ++ br.sptk.few b6 ++kexec_fake_sal_rendez_end: ++END(kexec_fake_sal_rendez) ++ ++ .global relocate_new_kernel_size ++relocate_new_kernel_size: ++ data8 kexec_fake_sal_rendez_end - relocate_new_kernel ++ +--- x/arch/ia64/kernel/smp.c ++++ x/arch/ia64/kernel/smp.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -84,6 +85,34 @@ unlock_ipi_calllock(void) + spin_unlock_irq(&call_lock); + } + ++#ifdef CONFIG_KEXEC ++/* ++ * Stop the CPU and put it in fake SAL rendezvous. This allows CPU to wake ++ * up with IPI from boot processor ++ */ ++void ++kexec_stop_this_cpu (void *func) ++{ ++ unsigned long pta, impl_va_bits, pal_base; ++ ++ /* ++ * Remove this CPU by putting it into fake SAL rendezvous ++ */ ++ cpu_clear(smp_processor_id(), cpu_online_map); ++ max_xtp(); ++ ia64_eoi(); ++ ++ /* Disable VHPT */ ++ impl_va_bits = ffz(~(local_cpu_data->unimpl_va_mask | (7UL << 61))); ++ pta = POW2(61) - POW2(vmlpt_bits); ++ ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | 0); ++ ++ local_irq_disable(); ++ pal_base = __get_cpu_var(ia64_mca_pal_base); ++ kexec_fake_sal_rendez(func, ap_wakeup_vector, pal_base); ++} ++#endif ++ + static void + stop_this_cpu (void) + { +--- x//dev/null ++++ x/include/asm-ia64/kexec.h +@@ -0,0 +1,36 @@ ++#ifndef _ASM_IA64_KEXEC_H ++#define _ASM_IA64_KEXEC_H ++ ++ ++/* Maximum physical address we can use pages from */ ++#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) ++/* Maximum address we can reach in physical address mode */ ++#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) ++/* Maximum address we can use for the control code buffer */ ++#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE ++ ++#define KEXEC_CONTROL_CODE_SIZE (8192 + 8192 + 4096) ++ ++/* The native architecture */ ++#define KEXEC_ARCH KEXEC_ARCH_IA_64 ++ ++#define MAX_NOTE_BYTES 1024 ++ ++#define pte_bits 3 ++#define vmlpt_bits (impl_va_bits - PAGE_SHIFT + pte_bits) ++#define POW2(n) (1ULL << (n)) ++ ++DECLARE_PER_CPU(u64, ia64_mca_pal_base); ++ ++const extern unsigned int relocate_new_kernel_size; ++volatile extern long kexec_rendez; ++extern void relocate_new_kernel(unsigned long, unsigned long, ++ struct ia64_boot_param *, unsigned long); ++extern void kexec_fake_sal_rendez(void *start, unsigned long wake_up, ++ unsigned long pal_base); ++ ++static inline void ++crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs) ++{ ++} ++#endif /* _ASM_IA64_KEXEC_H */ +--- x/include/asm-ia64/machvec_hpzx1.h ++++ x/include/asm-ia64/machvec_hpzx1.h +@@ -34,4 +34,6 @@ extern ia64_mv_dma_mapping_error sba_dma + #define platform_dma_supported sba_dma_supported + #define platform_dma_mapping_error sba_dma_mapping_error + ++extern void ioc_iova_disable(void); ++ + #endif /* _ASM_IA64_MACHVEC_HPZX1_h */ +--- x/include/asm-ia64/smp.h ++++ x/include/asm-ia64/smp.h +@@ -129,6 +129,9 @@ extern void smp_send_reschedule (int cpu + extern void lock_ipi_calllock(void); + extern void unlock_ipi_calllock(void); + extern void identify_siblings (struct cpuinfo_ia64 *); ++#ifdef CONFIG_KEXEC ++extern void kexec_stop_this_cpu(void *); ++#endif + + #else + --- /dev/null +++ x/patches/linux-2.6.16.13/kexec-ia64-2.patch @@ -0,0 +1,596 @@ +commit beada884dd437b509c26b39f1a0b0c6b31e6f340 +tree ad7608f34ca8aa9e292e2a863484b3e13250107d +parent b373e385743597f576b67c423807bbdfe3b862e7 +author Zou Nan hai 1150320804 -0700 +committer Tony Luck 1150320804 -0700 + +[IA64] Miscellaneous updates for kexec/kdump + +Signed-off-by: Zou Nan hai + +This patch is from Tony Luck's ia64 test git tree circa 2.6.17. +It has been rediffed and trivially backported to xen 2.6.16.3 + +Signed-Off-By: Magnus Damm +Signed-Off-By: Horms + + arch/ia64/Kconfig | 6 + + arch/ia64/kernel/crash.c | 113 +++++++++++++++++++++++++++++++++++- + arch/ia64/kernel/efi.c | 17 ++++- + arch/ia64/kernel/machine_kexec.c | 43 ++----------- + arch/ia64/kernel/relocate_kernel.S | 38 +++++------- + arch/ia64/kernel/setup.c | 38 ++++++++++++ + include/asm-ia64/kexec.h | 4 - + include/asm-ia64/meminit.h | 3 + include/linux/irq.h | 1 + kernel/irq/manage.c | 19 ++++++ + 10 files changed, 217 insertions(+), 65 deletions(-) + +--- x/arch/ia64/Kconfig ++++ x/arch/ia64/Kconfig +@@ -437,6 +437,12 @@ config KEXEC + support. As of this writing the exact hardware interface is + strongly in flux, so no good recommendation can be made. + ++config CRASH_DUMP ++ bool "kernel crash dumps (EXPERIMENTAL)" ++ depends on EXPERIMENTAL ++ help ++ Generate crash dump after being started by kexec. ++ + source "net/Kconfig" + + source "drivers/Kconfig" +--- x/arch/ia64/kernel/crash.c ++++ x/arch/ia64/kernel/crash.c +@@ -4,8 +4,8 @@ + * Architecture specific (ia64) functions for kexec based crash dumps. + * + * Created by: Khalid Aziz +- * + * Copyright (C) 2005 Hewlett-Packard Development Company, L.P. ++ * Copyright (C) 2005 Intel Corp Zou Nan hai + * + */ + #include +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -20,6 +21,111 @@ + #include + #include + #include ++#include ++ ++size_t copy_oldmem_page(unsigned long pfn, char *buf, ++ size_t csize, unsigned long offset, int userbuf) ++{ ++ void *vaddr; ++ ++ if (!csize) ++ return 0; ++ vaddr = page_address(pfn_to_page(pfn)); ++ ++ if (userbuf) { ++ if (copy_to_user(buf, (vaddr + offset), csize)) { ++ return -EFAULT; ++ } ++ } else ++ memcpy(buf, (vaddr + offset), csize); ++ return csize; ++} ++ ++static void device_shootdown(void) ++{ ++ struct pci_dev *dev; ++ irq_desc_t *desc; ++ u16 pci_command; ++ ++ list_for_each_entry(dev, &pci_devices, global_list) { ++ desc = irq_descp(dev->irq); ++ if (!desc->action) ++ continue; ++ pci_read_config_word(dev, PCI_COMMAND, &pci_command); ++ if (pci_command & PCI_COMMAND_MASTER) { ++ pci_command &= ~PCI_COMMAND_MASTER; ++ pci_write_config_word(dev, PCI_COMMAND, pci_command); ++ } ++ disable_irq_nosync(dev->irq); ++ desc->handler->end(dev->irq); ++ } ++} ++ ++static Elf64_Word ++*append_elf_note(Elf64_Word *buf, char *name, unsigned type, void *data, ++ size_t data_len) ++{ ++ struct elf_note *note = (struct elf_note *)buf; ++ note->n_namesz = strlen(name) + 1; ++ note->n_descsz = data_len; ++ note->n_type = type; ++ buf += (sizeof(*note) + 3)/4; ++ memcpy(buf, name, note->n_namesz); ++ buf += (note->n_namesz + 3)/4; ++ memcpy(buf, data, data_len); ++ buf += (data_len + 3)/4; ++ return buf; ++} ++ ++static void ++final_note(void *buf) ++{ ++ memset(buf, 0, sizeof(struct elf_note)); ++} ++ ++static void ++crash_save_this_cpu(void) ++{ ++ void *buf; ++ struct elf_prstatus prstatus; ++ int cpu = smp_processor_id(); ++ elf_greg_t *dst = (elf_greg_t *)&prstatus.pr_reg; ++ ++ memset(&prstatus, 0, sizeof(prstatus)); ++ prstatus.pr_pid = current->pid; ++ ++ dst[1] = ia64_getreg(_IA64_REG_GP); ++ dst[12] = ia64_getreg(_IA64_REG_SP); ++ dst[13] = ia64_getreg(_IA64_REG_TP); ++ ++ dst[42] = ia64_getreg(_IA64_REG_IP); ++ dst[45] = ia64_getreg(_IA64_REG_AR_RSC); ++ ++ ia64_setreg(_IA64_REG_AR_RSC, 0); ++ ia64_srlz_i(); ++ ++ dst[46] = ia64_getreg(_IA64_REG_AR_BSP); ++ dst[47] = ia64_getreg(_IA64_REG_AR_BSPSTORE); ++ ++ dst[48] = ia64_getreg(_IA64_REG_AR_RNAT); ++ dst[49] = ia64_getreg(_IA64_REG_AR_CCV); ++ dst[50] = ia64_getreg(_IA64_REG_AR_UNAT); ++ ++ dst[51] = ia64_getreg(_IA64_REG_AR_FPSR); ++ dst[52] = ia64_getreg(_IA64_REG_AR_PFS); ++ dst[53] = ia64_getreg(_IA64_REG_AR_LC); ++ ++ dst[54] = ia64_getreg(_IA64_REG_AR_LC); ++ dst[55] = ia64_getreg(_IA64_REG_AR_CSD); ++ dst[56] = ia64_getreg(_IA64_REG_AR_SSD); ++ ++ buf = (u64 *) per_cpu_ptr(crash_notes, cpu); ++ if (!buf) ++ return; ++ buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, ++ sizeof(prstatus)); ++ final_note(buf); ++} + + void + machine_crash_shutdown(struct pt_regs *pt) +@@ -32,8 +138,11 @@ machine_crash_shutdown(struct pt_regs *p + * In practice this means shooting down the other cpus in + * an SMP system. + */ +- if (in_interrupt()) ++ if (in_interrupt()) { + ia64_eoi(); ++ } ++ crash_save_this_cpu(); ++ device_shootdown(); + #ifdef CONFIG_SMP + smp_send_stop(); + #endif +--- x/arch/ia64/kernel/efi.c ++++ x/arch/ia64/kernel/efi.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -40,7 +41,7 @@ extern efi_status_t efi_call_phys (void + struct efi efi; + EXPORT_SYMBOL(efi); + static efi_runtime_services_t *runtime; +-static unsigned long mem_limit = ~0UL, max_addr = ~0UL; ++static unsigned long mem_limit = ~0UL, max_addr = ~0UL, min_addr = 0UL; + + #define efi_call_virt(f, args...) (*(f))(args) + +@@ -420,6 +421,8 @@ efi_init (void) + mem_limit = memparse(cp + 4, &cp); + } else if (memcmp(cp, "max_addr=", 9) == 0) { + max_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp)); ++ } else if (memcmp(cp, "min_addr=", 9) == 0) { ++ min_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp)); + } else { + while (*cp != ' ' && *cp) + ++cp; +@@ -427,6 +430,8 @@ efi_init (void) + ++cp; + } + } ++ if (min_addr != 0UL) ++ printk(KERN_INFO "Ignoring memory below %luMB\n", min_addr >> 20); + if (max_addr != ~0UL) + printk(KERN_INFO "Ignoring memory above %luMB\n", max_addr >> 20); + +@@ -839,7 +844,8 @@ find_memmap_space (void) + as = max(contig_low, md->phys_addr); + ae = min(contig_high, efi_md_end(md)); + +- /* keep within max_addr= command line arg */ ++ /* keep within max_addr= and min_addr= command line arg */ ++ as = max(as, min_addr); + ae = min(ae, max_addr); + if (ae <= as) + continue; +@@ -949,7 +955,8 @@ efi_memmap_init(unsigned long *s, unsign + } else + ae = efi_md_end(md); + +- /* keep within max_addr= command line arg */ ++ /* keep within max_addr= and min_addr= command line arg */ ++ as = max(as, min_addr); + ae = min(ae, max_addr); + if (ae <= as) + continue; +@@ -1061,6 +1068,10 @@ efi_initialize_iomem_resources(struct re + */ + insert_resource(res, code_resource); + insert_resource(res, data_resource); ++#ifdef CONFIG_KEXEC ++ if (crashk_res.end > crashk_res.start) ++ insert_resource(res, &crashk_res); ++#endif + } + } + } +--- x/arch/ia64/kernel/machine_kexec.c ++++ x/arch/ia64/kernel/machine_kexec.c +@@ -1,5 +1,5 @@ + /* +- * arch/ia64/kernel/machine_kexec.c ++ * arch/ia64/kernel/machine_kexec.c + * + * Handle transition of Linux booting another kernel + * Copyright (C) 2005 Hewlett-Packard Development Comapny, L.P. +@@ -25,9 +25,7 @@ + #include + #include + +-extern unsigned long ia64_iobase; +- +-typedef void (*relocate_new_kernel_t)( unsigned long, unsigned long, ++typedef void (*relocate_new_kernel_t)(unsigned long, unsigned long, + struct ia64_boot_param *, unsigned long); + + /* +@@ -43,9 +41,9 @@ int machine_kexec_prepare(struct kimage + func = (unsigned long *)&relocate_new_kernel; + /* Pre-load control code buffer to minimize work in kexec path */ + control_code_buffer = page_address(image->control_code_page); +- memcpy((void *)control_code_buffer, (const void *)func[0], ++ memcpy((void *)control_code_buffer, (const void *)func[0], + relocate_new_kernel_size); +- flush_icache_range((unsigned long)control_code_buffer, ++ flush_icache_range((unsigned long)control_code_buffer, + (unsigned long)control_code_buffer + relocate_new_kernel_size); + + return 0; +@@ -61,7 +59,6 @@ void machine_shutdown(void) + struct pci_dev *dev = NULL; + irq_desc_t *idesc; + cpumask_t mask = CPU_MASK_NONE; +- + /* Disable all PCI devices */ + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + if (!(dev->is_enabled)) +@@ -91,7 +88,6 @@ void machine_shutdown(void) + smp_call_function(kexec_stop_this_cpu, (void *)image->start, 0, 0); + #endif + +- ia64_set_itv(1<<16); + + #ifdef CONFIG_IA64_HP_ZX1 + ioc_iova_disable(); +@@ -100,41 +96,20 @@ void machine_shutdown(void) + + /* + * Do not allocate memory (or fail in any way) in machine_kexec(). +- * We are past the point of no return, committed to rebooting now. ++ * We are past the point of no return, committed to rebooting now. + */ ++extern void *efi_get_pal_addr(void); + void machine_kexec(struct kimage *image) + { +- unsigned long indirection_page; + relocate_new_kernel_t rnk; +- unsigned long pta, impl_va_bits; + void *pal_addr = efi_get_pal_addr(); + unsigned long code_addr = (unsigned long)page_address(image->control_code_page); +- + /* Interrupts aren't acceptable while we reboot */ ++ ia64_set_itv(1<<16); + local_irq_disable(); +- +- /* Disable VHPT */ +- impl_va_bits = ffz(~(local_cpu_data->unimpl_va_mask | (7UL << 61))); +- pta = POW2(61) - POW2(vmlpt_bits); +- ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | 0); +- +- /* now execute the control code. +- * We will start by executing the control code linked into the +- * kernel as opposed to the code we copied in control code buffer * page. When this code switches to physical mode, we will start +- * executing the code in control code buffer page. Reason for +- * doing this is we start code execution in virtual address space. +- * If we were to try to execute the newly copied code in virtual +- * address space, we will need to make an ITLB entry to avoid ITLB +- * miss. By executing the code linked into kernel, we take advantage +- * of the ITLB entry already in place for kernel and avoid making +- * a new entry. +- */ +- indirection_page = image->head & PAGE_MASK; +- + rnk = (relocate_new_kernel_t)&code_addr; +- (*rnk)(indirection_page, image->start, ia64_boot_param, ++ (*rnk)(image->head, image->start, ia64_boot_param, + GRANULEROUNDDOWN((unsigned long) pal_addr)); + BUG(); +- for (;;) +- ; ++ for (;;); + } +--- x/arch/ia64/kernel/relocate_kernel.S ++++ x/arch/ia64/kernel/relocate_kernel.S +@@ -1,5 +1,5 @@ + /* +- * arch/ia64/kernel/relocate_kernel.S ++ * arch/ia64/kernel/relocate_kernel.S + * + * Relocate kexec'able kernel and start it + * +@@ -17,9 +17,7 @@ + #include + #include + +- /* Must be relocatable PIC code callable as a C function, that once +- * it starts can not use the previous processes stack. +- * ++ /* Must be relocatable PIC code callable as a C function + */ + GLOBAL_ENTRY(relocate_new_kernel) + .prologue +@@ -36,22 +34,16 @@ GLOBAL_ENTRY(relocate_new_kernel) + srlz.i + } + ;; +- ++ dep r2=0,r2,61,3 //to physical address ++ ;; + //first switch to physical mode + add r3=1f-.reloc_entry, r2 +- movl r16 = IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_IC|IA64_PSR_MFL ++ movl r16 = IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_IC + mov ar.rsc=0 // put RSE in enforced lazy mode + ;; +- add r2=(memory_stack-.reloc_entry), r2 +- ;; +- add sp=(memory_stack_end - .reloc_entry),r2 ++ add sp=(memory_stack_end - 16 - .reloc_entry),r2 + add r8=(register_stack - .reloc_entry),r2 + ;; +- tpa sp=sp +- tpa r3=r3 +- ;; +- loadrs +- ;; + mov r18=ar.rnat + mov ar.bspstore=r8 + ;; +@@ -66,7 +58,7 @@ GLOBAL_ENTRY(relocate_new_kernel) + 1: + //physical mode code begin + mov b6=in1 +- tpa r28=in2 // tpa must before TLB purge ++ dep r28=0,in2,61,3 //to physical address + + // purge all TC entries + #define O(member) IA64_CPUINFO_##member##_OFFSET +@@ -145,10 +137,10 @@ GLOBAL_ENTRY(relocate_new_kernel) + srlz.i + ;; + +- // copy kexec kernel segments ++ //copy segments + movl r16=PAGE_MASK +- ld8 r30=[in0],8;; // in0 is page_list +- br.sptk.few .dest_page ++ mov r30=in0 // in0 is page_list ++ br.sptk.few .dest_page + ;; + .loop: + ld8 r30=[in0], 8;; +@@ -188,6 +180,8 @@ GLOBAL_ENTRY(relocate_new_kernel) + srlz.d + ;; + br.call.sptk.many b0=b6;; ++ ++.align 32 + memory_stack: + .fill 8192, 1, 0 + memory_stack_end: +@@ -310,7 +304,7 @@ check_irr0: + cmp.eq p6,p0=0,r8 + (p6) br.cond.sptk.few check_irr0 + br.few call_start +- ++ + check_irr1: + mov r8=cr.irr1 + ;; +@@ -319,7 +313,7 @@ check_irr1: + cmp.eq p6,p0=0,r8 + (p6) br.cond.sptk.few check_irr1 + br.few call_start +- ++ + check_irr2: + mov r8=cr.irr2 + ;; +@@ -328,7 +322,7 @@ check_irr2: + cmp.eq p6,p0=0,r8 + (p6) br.cond.sptk.few check_irr2 + br.few call_start +- ++ + check_irr3: + mov r8=cr.irr3 + ;; +@@ -337,7 +331,7 @@ check_irr3: + cmp.eq p6,p0=0,r8 + (p6) br.cond.sptk.few check_irr3 + br.few call_start +- ++ + call_start: + mov cr.eoi=r0 + ;; +--- x/arch/ia64/kernel/setup.c ++++ x/arch/ia64/kernel/setup.c +@@ -44,6 +44,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -251,6 +253,32 @@ reserve_memory (void) + } + #endif + ++#ifdef CONFIG_KEXEC ++ /* crashkernel=size@addr specifies the location to reserve for ++ * a crash kernel. By reserving this memory we guarantee ++ * that linux never set's it up as a DMA target. ++ * Useful for holding code to do something appropriate ++ * after a kernel panic. ++ */ ++ { ++ char *from = strstr(saved_command_line, "crashkernel="); ++ if (from) { ++ unsigned long size, base; ++ size = memparse(from + 12, &from); ++ if (*from == '@') { ++ base = memparse(from + 1, &from); ++ rsvd_region[n].start = ++ (unsigned long)__va(base); ++ rsvd_region[n].end = ++ (unsigned long)__va(base + size); ++ crashk_res.start = base; ++ crashk_res.end = base + size - 1; ++ n++; ++ } ++ } ++ } ++#endif ++ + efi_memmap_init(&rsvd_region[n].start, &rsvd_region[n].end); + n++; + +@@ -496,6 +524,16 @@ setup_arch (char **cmdline_p) + if (!strstr(saved_command_line, "nomca")) + ia64_mca_init(); + ++#ifdef CONFIG_CRASH_DUMP ++ { ++ char *from = strstr(saved_command_line, "elfcorehdr="); ++ ++ if (from) ++ elfcorehdr_addr = memparse(from+11, &from); ++ saved_max_pfn = (unsigned long) -1; ++ } ++#endif ++ + platform_setup(cmdline_p); + paging_init(); + } +--- x/include/asm-ia64/kexec.h ++++ x/include/asm-ia64/kexec.h +@@ -21,14 +21,12 @@ + #define POW2(n) (1ULL << (n)) + + DECLARE_PER_CPU(u64, ia64_mca_pal_base); +- + const extern unsigned int relocate_new_kernel_size; + volatile extern long kexec_rendez; +-extern void relocate_new_kernel(unsigned long, unsigned long, ++extern void relocate_new_kernel(unsigned long, unsigned long, + struct ia64_boot_param *, unsigned long); + extern void kexec_fake_sal_rendez(void *start, unsigned long wake_up, + unsigned long pal_base); +- + static inline void + crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs) + { +--- x/include/asm-ia64/meminit.h ++++ x/include/asm-ia64/meminit.h +@@ -16,11 +16,12 @@ + * - initrd (optional) + * - command line string + * - kernel code & data ++ * - crash dumping code reserved region + * - Kernel memory map built from EFI memory map + * + * More could be added if necessary + */ +-#define IA64_MAX_RSVD_REGIONS 6 ++#define IA64_MAX_RSVD_REGIONS 7 + + struct rsvd_region { + unsigned long start; /* virtual address of beginning of element */ +--- x/include/linux/irq.h ++++ x/include/linux/irq.h +@@ -94,6 +94,7 @@ irq_descp (int irq) + #include /* the arch dependent stuff */ + + extern int setup_irq(unsigned int irq, struct irqaction * new); ++extern void terminate_irqs(void); + + #ifdef CONFIG_GENERIC_HARDIRQS + extern cpumask_t irq_affinity[NR_IRQS]; +--- x/kernel/irq/manage.c ++++ x/kernel/irq/manage.c +@@ -377,3 +377,22 @@ int request_irq(unsigned int irq, + + EXPORT_SYMBOL(request_irq); + ++/* ++ * Terminate any outstanding interrupts ++ */ ++void terminate_irqs(void) ++{ ++ struct irqaction * action; ++ irq_desc_t *idesc; ++ int i; ++ ++ for (i=0; i < NR_IRQS; i++) { ++ idesc = irq_descp(i); ++ action = idesc->action; ++ if (!action) ++ continue; ++ if (idesc->handler->end) ++ idesc->handler->end(i); ++ } ++} ++ --- /dev/null +++ x/patches/linux-2.6.16.13/kexec-ia64-xen.patch @@ -0,0 +1,266 @@ +kexec: ia64 + +This is the kernel patch to make kexec work for xen + +Signed-Off-By: Magnus Damm +Signed-Off-By: Horms + + arch/ia64/kernel/crash.c | 8 ++++++ + arch/ia64/kernel/machine_kexec.c | 36 +++++++++++++++++++++++++++ + arch/ia64/kernel/relocate_kernel.S | 47 +++++++++++++++++++++++++++++++++++- + include/asm-ia64/kexec-xen.h | 7 +++++ + include/asm-ia64/kexec.h | 2 + + 5 files changed, 99 insertions(+), 1 deletion(-) + +--- x/include/asm-ia64/kexec-xen.h ++++ x/include/asm-ia64/kexec-xen.h +@@ -18,10 +18,17 @@ static inline void crash_translate_regs( + /* Kexec needs to know about the actual physical addresss. + * But in xen, on some architectures, a physical address is a + * pseudo-physical addresss. */ ++#ifdef CONFIG_XEN ++#define kexec_page_to_pfn(page) pfn_to_mfn_for_dma(page_to_pfn(page)) ++#define kexec_pfn_to_page(pfn) pfn_to_page(pfn_to_mfn_for_dma(pfn)) ++#define kexec_virt_to_phys(addr) phys_to_machine_for_dma(__pa(addr)) ++#define kexec_phys_to_virt(addr) phys_to_virt(machine_to_phys_for_dma(addr)) ++#else + #define kexec_page_to_pfn(page) page_to_pfn(page) + #define kexec_pfn_to_page(pfn) pfn_to_page(pfn) + #define kexec_virt_to_phys(addr) virt_to_phys(addr) + #define kexec_phys_to_virt(addr) phys_to_virt(addr) ++#endif + + #endif /* _IA64_KEXEC_XEN_H */ + +--- x/arch/ia64/kernel/crash.c ++++ x/arch/ia64/kernel/crash.c +@@ -8,6 +8,11 @@ + * Copyright (C) 2005 Intel Corp Zou Nan hai + * + */ ++#ifdef CONFIG_XEN ++#include ++#include ++#include ++#else /* !CONFIG_XEN */ + #include + #include + #include +@@ -22,6 +27,7 @@ + #include + #include + #include ++#endif /* !CONFIG_XEN */ + + size_t copy_oldmem_page(unsigned long pfn, char *buf, + size_t csize, unsigned long offset, int userbuf) +@@ -41,6 +47,7 @@ size_t copy_oldmem_page(unsigned long pf + return csize; + } + ++#ifndef CONFIG_XEN + static void device_shootdown(void) + { + struct pci_dev *dev; +@@ -150,3 +157,4 @@ machine_crash_shutdown(struct pt_regs *p + ioc_iova_disable(); + #endif + } ++#endif /* !CONFIG_XEN */ +--- x/arch/ia64/kernel/machine_kexec.c ++++ x/arch/ia64/kernel/machine_kexec.c +@@ -24,6 +24,10 @@ + #include + #include + #include ++#ifdef CONFIG_XEN ++#include ++#include ++#endif + + typedef void (*relocate_new_kernel_t)(unsigned long, unsigned long, + struct ia64_boot_param *, unsigned long); +@@ -53,6 +57,7 @@ void machine_kexec_cleanup(struct kimage + { + } + ++#ifndef CONFIG_XEN + void machine_shutdown(void) + { + #ifdef CONFIG_PCI +@@ -113,3 +118,34 @@ void machine_kexec(struct kimage *image) + BUG(); + for (;;); + } ++#else /* !CONFIG_XEN */ ++void machine_shutdown(void){ } ++ ++void machine_kexec_setup_load_arg(xen_kexec_image_t *xki,struct kimage *image) ++{ ++ const extern unsigned int kexec_fake_sal_rendez_offset; ++ ++ unsigned long page_addr; ++ unsigned long offset; ++ ++ page_addr = (unsigned long)page_address(image->control_code_page); ++ offset = kexec_fake_sal_rendez_offset; ++ ++ /* This is a very nasty work around the fact that ++ * kexec_fake_sal_rendez may be on a separate page ++ * to relocate_new_kernel, or it may not depending ++ * on the page size. ++ * ++ * Fortunately kexec_fake_sal_rendez shouldn't cross a page boundary. ++ * ++ * XXX: what about the stack going over a page boundry??? ++ */ ++ while (offset > PAGE_SIZE) { ++ offset -= PAGE_SIZE; ++ page_addr += PAGE_SIZE; ++ } ++ ++ xki->fake_sal_rendez = kexec_virt_to_phys(page_addr) | offset; ++} ++#endif /* CONFIG_XEN */ ++ +--- x/arch/ia64/kernel/relocate_kernel.S ++++ x/arch/ia64/kernel/relocate_kernel.S +@@ -21,7 +21,11 @@ + */ + GLOBAL_ENTRY(relocate_new_kernel) + .prologue ++#ifdef CONFIG_XEN ++ alloc r31=ar.pfs,8,0,0,0 ++#else + alloc r31=ar.pfs,4,0,0,0 ++#endif + .body + .reloc_entry: + { +@@ -34,7 +38,11 @@ GLOBAL_ENTRY(relocate_new_kernel) + srlz.i + } + ;; ++#ifdef CONFIG_XEN ++ dep r2=0,r2,60,4 //to physical address ++#else + dep r2=0,r2,61,3 //to physical address ++#endif + ;; + //first switch to physical mode + add r3=1f-.reloc_entry, r2 +@@ -58,11 +66,19 @@ GLOBAL_ENTRY(relocate_new_kernel) + 1: + //physical mode code begin + mov b6=in1 ++#ifdef CONFIG_XEN ++ dep r28=0,in2,60,4 //to physical address ++#else + dep r28=0,in2,61,3 //to physical address ++#endif + + // purge all TC entries + #define O(member) IA64_CPUINFO_##member##_OFFSET ++#ifdef CONFIG_XEN ++ mov r2=in4 // load phys addr of cpu_info into r2 ++#else + GET_THIS_PADDR(r2, cpu_info) // load phys addr of cpu_info into r2 ++#endif + ;; + addl r17=O(PTCE_STRIDE),r2 + addl r2=O(PTCE_BASE),r2 +@@ -73,7 +89,11 @@ GLOBAL_ENTRY(relocate_new_kernel) + ;; + ld4 r20=[r2] // r20=ptce_count[1] + ld4 r22=[r17] // r22=ptce_stride[1] ++#ifdef CONFIG_XEN ++ mov r24=0 // From xen's mca_asm.S ++#else + mov r24=r0 ++#endif + ;; + adds r20=-1,r20 + ;; +@@ -96,7 +116,11 @@ GLOBAL_ENTRY(relocate_new_kernel) + srlz.i + ;; + //purge TR entry for kernel text and data ++#ifdef CONFIG_XEN ++ mov r16=in5 ++#else + movl r16=KERNEL_START ++#endif + mov r18=KERNEL_TR_PAGE_SHIFT<<2 + ;; + ptr.i r16, r18 +@@ -104,6 +128,10 @@ GLOBAL_ENTRY(relocate_new_kernel) + ;; + srlz.i + ;; ++#ifdef CONFIG_XEN // From xen's mca_asm.S ++ srlz.d ++ ;; ++#endif + + // purge TR entry for percpu data + movl r16=PERCPU_ADDR +@@ -127,7 +155,11 @@ GLOBAL_ENTRY(relocate_new_kernel) + mov r16=IA64_KR(CURRENT_STACK) + ;; + shl r16=r16,IA64_GRANULE_SHIFT ++#ifdef CONFIG_XEN ++ mov r19=in6 ++#else + movl r19=PAGE_OFFSET ++#endif + ;; + add r16=r19,r16 + mov r18=IA64_GRANULE_SHIFT<<2 +@@ -183,10 +215,18 @@ GLOBAL_ENTRY(relocate_new_kernel) + + .align 32 + memory_stack: ++#ifdef CONFIG_XEN ++ .fill 4096, 1, 0 ++#else + .fill 8192, 1, 0 ++#endif + memory_stack_end: + register_stack: ++#ifdef CONFIG_XEN ++ .fill 4096, 1, 0 ++#else + .fill 8192, 1, 0 ++#endif + register_stack_end: + relocate_new_kernel_end: + END(relocate_new_kernel) +@@ -262,7 +302,7 @@ GLOBAL_ENTRY(kexec_fake_sal_rendez) + mov r16=IA64_KR(CURRENT_STACK) + ;; + shl r16=r16,IA64_GRANULE_SHIFT +- movl r19=PAGE_OFFSET ++ movl r19=PAGE_OFFSET // XXX: This will not work in XEN + ;; + add r16=r19,r16 + mov r18=IA64_GRANULE_SHIFT<<2 +@@ -351,3 +391,8 @@ END(kexec_fake_sal_rendez) + relocate_new_kernel_size: + data8 kexec_fake_sal_rendez_end - relocate_new_kernel + ++#ifdef CONFIG_XEN ++ .global kexec_fake_sal_rendez_offset ++kexec_fake_sal_rendez_offset: ++ data8 kexec_fake_sal_rendez - relocate_new_kernel ++#endif +--- x/include/asm-ia64/kexec.h ++++ x/include/asm-ia64/kexec.h +@@ -16,6 +16,8 @@ + + #define MAX_NOTE_BYTES 1024 + ++struct kimage_arch {}; ++ + #define pte_bits 3 + #define vmlpt_bits (impl_va_bits - PAGE_SHIFT + pte_bits) + #define POW2(n) (1ULL << (n))