]> git.karo-electronics.de Git - linux-beck.git/commitdiff
[PATCH] kexec: s390 support
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Sat, 25 Jun 2005 21:58:11 +0000 (14:58 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Sat, 25 Jun 2005 23:24:51 +0000 (16:24 -0700)
Add kexec support for s390 architecture.

From: Milton Miller <miltonm@bga.com>

- 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.

Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/s390/Kconfig
arch/s390/kernel/Makefile
arch/s390/kernel/compat_wrapper.S
arch/s390/kernel/crash.c [new file with mode: 0644]
arch/s390/kernel/machine_kexec.c [new file with mode: 0644]
arch/s390/kernel/relocate_kernel.S [new file with mode: 0644]
arch/s390/kernel/relocate_kernel64.S [new file with mode: 0644]
arch/s390/kernel/syscalls.S
include/asm-s390/kexec.h [new file with mode: 0644]
include/asm-s390/unistd.h
include/linux/kexec.h

index 32696c1d92806c7cac9eebaa20220aacd6793993..6600ee87f896938bd7e71f30bc4e43c69e148c2a 100644 (file)
@@ -455,6 +455,14 @@ config NO_IDLE_HZ_INIT
          The HZ timer is switched off in idle by default. That means the
          HZ timer is already disabled at boot time.
 
          The HZ timer is switched off in idle by default. That means the
          HZ timer is already disabled at boot time.
 
+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 is independent of hardware/microcode support.
+
 endmenu
 
 config PCMCIA
 endmenu
 
 config PCMCIA
index b41e0e199a7cf8aa9d5b8f221b72b4f58b27b4bc..ab1e49d2e5185dad2116aa8ff8afacf5e6f2cf2e 100644 (file)
@@ -25,6 +25,16 @@ obj-$(CONFIG_ARCH_S390X)     += entry64.o reipl64.o
 
 obj-$(CONFIG_VIRT_TIMER)       += vtime.o
 
 
 obj-$(CONFIG_VIRT_TIMER)       += vtime.o
 
+# Kexec part
+S390_KEXEC_OBJS := machine_kexec.o crash.o
+ifeq ($(CONFIG_ARCH_S390X),y)
+S390_KEXEC_OBJS += relocate_kernel64.o
+else
+S390_KEXEC_OBJS += relocate_kernel.o
+endif
+obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS)
+
+
 #
 # This is just to get the dependencies...
 #
 #
 # This is just to get the dependencies...
 #
index 7a607b1d03808f6abdb36e47de42d6c5ef91e2d8..bf529739c8ab6a53709b4bf5507ae7c4ca7410f0 100644 (file)
@@ -1441,3 +1441,11 @@ compat_sys_waitid_wrapper:
        lgfr    %r5,%r5                 # int
        llgtr   %r6,%r6                 # struct rusage_emu31 *
        jg      compat_sys_waitid
        lgfr    %r5,%r5                 # int
        llgtr   %r6,%r6                 # struct rusage_emu31 *
        jg      compat_sys_waitid
+
+       .globl  compat_sys_kexec_load_wrapper
+compat_sys_kexec_load_wrapper:
+       llgfr   %r2,%r2                 # unsigned long
+       llgfr   %r3,%r3                 # unsigned long
+       llgtr   %r4,%r4                 # struct kexec_segment *
+       llgfr   %r5,%r5                 # unsigned long
+       jg      compat_sys_kexec_load
diff --git a/arch/s390/kernel/crash.c b/arch/s390/kernel/crash.c
new file mode 100644 (file)
index 0000000..db38283
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * arch/s390/kernel/crash.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ *
+ */
+
+#include <linux/threads.h>
+#include <linux/kexec.h>
+
+note_buf_t crash_notes[NR_CPUS];
+
+void machine_crash_shutdown(void)
+{
+}
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
new file mode 100644 (file)
index 0000000..7a94db7
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * arch/s390/kernel/machine_kexec.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ *
+ */
+
+/*
+ * s390_machine_kexec.c - handle the transition of Linux booting another kernel
+ * on the S390 architecture.
+ */
+
+#include <asm/cio.h>
+#include <asm/setup.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/system.h>
+
+static void kexec_halt_all_cpus(void *);
+
+typedef void (*relocate_kernel_t) (kimage_entry_t *, unsigned long);
+
+const extern unsigned char relocate_kernel[];
+const extern unsigned long long relocate_kernel_len;
+
+int
+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)<<PAGE_SHIFT;
+
+       /* Then copy it */
+       memcpy((void *) reboot_code_buffer, relocate_kernel,
+              relocate_kernel_len);
+       return 0;
+}
+
+void
+machine_kexec_cleanup(struct kimage *image)
+{
+}
+
+void
+machine_shutdown(void)
+{
+       printk(KERN_INFO "kexec: machine_shutdown called\n");
+}
+
+NORET_TYPE void
+machine_kexec(struct kimage *image)
+{
+       clear_all_subchannels();
+
+       /* Disable lowcore protection */
+       ctl_clear_bit(0,28);
+
+       on_each_cpu(kexec_halt_all_cpus, image, 0, 0);
+       for(;;);
+}
+
+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;
+
+       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 */
+       for_each_online_cpu(cpu) {
+               if (cpu == smp_processor_id())
+                       continue;
+               while(!smp_cpu_not_running(cpu))
+                       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) (&image->head, image->start);
+}
diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S
new file mode 100644 (file)
index 0000000..d5e4a62
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * arch/s390/kernel/relocate_kernel.S
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ *
+ */
+
+/*
+ * moves the new kernel to its destination...
+ * %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
+ * %r7 = PAGE_SIZE
+ * %r8 holds the source address
+ * %r9 = PAGE_SIZE
+ * %r10 is a page mask
+ */
+
+       .text
+       .globl          relocate_kernel
+       relocate_kernel:
+               basr    %r13,0          #base address
+       .base:
+               spx     zero64-.base(%r13)      #absolute addressing mode
+               stnsm   sys_msk-.base(%r13),0xf8        #disable DAT and IRQ (external)
+               lhi     %r10,-1         #preparing the mask
+               sll     %r10,12         #shift it such that it becomes 0xf000
+       .top:
+               lhi     %r7,4096        #load PAGE_SIZE in r7
+               lhi     %r9,4096        #load PAGE_SIZE in r9
+               l       %r5,0(%r2)      #read another word for indirection page
+               ahi     %r2,4           #increment pointer
+               tml     %r5,0x1         #is it a destination page?
+               je      .indir_check    #NO, goto "indir_check"
+               lr      %r6,%r5         #r6 = r5
+               nr      %r6,%r10        #mask it out and...
+               j       .top            #...next iteration
+       .indir_check:
+               tml     %r5,0x2         #is it a indirection page?
+               je      .done_test      #NO, goto "done_test"
+               nr      %r5,%r10        #YES, mask out,
+               lr      %r2,%r5         #move it into the right register,
+               j       .top            #and read next...
+       .done_test:
+               tml     %r5,0x4         #is it the done indicator?
+               je      .source_test    #NO! Well, then it should be the source indicator...
+               j       .done           #ok, lets finish it here...
+       .source_test:
+               tml     %r5,0x8         #it should be a source indicator...
+               je      .top            #NO, ignore it...
+               lr      %r8,%r5         #r8 = r5
+               nr      %r8,%r10        #masking
+       0:      mvcle   %r6,%r8,0x0     #copy PAGE_SIZE bytes from r8 to r6 - pad with 0
+               jo      0b
+               j       .top
+       .done:
+               sr      %r0,%r0         #clear register r0
+               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
+               lpsw    0               #hopefully start new kernel...
+
+               .align  8
+       zero64:
+               .quad   0
+       load_psw:
+               .long   0x00080000,0x80000000
+       sys_msk:
+               .quad   0
+       relocate_kernel_end:
+       .globl  relocate_kernel_len
+       relocate_kernel_len:
+               .quad   relocate_kernel_end - relocate_kernel
diff --git a/arch/s390/kernel/relocate_kernel64.S b/arch/s390/kernel/relocate_kernel64.S
new file mode 100644 (file)
index 0000000..96290cc
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * arch/s390/kernel/relocate_kernel64.S
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ *
+ */
+
+/*
+ * moves the new kernel to its destination...
+ * %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
+ * %r7 = PAGE_SIZE
+ * %r8 holds the source address
+ * %r9 = PAGE_SIZE
+ *
+ * 0xf000 is a page_mask
+ */
+
+       .text
+       .globl          relocate_kernel
+       relocate_kernel:
+               basr    %r13,0          #base address
+       .base:
+               spx     zero64-.base(%r13)      #absolute addressing mode
+               stnsm   sys_msk-.base(%r13),0xf8        #disable DAT and IRQ (external)
+       .top:
+               lghi    %r7,4096        #load PAGE_SIZE in r7
+               lghi    %r9,4096        #load PAGE_SIZE in r9
+               lg      %r5,0(%r2)      #read another word for indirection page
+               aghi    %r2,8           #increment pointer
+               tml     %r5,0x1         #is it a destination page?
+               je      .indir_check    #NO, goto "indir_check"
+               lgr     %r6,%r5         #r6 = r5
+               nill    %r6,0xf000      #mask it out and...
+               j       .top            #...next iteration
+       .indir_check:
+               tml     %r5,0x2         #is it a indirection page?
+               je      .done_test      #NO, goto "done_test"
+               nill    %r5,0xf000      #YES, mask out,
+               lgr     %r2,%r5         #move it into the right register,
+               j       .top            #and read next...
+       .done_test:
+               tml     %r5,0x4         #is it the done indicator?
+               je      .source_test    #NO! Well, then it should be the source indicator...
+               j       .done           #ok, lets finish it here...
+       .source_test:
+               tml     %r5,0x8         #it should be a source indicator...
+               je      .top            #NO, ignore it...
+               lgr     %r8,%r5         #r8 = r5
+               nill    %r8,0xf000      #masking
+       0:      mvcle   %r6,%r8,0x0     #copy PAGE_SIZE bytes from r8 to r6 - pad with 0
+               jo      0b
+               j       .top
+       .done:
+               sgr     %r0,%r0         #clear register r0
+               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
+               sigp    %r1,%r2,0x12    #set cpuid to zero
+               lpsw    0               #hopefully start new kernel...
+
+               .align  8
+       zero64:
+               .quad   0
+       load_psw:
+               .long   0x00080000,0x80000000
+       sys_msk:
+               .quad   0
+       relocate_kernel_end:
+       .globl  relocate_kernel_len
+       relocate_kernel_len:
+               .quad   relocate_kernel_end - relocate_kernel
+
index 515938628f82c75a7d80367568e933cfc4e0783c..a8668afb5f87d2b5b3324a8dae1802eab7aedcdf 100644 (file)
@@ -285,7 +285,7 @@ SYSCALL(sys_mq_timedsend,sys_mq_timedsend,compat_sys_mq_timedsend_wrapper)
 SYSCALL(sys_mq_timedreceive,sys_mq_timedreceive,compat_sys_mq_timedreceive_wrapper)
 SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify_wrapper) /* 275 */
 SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr_wrapper)
 SYSCALL(sys_mq_timedreceive,sys_mq_timedreceive,compat_sys_mq_timedreceive_wrapper)
 SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify_wrapper) /* 275 */
 SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr_wrapper)
-NI_SYSCALL                                                     /* reserved for kexec */
+SYSCALL(sys_kexec_load,sys_kexec_load,compat_sys_kexec_load_wrapper)
 SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key_wrapper)
 SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key_wrapper)
 SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl)               /* 280 */
 SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key_wrapper)
 SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key_wrapper)
 SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl)               /* 280 */
diff --git a/include/asm-s390/kexec.h b/include/asm-s390/kexec.h
new file mode 100644 (file)
index 0000000..54cf7d9
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * include/asm-s390/kexec.h
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ *
+ */
+
+#ifndef _S390_KEXEC_H
+#define _S390_KEXEC_H
+
+#include <asm/page.h>
+#include <asm/processor.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.
+ */
+
+/* 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 pages */
+/* Not more than 2GB */
+#define KEXEC_CONTROL_MEMORY_LIMIT (1<<31)
+
+/* Allocate one page for the pdp and the second for the code */
+#define KEXEC_CONTROL_CODE_SIZE 4096
+
+/* The native architecture */
+#define KEXEC_ARCH KEXEC_ARCH_S390
+
+#define MAX_NOTE_BYTES 1024
+typedef u32 note_buf_t[MAX_NOTE_BYTES/4];
+
+extern note_buf_t crash_notes[];
+
+#endif /*_S390_KEXEC_H */
index f1a204f7c0f0b2559636a815d813766f89d71d1f..363db45f8d074314ed9603bc8c26466aeb270134 100644 (file)
 #define __NR_mq_timedreceive   274
 #define __NR_mq_notify         275
 #define __NR_mq_getsetattr     276
 #define __NR_mq_timedreceive   274
 #define __NR_mq_notify         275
 #define __NR_mq_getsetattr     276
-/* Number 277 is reserved for new sys_kexec_load */
+#define __NR_kexec_load                277
 #define __NR_add_key           278
 #define __NR_request_key       279
 #define __NR_keyctl            280
 #define __NR_add_key           278
 #define __NR_request_key       279
 #define __NR_keyctl            280
index e3fc35f4e35fdac44e3132ca93e4d5865def31c5..0653a27c3d724e83f3169ddb5f5a59c6545c8e55 100644 (file)
@@ -114,6 +114,7 @@ extern struct kimage *kexec_image;
 #define KEXEC_ARCH_PPC     (20 << 16)
 #define KEXEC_ARCH_PPC64   (21 << 16)
 #define KEXEC_ARCH_IA_64   (50 << 16)
 #define KEXEC_ARCH_PPC     (20 << 16)
 #define KEXEC_ARCH_PPC64   (21 << 16)
 #define KEXEC_ARCH_IA_64   (50 << 16)
+#define KEXEC_ARCH_S390    (22 << 16)
 
 #define KEXEC_FLAGS    (KEXEC_ON_CRASH)  /* List of defined/legal kexec flags */
 
 
 #define KEXEC_FLAGS    (KEXEC_ON_CRASH)  /* List of defined/legal kexec flags */