diff -Nraup a/arch/ia64/Kconfig b/arch/ia64/Kconfig --- a/arch/ia64/Kconfig 2005-11-08 06:06:05.000000000 +0800 +++ b/arch/ia64/Kconfig 2005-11-08 06:08:14.000000000 +0800 @@ -334,6 +334,17 @@ config IA64_PALINFO To use this option, you have to ensure that the "/proc file system support" (CONFIG_PROC_FS) is enabled, too. +config KEXEC + bool "kexec system call (EXPERIMENTAL)" + depends on EXPERIMENTAL && (!SMP || HOTPLUG_CPU) + 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. + source "drivers/firmware/Kconfig" source "fs/Kconfig.binfmt" diff -Nraup a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c --- a/arch/ia64/kernel/crash.c 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/ia64/kernel/crash.c 2005-11-08 06:08:14.000000000 +0800 @@ -0,0 +1,22 @@ +/* + * arch/ia64/kernel/crash.c + * + * Copyright (C) 2005 Intel Corp + * Zou Nan hai + */ +#include +#include + +note_buf_t crash_notes[NR_CPUS]; +void machine_crash_shutdown(void) +{ + /* 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. + */ +} + diff -Nraup a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S --- a/arch/ia64/kernel/entry.S 2005-11-08 06:06:05.000000000 +0800 +++ b/arch/ia64/kernel/entry.S 2005-11-08 06:08:14.000000000 +0800 @@ -1588,7 +1588,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 diff -Nraup a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c --- a/arch/ia64/kernel/machine_kexec.c 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/ia64/kernel/machine_kexec.c 2005-11-08 06:08:55.000000000 +0800 @@ -0,0 +1,67 @@ +/* + * arch/ia64/kernel/machine_exec.c + * + * Copyright (C) 2005 Intel Corp + * Zou Nan hai + */ + +#include +#include +#include +#include +#include +#include + +int +machine_kexec_prepare(struct kimage * image) +{ + return 0; +} + +void +machine_kexec_cleanup(struct kimage *image) +{ +} + +void +machine_shutdown(void) +{ + printk(KERN_INFO "kexec: machine_shutdown called\n"); +} + +const extern unsigned char relocate_new_kernel[]; +const extern unsigned long relocate_new_kernel_size; +typedef void (*relocate_kernel_t) (unsigned long, kimage_entry_t, void *, + unsigned long); + +extern void *efi_get_pal_addr(void); + +NORET_TYPE void +machine_kexec(struct kimage *image) +{ + relocate_kernel_t relocator; + void *pal_addr = efi_get_pal_addr(); + unsigned long + code_addr = (unsigned long)page_address(image->control_code_page); + +#ifdef CONFIG_SMP + int cpu; + for_each_online_cpu(cpu) { + if (cpu != smp_processor_id()) + cpu_down(cpu); + } +#endif + ia64_set_itv(1<<16); + local_irq_disable(); + relocator = (relocate_kernel_t)&code_addr; + memcpy((void *)code_addr, relocate_new_kernel, + relocate_new_kernel_size); + flush_icache_range(code_addr, code_addr + relocate_new_kernel_size); + + (*relocator)(image->start, image->head, ia64_boot_param, + GRANULEROUNDDOWN((unsigned long) pal_addr)); + BUG(); + + for(;;); + +} diff -Nraup a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile --- a/arch/ia64/kernel/Makefile 2005-11-08 06:06:05.000000000 +0800 +++ b/arch/ia64/kernel/Makefile 2005-11-08 06:08:14.000000000 +0800 @@ -23,6 +23,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 crash.o relocate_kernel.o obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o mca_recovery-y += mca_drv.o mca_drv_asm.o diff -Nraup a/arch/ia64/kernel/relocate_kernel.S b/arch/ia64/kernel/relocate_kernel.S --- a/arch/ia64/kernel/relocate_kernel.S 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/ia64/kernel/relocate_kernel.S 2005-11-08 06:08:14.000000000 +0800 @@ -0,0 +1,187 @@ +/* + * arch/ia64/kernel/relocate_kernel.S + * + * Copyright (C) 2005 Intel Corp + * Zou Nan hai + */ +#include +#include +#include +#include + +/* relocate new kernel + * => switch to physical mode + * => purge all TC and TR entries + * => go through kimage page_list to copy segments + * => clear system state + * => call to entry in physical mode + */ + +GLOBAL_ENTRY(relocate_new_kernel) + .prologue + alloc r31=ar.pfs,4,0,0,0 + .body +.here: +{ + rsm psr.i| psr.ic + mov r15=ip +} + ;; +{ + flushrs // must be first insn in group + srlz.i +} + ;; + + //first switch to physical mode + add r3=1f-.here, r15 + movl r16 = IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_IC + mov ar.rsc=0 // put RSE in enforced lazy mode + ;; + add r2=__reloc_stack-.here, r15 + ;; + add sp=8192-16, r2 + ;; + tpa sp=sp + tpa r3=r3 + ;; + mov r18=ar.rnat + mov ar.bspstore=r2 + ;; + 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=in0 + 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 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 + ;; + + // purge TR entry for pal code + mov r16=in3 + mov r18=IA64_GRANULE_SHIFT<<2 + ;; + ptr.i r16,r18 + ;; + srlz.i + ;; + + // copy segments + movl r16=PAGE_MASK + mov r30=in1 // in1 is page_list + br.sptk.few .dest_page + ;; +.loop: + ld8 r30=[in1], 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 in1=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 + ;; + br.call.sptk.many b0=b6;; +__reloc_stack: +.skip 8192 +relocate_new_kernel_end: +END(relocate_new_kernel) + .global relocate_new_kernel_size +relocate_new_kernel_size: + data8 relocate_new_kernel_end - relocate_new_kernel diff -Nraup a/include/asm-ia64/kexec.h b/include/asm-ia64/kexec.h --- a/include/asm-ia64/kexec.h 1970-01-01 08:00:00.000000000 +0800 +++ b/include/asm-ia64/kexec.h 2005-11-08 06:08:14.000000000 +0800 @@ -0,0 +1,29 @@ +#ifndef _IA64_KEXEC_H +#define _IA64_KEXEC_H + +/* + * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. + * I.e. Maximum page that is mapped directly into kernel memory, + * and kmap is not required. + * + * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct + * calculation for the amount of memory directly mappable into the + * kernel memory space. + */ + +/* 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 (1UL << 14) + +/* The native architecture */ +#define KEXEC_ARCH KEXEC_ARCH_IA_64 + +#define MAX_NOTE_BYTES 1024 +typedef u32 note_buf_t[MAX_NOTE_BYTES/4]; +extern note_buf_t crash_notes[]; +#endif