[PATCH] kexec: s390 support
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>
This commit is contained in:
Родитель
fce0d57403
Коммит
cf13f0eaff
|
@ -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.
|
||||
|
||||
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
|
||||
|
|
|
@ -25,6 +25,16 @@ obj-$(CONFIG_ARCH_S390X) += entry64.o reipl64.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...
|
||||
#
|
||||
|
|
|
@ -1441,3 +1441,11 @@ compat_sys_waitid_wrapper:
|
|||
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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
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 */
|
||||
|
|
|
@ -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 */
|
|
@ -269,7 +269,7 @@
|
|||
#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
|
||||
|
|
|
@ -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_S390 (22 << 16)
|
||||
|
||||
#define KEXEC_FLAGS (KEXEC_ON_CRASH) /* List of defined/legal kexec flags */
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче