s390: improved machine check handling.
PATCH 1/3 s390: improved machine check handling.
[patch 1/3] s390: improved machine check handling.
From: Heiko Carstens <[email protected]>
Improved machine check handling. Kernel is now able to receive machine checks while in kernel mode (system call, interrupt and program check handling). Also register validation is now performed.
Signed-off-by Martin Schwidefsky <[email protected]>
diffstat:
arch/s390/kernel/entry.S | 102 +++++++++++-- arch/s390/kernel/entry64.S | 97 +++++++++++- arch/s390/kernel/process.c | 46 +---- arch/s390/kernel/setup.c | 13 + arch/s390/kernel/smp.c | 13 + drivers/s390/s390mach.c | 321 ++++++++++++++++++++++++++++++++++++----- drivers/s390/s390mach.h | 35 +++- include/asm-s390/lowcore.h | 7 include/asm-s390/processor.h | 52 ++---- include/asm-s390/ptrace.h | 2 include/asm-s390/system.h | 21 +- include/asm-s390/thread_info.h | 2 12 files changed, 576 insertions(+), 135 deletions(-)
arch/s390/kernel/entry64.S +88 -9
@@ -7,6 +7,7 @@ * Author(s): Martin Schwidefsky ([email protected]), * Hartmut Penner ([email protected]), * Denis Joseph Barrow ([email protected],[email protected]), + * Heiko Carstens <[email protected]> */ #include <linux/sys.h>
@@ -52,9 +53,9 @@ SP_SIZE = STACK_FRAME_OVERHEAD + _ STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER STACK_SIZE = 1 << STACK_SHIFT -_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ +_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING | \ _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) -_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) +_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) #define BASED(name) name-system_call(%r13)
@@ -114,7 +115,11 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_ jz stack_overflow 3: #endif -2: aghi %r15,-SP_SIZE # make room for registers & psw +2: + .endm + + .macro CREATE_STACK_FRAME psworg,savearea + aghi %r15,-SP_SIZE # make room for registers & psw mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack la %r12,\psworg stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
@@ -152,6 +157,13 @@ __switch_to: je __switch_to_noper # we got away without bashing TLB's lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't __switch_to_noper: + lg %r4,__THREAD_info(%r2) # get thread_info of prev + tm __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending? + jz __switch_to_no_mcck + ni __TI_flags+7(%r4),255-_TIF_MCCK_PENDING # clear flag in prev + lg %r4,__THREAD_info(%r3) # get thread_info of next + oi __TI_flags+7(%r4),_TIF_MCCK_PENDING # set it in next +__switch_to_no_mcck: stmg %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task stg %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp lg %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp
@@ -176,6 +188,7 @@ system_call: sysc_saveall: SAVE_ALL_BASE __LC_SAVE_AREA SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 + CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore #ifdef CONFIG_VIRT_CPU_ACCOUNTING sysc_vtime:
@@ -232,6 +245,8 @@ sysc_work_loop: # One of the work bits is on. Find out which one. # sysc_work: + tm __TI_flags+7(%r9),_TIF_MCCK_PENDING + jo sysc_mcck_pending tm __TI_flags+7(%r9),_TIF_NEED_RESCHED jo sysc_reschedule tm __TI_flags+7(%r9),_TIF_SIGPENDING
@@ -250,6 +265,13 @@ sysc_reschedule: jg schedule # return point is sysc_return # +# _TIF_MCCK_PENDING is set, call handler +# +sysc_mcck_pending: + larl %r14,sysc_work_loop + jg s390_handle_mcck # TIF bit will be cleared by handler + +# # _TIF_SIGPENDING is set, call do_signal # sysc_sigpending:
@@ -474,6 +496,7 @@ pgm_check_handler: tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception jnz pgm_per # got per exception -> special case SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 + CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz pgm_no_vtime
@@ -512,6 +535,7 @@ pgm_per: # pgm_per_std: SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 + CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz pgm_no_vtime2
@@ -537,6 +561,7 @@ pgm_no_vtime2: # pgm_svcper: SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 + CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz pgm_no_vtime3
@@ -564,6 +589,7 @@ io_int_handler: stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+32 SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0 + CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+32 #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz io_no_vtime
@@ -621,9 +647,11 @@ io_work: lgr %r15,%r1 # # One of the work bits is on. Find out which one. -# Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED +# Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED and _TIF_MCCK_PENDING # io_work_loop: + tm __TI_flags+7(%r9),_TIF_MCCK_PENDING + jo io_mcck_pending tm __TI_flags+7(%r9),_TIF_NEED_RESCHED jo io_reschedule tm __TI_flags+7(%r9),_TIF_SIGPENDING
@@ -631,6 +659,13 @@ io_work_loop: j io_leave # +# _TIF_MCCK_PENDING is set, call handler +# +io_mcck_pending: + larl %r14,io_work_loop + jg s390_handle_mcck # TIF bit will be cleared by handler + +# # _TIF_NEED_RESCHED is set, call schedule # io_reschedule:
@@ -661,6 +696,7 @@ ext_int_handler: stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+32 SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0 + CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32 #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz ext_no_vtime
@@ -680,18 +716,60 @@ ext_no_vtime: */ .globl mcck_int_handler mcck_int_handler: - STORE_TIMER __LC_ASYNC_ENTER_TIMER + la %r1,4095 # revalidate r1 + spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer + lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs SAVE_ALL_BASE __LC_SAVE_AREA+64 - SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64,0 + la %r12,__LC_MCK_OLD_PSW + tm __LC_MCCK_CODE,0x80 # system damage? + jo mcck_int_main # yes -> rest of mcck code invalid + tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? + jo 0f + spt __LC_LAST_UPDATE_TIMER #ifdef CONFIG_VIRT_CPU_ACCOUNTING - tm SP_PSW+1(%r15),0x01 # interrupting from user ? + mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_EXIT_TIMER +0: tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? + jno mcck_no_vtime # no -> no timer update + tm __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ? jz mcck_no_vtime UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER mcck_no_vtime: #endif - brasl %r14,s390_do_machine_check +0: + tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? + jno mcck_int_main # no -> skip cleanup critical + tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit + jnz mcck_int_main # from user -> load kernel stack + clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_end) + jhe mcck_int_main + clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_start) + jl mcck_int_main + brasl %r14,cleanup_critical +mcck_int_main: + lg %r14,__LC_PANIC_STACK # are we already on the panic stack? + slgr %r14,%r15 + srag %r14,%r14,PAGE_SHIFT + jz 0f + lg %r15,__LC_PANIC_STACK # load panic stack +0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64 + lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct + la %r2,SP_PTREGS(%r15) # load pt_regs + brasl %r14,s390_do_machine_check + tm SP_PSW+1(%r15),0x01 # returning to user ? + jno mcck_return + lg %r1,__LC_KERNEL_STACK # switch to kernel stack + aghi %r1,-SP_SIZE + mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) + xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain + lgr %r15,%r1 + stosm __SF_EMPTY(%r15),0x04 # turn dat on + tm __TI_flags+7(%r9),_TIF_MCCK_PENDING + jno mcck_return + brasl %r14,s390_handle_mcck mcck_return: RESTORE_ALL 0
@@ -775,7 +853,7 @@ cleanup_critical: clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop) jl 0f clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop+8) - jl cleanup_sysc_leave + jl cleanup_sysc_return 0: br %r14
@@ -793,6 +871,7 @@ cleanup_system_call: mvc __LC_SAVE_AREA(32),__LC_SAVE_AREA+32 0: stg %r13,__LC_SAVE_AREA+40 SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 + CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA stg %r15,__LC_SAVE_AREA+56 llgh %r7,__LC_SVC_INT_CODE #ifdef CONFIG_VIRT_CPU_ACCOUNTING
arch/s390/kernel/entry.S +93 -9
222 lines not on this page · raw message
arch/s390/kernel/process.c +12 -34
63 lines not on this page · raw message
arch/s390/kernel/setup.c +10 -3
@@ -414,7 +414,8 @@ setup_lowcore(void) lc->program_new_psw.mask =PSW_KERNEL_BITS ; lc->program_new_psw.addr =PSW_ADDR_AMODE | (unsigned long )pgm_check_handler; - lc->mcck_new_psw.mask =PSW_KERNEL_BITS ; + lc->mcck_new_psw.mask = +PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT ; lc->mcck_new_psw.addr =PSW_ADDR_AMODE | (unsigned long ) mcck_int_handler; lc->io_new_psw.mask =PSW_KERNEL_BITS ;
@@ -424,12 +425,18 @@ setup_lowcore(void) lc->kernel_stack = ((unsigned long ) &init_thread_union) +THREAD_SIZE ; lc->async_stack = (unsigned long )__alloc_bootmem (ASYNC_SIZE ,ASYNC_SIZE ,0 ) +ASYNC_SIZE ; -#ifdef CONFIG_CHECK_STACK lc->panic_stack = (unsigned long )__alloc_bootmem (PAGE_SIZE ,PAGE_SIZE ,0 ) +PAGE_SIZE ; -#endif lc->current_task = (unsigned long ) init_thread_union.thread_info.task; lc->thread_info = (unsigned long ) &init_thread_union; +#ifndef CONFIG_ARCH_S390X +if (MACHINE_HAS_IEEE ) { + lc->extended_save_area_addr = (__u32 ) +__alloc_bootmem (PAGE_SIZE ,PAGE_SIZE ,0 ); +/* enable extended save area */ +ctl_set_bit (14 ,29 ); + } +#endif #ifdef CONFIG_ARCH_S390X if (MACHINE_HAS_DIAG44 ) lc->diag44_opcode =0x83000044 ;
arch/s390/kernel/smp.c +12 -1
@@ -771,13 +771,24 @@ void __init smp_prepare_cpus(unsigned in *(lowcore_ptr[i]) = S390_lowcore; lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE ); -#ifdef CONFIG_CHECK_STACK stack =__get_free_pages (GFP_KERNEL ,0 );if (stack ==0ULL )panic ("smp_boot_cpus failed to allocate memory\n" ); lowcore_ptr[i]->panic_stack = stack + (PAGE_SIZE ); +#ifndef __s390x__ +if (MACHINE_HAS_IEEE ) { + lowcore_ptr[i]->extended_save_area_addr = + (__u32 )__get_free_pages (GFP_KERNEL ,0 ); +if (lowcore_ptr[i]->extended_save_area_addr ==0 ) +panic ("smp_boot_cpus failed to " +"allocate memory\n" ); + }#endif } +#ifndef __s390x__ +if (MACHINE_HAS_IEEE ) +ctl_set_bit (14 ,29 );/* enable extended save area */ +#endif set_prefix ((u32 )(unsigned long ) lowcore_ptr[smp_processor_id ()]);for_each_cpu (cpu)
drivers/s390/s390mach.c +287 -34
363 lines not on this page · raw message
drivers/s390/s390mach.h +30 -5
@@ -16,20 +16,45 @@ struct mci { __u32 sd : 1; /* 00 system damage */ __u32 pd : 1; /* 01 instruction-processing damage */ __u32 sr : 1; /* 02 system recovery */ - __u32 to_be_defined_1 : 4; /* 03-06 */ + __u32 to_be_defined_1 : 1; /* 03 */ + __u32 cd : 1; /* 04 timing-facility damage */ + __u32 ed : 1; /* 05 external damage */ + __u32 to_be_defined_2 : 1; /* 06 */ __u32 dg : 1; /* 07 degradation */ __u32 w : 1; /* 08 warning pending */ __u32 cp : 1; /* 09 channel-report pending */ - __u32 to_be_defined_2 : 6; /* 10-15 */ + __u32 sp : 1; /* 10 service-processor damage */ + __u32 ck : 1; /* 11 channel-subsystem damage */ + __u32 to_be_defined_3 : 2; /* 12-13 */ + __u32 b : 1; /* 14 backed up */ + __u32 to_be_defined_4 : 1; /* 15 */ __u32 se : 1; /* 16 storage error uncorrected */ __u32 sc : 1; /* 17 storage error corrected */ __u32 ke : 1; /* 18 storage-key error uncorrected */ __u32 ds : 1; /* 19 storage degradation */ - __u32 to_be_defined_3 : 4; /* 20-23 */ + __u32 wp : 1; /* 20 psw mwp validity */ + __u32 ms : 1; /* 21 psw mask and key validity */ + __u32 pm : 1; /* 22 psw program mask and cc validity */ + __u32 ia : 1; /* 23 psw instruction address validity */ __u32 fa : 1; /* 24 failing storage address validity */ - __u32 to_be_defined_4 : 7; /* 25-31 */ + __u32 to_be_defined_5 : 1; /* 25 */ + __u32 ec : 1; /* 26 external damage code validity */ + __u32 fp : 1; /* 27 floating point register validity */ + __u32 gr : 1; /* 28 general register validity */ + __u32 cr : 1; /* 29 control register validity */ + __u32 to_be_defined_6 : 1; /* 30 */ + __u32 st : 1; /* 31 storage logical validity */ __u32 ie : 1; /* 32 indirect storage error */ - __u32 to_be_defined_5 : 31; /* 33-63 */ + __u32 ar : 1; /* 33 access register validity */ + __u32 da : 1; /* 34 delayed access exception */ + __u32 to_be_defined_7 : 7; /* 35-41 */ + __u32 pr : 1; /* 42 tod programmable register validity */ + __u32 fc : 1; /* 43 fp control register validity */ + __u32 ap : 1; /* 44 ancillary report */ + __u32 to_be_defined_8 : 1; /* 45 */ + __u32 ct : 1; /* 46 cpu timer validity */ + __u32 cc : 1; /* 47 clock comparator validity */ + __u32 to_be_defined_9 : 16; /* 47-63 */ };/*
include/asm-s390/lowcore.h +6 -1
@@ -109,10 +109,14 @@#ifndef __s390x__#define __LC_PFAULT_INTPARM 0x080 +#define __LC_CPU_TIMER_SAVE_AREA 0x0D8#define __LC_AREGS_SAVE_AREA 0x120 +#define __LC_GPREGS_SAVE_AREA 0x180#define __LC_CREGS_SAVE_AREA 0x1C0#else /* __s390x__ */ #define __LC_PFAULT_INTPARM 0x11B8 +#define __LC_GPREGS_SAVE_AREA 0x1280 +#define __LC_CPU_TIMER_SAVE_AREA 0x1328#define __LC_AREGS_SAVE_AREA 0x1340#define __LC_CREGS_SAVE_AREA 0x1380#endif /* __s390x__ */
@@ -167,7 +171,8 @@ struct _lowcore__u16 subchannel_nr;/* 0x0ba */ __u32 io_int_parm;/* 0x0bc */ __u32 io_int_word;/* 0x0c0 */ -__u8 pad3[0xD8 -0xC4 ];/* 0x0c4 */ +__u8 pad3[0xD4 -0xC4 ];/* 0x0c4 */ +__u32 extended_save_area_addr;/* 0x0d4 */ __u32 cpu_timer_save_area[2 ];/* 0x0d8 */ __u32 clock_comp_save_area[2 ];/* 0x0e0 */ __u32 mcck_interruption_code[2 ];/* 0x0e8 */
include/asm-s390/processor.h +20 -32
91 lines not on this page · raw message
include/asm-s390/ptrace.h +1 -1
@@ -276,7 +276,7 @@ typedef struct#endif /* __s390x__ */ #define PSW_KERNEL_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | \ - PSW_DEFAULT_KEY) + PSW_MASK_MCHECK | PSW_DEFAULT_KEY)#define PSW_USER_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \ PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \ PSW_MASK_PSTATE | PSW_DEFAULT_KEY)
include/asm-s390/system.h +15 -6
@@ -16,6 +16,7 @@#include <asm/types.h> #include <asm/ptrace.h> #include <asm/setup.h> +#include <asm/processor.h> #ifdef __KERNEL__
@@ -331,9 +332,6 @@ __cmpxchg(volatile void *ptr, unsigned l#ifdef __s390x__ -#define __load_psw (psw) \ - __asm__ __volatile__("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc" ); -#define __ctl_load (array, low, high) ({ \ typedef struct { char _[sizeof(array)]; } addrtype; \ __asm__ __volatile__ ( \
@@ -390,9 +388,6 @@ __cmpxchg(volatile void *ptr, unsigned l#else /* __s390x__ */ -#define __load_psw (psw) \ - __asm__ __volatile__("lpsw 0(%0)" : : "a" (&psw) : "cc" ); -#define __ctl_load (array, low, high) ({ \ typedef struct { char _[sizeof(array)]; } addrtype; \ __asm__ __volatile__ ( \
@@ -451,6 +446,20 @@ __cmpxchg(volatile void *ptr, unsigned l/* For spinlocks etc */ #define local_irq_save (x) ((x) = local_irq_disable()) +/* +* Use to set psw mask except for the first byte which +* won't be changed by this function. +*/ +static inline void +__set_psw_mask (unsigned long mask) +{ +local_save_flags (mask); +__load_psw_mask (mask); +} + +#define local_mcck_enable () __set_psw_mask(PSW_KERNEL_BITS) +#define local_mcck_disable () __set_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK) +#ifdef CONFIG_SMP extern void smp_ctl_set_bit (int cr,int bit);
include/asm-s390/thread_info.h +2 -0
@@ -96,6 +96,7 @@ static inline struct thread_info *curren#define TIF_RESTART_SVC 4/* restart svc with new svc number */ #define TIF_SYSCALL_AUDIT 5/* syscall auditing active */ #define TIF_SINGLE_STEP 6/* deliver sigtrap on return to user */ +#define TIF_MCCK_PENDING 7/* machine check handling is pending */ #define TIF_USEDFPU 16/* FPU was used by this task this quantum (SMP) */ #define TIF_POLLING_NRFLAG 17/* true if poll_idle() is polling TIF_NEED_RESCHED */
@@ -109,6 +110,7 @@ static inline struct thread_info *curren#define _TIF_RESTART_SVC (1<<TIF_RESTART_SVC)#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)#define _TIF_SINGLE_STEP (1<<TIF_SINGLE_STEP) +#define _TIF_MCCK_PENDING (1<<TIF_MCCK_PENDING)#define _TIF_USEDFPU (1<<TIF_USEDFPU)#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)#define _TIF_31BIT (1<<TIF_31BIT)