From: Heiko Carstens This patch is mostly based on comments which I received from Milton Miller . Changes are: - Fix passing of first argument to relocate_kernel assembly. - Fix Kconfig description. - Remove wrong comment and comments that describe obvious things. - Allow only KEXEC_TYPE_DEFAULT as image type -> dump not supported. Signed-off-by: Heiko Carstens Signed-off-by: Andrew Morton --- arch/s390/Kconfig | 14 -------- arch/s390/kernel/machine_kexec.c | 61 ++++++++--------------------------- arch/s390/kernel/relocate_kernel.S | 14 +++----- arch/s390/kernel/relocate_kernel64.S | 14 +++----- 4 files changed, 27 insertions(+), 76 deletions(-) diff -puN arch/s390/Kconfig~s390-kexec-fixes arch/s390/Kconfig --- 25/arch/s390/Kconfig~s390-kexec-fixes 2005-04-28 23:11:21.976403248 -0700 +++ 25-akpm/arch/s390/Kconfig 2005-04-28 23:11:21.984402032 -0700 @@ -461,19 +461,7 @@ config KEXEC 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. - - In the GAMECUBE implementation, kexec allows you to load and - run DOL files, including kernel and homebrew DOLs. + but is independent of hardware/microcode support. endmenu diff -puN arch/s390/kernel/machine_kexec.c~s390-kexec-fixes arch/s390/kernel/machine_kexec.c --- 25/arch/s390/kernel/machine_kexec.c~s390-kexec-fixes 2005-04-28 23:11:21.977403096 -0700 +++ 25-akpm/arch/s390/kernel/machine_kexec.c 2005-04-28 23:11:21.985401880 -0700 @@ -22,29 +22,22 @@ #include #include -int machine_kexec_prepare(struct kimage *); -void machine_kexec_cleanup(struct kimage *); -void machine_shutdown(void); -void machine_kexec(struct kimage *); static void kexec_halt_all_cpus(void *); -typedef void (*relocate_kernel_t) (unsigned long indirection_page, - unsigned long reboot_code_buffer, - unsigned long start_address); +typedef void (*relocate_kernel_t) (kimage_entry_t *, unsigned long); const extern unsigned char relocate_kernel[]; const extern unsigned long long relocate_kernel_len; -/* - * Do whatever setup is needed on image and the reboot code buffer to - * allow us to aviood allocations later. - */ - int -machine_kexec_prepare(struct kimage * image) +machine_kexec_prepare(struct kimage *image) { unsigned long reboot_code_buffer; + /* We don't support anything but the default image type for now. */ + if (image->type != KEXEC_TYPE_DEFAULT) + return -EINVAL; + /* Get the destination where the assembler code should be copied to.*/ reboot_code_buffer = page_to_pfn(image->control_code_page)<control_code_page)<head & PAGE_MASK; - data_mover = (relocate_kernel_t) reboot_code_buffer; - clear_all_subchannels(); /* Disable lowcore protection */ @@ -102,20 +70,15 @@ machine_kexec(struct kimage *image) for(;;); } -/* - * Make sure that all except one CPU are stopped. The first CPU - * that enters this function is going to halt all the others and then, if it is - * the only one left, the 'data_mover' function will be called. - */ static void kexec_halt_all_cpus(void *kernel_image) { static atomic_t cpuid = ATOMIC_INIT(-1); int cpu; + struct kimage *image; + relocate_kernel_t data_mover; - struct kimage *image = (struct kimage *) kernel_image; - - if(atomic_compare_and_swap(-1, smp_processor_id(), &cpuid)) + if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid)) signal_processor(smp_processor_id(), sigp_stop); /* Wait for all other cpus to enter stopped state */ @@ -126,6 +89,10 @@ kexec_halt_all_cpus(void *kernel_image) cpu_relax(); } + image = (struct kimage *) kernel_image; + data_mover = (relocate_kernel_t) + (page_to_pfn(image->control_code_page) << PAGE_SHIFT); + /* Call the moving routine */ - (*data_mover) (indirection_page, reboot_code_buffer, image->start); + (*data_mover) (&image->head, image->start); } diff -puN arch/s390/kernel/relocate_kernel64.S~s390-kexec-fixes arch/s390/kernel/relocate_kernel64.S --- 25/arch/s390/kernel/relocate_kernel64.S~s390-kexec-fixes 2005-04-28 23:11:21.978402944 -0700 +++ 25-akpm/arch/s390/kernel/relocate_kernel64.S 2005-04-28 23:11:21.986401728 -0700 @@ -9,9 +9,8 @@ /* * moves the new kernel to its destination... - * %r2 = indirection page - * %r3 = reboot_code_buffer - * %r4 = start address - where to jump to after the job is done... + * %r2 = pointer to first kimage_entry_t + * %r3 = start address - where to jump to after the job is done... * * %r5 will be used as temp. storage * %r6 holds the destination address @@ -59,11 +58,10 @@ j .top .done: sgr %r0,%r0 #clear register r0 - la %r3,load_psw-.base(%r13) #load psw-address into the register - mvc 0(4,%r0),0(%r3) #copy the first part of it - l %r1,4(0,%r3) #copy the second part of load_psw in %r1 - or %r1,%r4 #OR it with the given psw --> %r1 = (%r1 | %r4) - st %r1,4(0,%r0) #store it at addr 0+4B, i.e. second part of psw + la %r4,load_psw-.base(%r13) #load psw-address into the register + o %r3,4(%r4) #or load address into psw + st %r3,4(%r4) + mvc 0(8,%r0),0(%r4) #copy psw to absolute address 0 sam31 #31 bit mode sr %r1,%r1 #erase register r1 sr %r2,%r2 #erase register r2 diff -puN arch/s390/kernel/relocate_kernel.S~s390-kexec-fixes arch/s390/kernel/relocate_kernel.S --- 25/arch/s390/kernel/relocate_kernel.S~s390-kexec-fixes 2005-04-28 23:11:21.980402640 -0700 +++ 25-akpm/arch/s390/kernel/relocate_kernel.S 2005-04-28 23:11:21.986401728 -0700 @@ -9,9 +9,8 @@ /* * moves the new kernel to its destination... - * %r2 = indirection page - * %r3 = reboot_code_buffer - * %r4 = start address - where to jump to after the job is done... + * %r2 = pointer to first kimage_entry_t + * %r3 = start address - where to jump to after the job is done... * * %r5 will be used as temp. storage * %r6 holds the destination address @@ -60,11 +59,10 @@ j .top .done: sr %r0,%r0 #clear register r0 - la %r3,load_psw-.base(%r13) #load psw-address into the register - mvc 0(4,%r0),0(%r3) #copy the first part of psw - l %r1,4(0,%r3) #get the second part of psw in %r1 - or %r1,%r4 #OR the load address with the 2nd part of psw - st %r1,4(0,%r0) #store it at add 0+4B + la %r4,load_psw-.base(%r13) #load psw-address into the register + o %r3,4(%r4) #or load address into psw + st %r3,4(%r4) + mvc 0(8,%r0),0(%r4) #copy psw to absolute address 0 sr %r1,%r1 #clear %r1 sr %r2,%r2 #clear %r2 sigp %r1,%r2,0x12 #set cpuid to zero _