aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/s390/Kconfig8
-rw-r--r--arch/s390/kernel/Makefile10
-rw-r--r--arch/s390/kernel/compat_wrapper.S8
-rw-r--r--arch/s390/kernel/crash.c17
-rw-r--r--arch/s390/kernel/machine_kexec.c98
-rw-r--r--arch/s390/kernel/relocate_kernel.S81
-rw-r--r--arch/s390/kernel/relocate_kernel64.S82
-rw-r--r--arch/s390/kernel/syscalls.S2
8 files changed, 305 insertions, 1 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 32696c1d9280..6600ee87f896 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -455,6 +455,14 @@ config NO_IDLE_HZ_INIT
455 The HZ timer is switched off in idle by default. That means the 455 The HZ timer is switched off in idle by default. That means the
456 HZ timer is already disabled at boot time. 456 HZ timer is already disabled at boot time.
457 457
458config KEXEC
459 bool "kexec system call (EXPERIMENTAL)"
460 depends on EXPERIMENTAL
461 help
462 kexec is a system call that implements the ability to shutdown your
463 current kernel, and to start another kernel. It is like a reboot
464 but is independent of hardware/microcode support.
465
458endmenu 466endmenu
459 467
460config PCMCIA 468config PCMCIA
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index b41e0e199a7c..ab1e49d2e518 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -25,6 +25,16 @@ obj-$(CONFIG_ARCH_S390X) += entry64.o reipl64.o
25 25
26obj-$(CONFIG_VIRT_TIMER) += vtime.o 26obj-$(CONFIG_VIRT_TIMER) += vtime.o
27 27
28# Kexec part
29S390_KEXEC_OBJS := machine_kexec.o crash.o
30ifeq ($(CONFIG_ARCH_S390X),y)
31S390_KEXEC_OBJS += relocate_kernel64.o
32else
33S390_KEXEC_OBJS += relocate_kernel.o
34endif
35obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS)
36
37
28# 38#
29# This is just to get the dependencies... 39# This is just to get the dependencies...
30# 40#
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 7a607b1d0380..bf529739c8ab 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -1441,3 +1441,11 @@ compat_sys_waitid_wrapper:
1441 lgfr %r5,%r5 # int 1441 lgfr %r5,%r5 # int
1442 llgtr %r6,%r6 # struct rusage_emu31 * 1442 llgtr %r6,%r6 # struct rusage_emu31 *
1443 jg compat_sys_waitid 1443 jg compat_sys_waitid
1444
1445 .globl compat_sys_kexec_load_wrapper
1446compat_sys_kexec_load_wrapper:
1447 llgfr %r2,%r2 # unsigned long
1448 llgfr %r3,%r3 # unsigned long
1449 llgtr %r4,%r4 # struct kexec_segment *
1450 llgfr %r5,%r5 # unsigned long
1451 jg compat_sys_kexec_load
diff --git a/arch/s390/kernel/crash.c b/arch/s390/kernel/crash.c
new file mode 100644
index 000000000000..db38283c1f27
--- /dev/null
+++ b/arch/s390/kernel/crash.c
@@ -0,0 +1,17 @@
1/*
2 * arch/s390/kernel/crash.c
3 *
4 * (C) Copyright IBM Corp. 2005
5 *
6 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
7 *
8 */
9
10#include <linux/threads.h>
11#include <linux/kexec.h>
12
13note_buf_t crash_notes[NR_CPUS];
14
15void machine_crash_shutdown(void)
16{
17}
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
new file mode 100644
index 000000000000..7a94db76df46
--- /dev/null
+++ b/arch/s390/kernel/machine_kexec.c
@@ -0,0 +1,98 @@
1/*
2 * arch/s390/kernel/machine_kexec.c
3 *
4 * (C) Copyright IBM Corp. 2005
5 *
6 * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
7 *
8 */
9
10/*
11 * s390_machine_kexec.c - handle the transition of Linux booting another kernel
12 * on the S390 architecture.
13 */
14
15#include <asm/cio.h>
16#include <asm/setup.h>
17#include <linux/device.h>
18#include <linux/mm.h>
19#include <linux/kexec.h>
20#include <linux/delay.h>
21#include <asm/pgtable.h>
22#include <asm/pgalloc.h>
23#include <asm/system.h>
24
25static void kexec_halt_all_cpus(void *);
26
27typedef void (*relocate_kernel_t) (kimage_entry_t *, unsigned long);
28
29const extern unsigned char relocate_kernel[];
30const extern unsigned long long relocate_kernel_len;
31
32int
33machine_kexec_prepare(struct kimage *image)
34{
35 unsigned long reboot_code_buffer;
36
37 /* We don't support anything but the default image type for now. */
38 if (image->type != KEXEC_TYPE_DEFAULT)
39 return -EINVAL;
40
41 /* Get the destination where the assembler code should be copied to.*/
42 reboot_code_buffer = page_to_pfn(image->control_code_page)<<PAGE_SHIFT;
43
44 /* Then copy it */
45 memcpy((void *) reboot_code_buffer, relocate_kernel,
46 relocate_kernel_len);
47 return 0;
48}
49
50void
51machine_kexec_cleanup(struct kimage *image)
52{
53}
54
55void
56machine_shutdown(void)
57{
58 printk(KERN_INFO "kexec: machine_shutdown called\n");
59}
60
61NORET_TYPE void
62machine_kexec(struct kimage *image)
63{
64 clear_all_subchannels();
65
66 /* Disable lowcore protection */
67 ctl_clear_bit(0,28);
68
69 on_each_cpu(kexec_halt_all_cpus, image, 0, 0);
70 for(;;);
71}
72
73static void
74kexec_halt_all_cpus(void *kernel_image)
75{
76 static atomic_t cpuid = ATOMIC_INIT(-1);
77 int cpu;
78 struct kimage *image;
79 relocate_kernel_t data_mover;
80
81 if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid))
82 signal_processor(smp_processor_id(), sigp_stop);
83
84 /* Wait for all other cpus to enter stopped state */
85 for_each_online_cpu(cpu) {
86 if (cpu == smp_processor_id())
87 continue;
88 while(!smp_cpu_not_running(cpu))
89 cpu_relax();
90 }
91
92 image = (struct kimage *) kernel_image;
93 data_mover = (relocate_kernel_t)
94 (page_to_pfn(image->control_code_page) << PAGE_SHIFT);
95
96 /* Call the moving routine */
97 (*data_mover) (&image->head, image->start);
98}
diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S
new file mode 100644
index 000000000000..d5e4a62fbb79
--- /dev/null
+++ b/arch/s390/kernel/relocate_kernel.S
@@ -0,0 +1,81 @@
1/*
2 * arch/s390/kernel/relocate_kernel.S
3 *
4 * (C) Copyright IBM Corp. 2005
5 *
6 * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
7 *
8 */
9
10/*
11 * moves the new kernel to its destination...
12 * %r2 = pointer to first kimage_entry_t
13 * %r3 = start address - where to jump to after the job is done...
14 *
15 * %r5 will be used as temp. storage
16 * %r6 holds the destination address
17 * %r7 = PAGE_SIZE
18 * %r8 holds the source address
19 * %r9 = PAGE_SIZE
20 * %r10 is a page mask
21 */
22
23 .text
24 .globl relocate_kernel
25 relocate_kernel:
26 basr %r13,0 #base address
27 .base:
28 spx zero64-.base(%r13) #absolute addressing mode
29 stnsm sys_msk-.base(%r13),0xf8 #disable DAT and IRQ (external)
30 lhi %r10,-1 #preparing the mask
31 sll %r10,12 #shift it such that it becomes 0xf000
32 .top:
33 lhi %r7,4096 #load PAGE_SIZE in r7
34 lhi %r9,4096 #load PAGE_SIZE in r9
35 l %r5,0(%r2) #read another word for indirection page
36 ahi %r2,4 #increment pointer
37 tml %r5,0x1 #is it a destination page?
38 je .indir_check #NO, goto "indir_check"
39 lr %r6,%r5 #r6 = r5
40 nr %r6,%r10 #mask it out and...
41 j .top #...next iteration
42 .indir_check:
43 tml %r5,0x2 #is it a indirection page?
44 je .done_test #NO, goto "done_test"
45 nr %r5,%r10 #YES, mask out,
46 lr %r2,%r5 #move it into the right register,
47 j .top #and read next...
48 .done_test:
49 tml %r5,0x4 #is it the done indicator?
50 je .source_test #NO! Well, then it should be the source indicator...
51 j .done #ok, lets finish it here...
52 .source_test:
53 tml %r5,0x8 #it should be a source indicator...
54 je .top #NO, ignore it...
55 lr %r8,%r5 #r8 = r5
56 nr %r8,%r10 #masking
57 0: mvcle %r6,%r8,0x0 #copy PAGE_SIZE bytes from r8 to r6 - pad with 0
58 jo 0b
59 j .top
60 .done:
61 sr %r0,%r0 #clear register r0
62 la %r4,load_psw-.base(%r13) #load psw-address into the register
63 o %r3,4(%r4) #or load address into psw
64 st %r3,4(%r4)
65 mvc 0(8,%r0),0(%r4) #copy psw to absolute address 0
66 sr %r1,%r1 #clear %r1
67 sr %r2,%r2 #clear %r2
68 sigp %r1,%r2,0x12 #set cpuid to zero
69 lpsw 0 #hopefully start new kernel...
70
71 .align 8
72 zero64:
73 .quad 0
74 load_psw:
75 .long 0x00080000,0x80000000
76 sys_msk:
77 .quad 0
78 relocate_kernel_end:
79 .globl relocate_kernel_len
80 relocate_kernel_len:
81 .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
index 000000000000..96290cc4eb3c
--- /dev/null
+++ b/arch/s390/kernel/relocate_kernel64.S
@@ -0,0 +1,82 @@
1/*
2 * arch/s390/kernel/relocate_kernel64.S
3 *
4 * (C) Copyright IBM Corp. 2005
5 *
6 * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
7 *
8 */
9
10/*
11 * moves the new kernel to its destination...
12 * %r2 = pointer to first kimage_entry_t
13 * %r3 = start address - where to jump to after the job is done...
14 *
15 * %r5 will be used as temp. storage
16 * %r6 holds the destination address
17 * %r7 = PAGE_SIZE
18 * %r8 holds the source address
19 * %r9 = PAGE_SIZE
20 *
21 * 0xf000 is a page_mask
22 */
23
24 .text
25 .globl relocate_kernel
26 relocate_kernel:
27 basr %r13,0 #base address
28 .base:
29 spx zero64-.base(%r13) #absolute addressing mode
30 stnsm sys_msk-.base(%r13),0xf8 #disable DAT and IRQ (external)
31 .top:
32 lghi %r7,4096 #load PAGE_SIZE in r7
33 lghi %r9,4096 #load PAGE_SIZE in r9
34 lg %r5,0(%r2) #read another word for indirection page
35 aghi %r2,8 #increment pointer
36 tml %r5,0x1 #is it a destination page?
37 je .indir_check #NO, goto "indir_check"
38 lgr %r6,%r5 #r6 = r5
39 nill %r6,0xf000 #mask it out and...
40 j .top #...next iteration
41 .indir_check:
42 tml %r5,0x2 #is it a indirection page?
43 je .done_test #NO, goto "done_test"
44 nill %r5,0xf000 #YES, mask out,
45 lgr %r2,%r5 #move it into the right register,
46 j .top #and read next...
47 .done_test:
48 tml %r5,0x4 #is it the done indicator?
49 je .source_test #NO! Well, then it should be the source indicator...
50 j .done #ok, lets finish it here...
51 .source_test:
52 tml %r5,0x8 #it should be a source indicator...
53 je .top #NO, ignore it...
54 lgr %r8,%r5 #r8 = r5
55 nill %r8,0xf000 #masking
56 0: mvcle %r6,%r8,0x0 #copy PAGE_SIZE bytes from r8 to r6 - pad with 0
57 jo 0b
58 j .top
59 .done:
60 sgr %r0,%r0 #clear register r0
61 la %r4,load_psw-.base(%r13) #load psw-address into the register
62 o %r3,4(%r4) #or load address into psw
63 st %r3,4(%r4)
64 mvc 0(8,%r0),0(%r4) #copy psw to absolute address 0
65 sam31 #31 bit mode
66 sr %r1,%r1 #erase register r1
67 sr %r2,%r2 #erase register r2
68 sigp %r1,%r2,0x12 #set cpuid to zero
69 lpsw 0 #hopefully start new kernel...
70
71 .align 8
72 zero64:
73 .quad 0
74 load_psw:
75 .long 0x00080000,0x80000000
76 sys_msk:
77 .quad 0
78 relocate_kernel_end:
79 .globl relocate_kernel_len
80 relocate_kernel_len:
81 .quad relocate_kernel_end - relocate_kernel
82
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 515938628f82..a8668afb5f87 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -285,7 +285,7 @@ SYSCALL(sys_mq_timedsend,sys_mq_timedsend,compat_sys_mq_timedsend_wrapper)
285SYSCALL(sys_mq_timedreceive,sys_mq_timedreceive,compat_sys_mq_timedreceive_wrapper) 285SYSCALL(sys_mq_timedreceive,sys_mq_timedreceive,compat_sys_mq_timedreceive_wrapper)
286SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify_wrapper) /* 275 */ 286SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify_wrapper) /* 275 */
287SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr_wrapper) 287SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr_wrapper)
288NI_SYSCALL /* reserved for kexec */ 288SYSCALL(sys_kexec_load,sys_kexec_load,compat_sys_kexec_load_wrapper)
289SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key_wrapper) 289SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key_wrapper)
290SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key_wrapper) 290SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key_wrapper)
291SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl) /* 280 */ 291SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl) /* 280 */