summaryrefslogtreecommitdiff
path: root/arch/s390/kernel/entry64.S
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2005-06-25 14:55:30 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-25 16:24:37 -0700
commit77fa22450de00d535de2cc8be653983560828000 (patch)
tree61644edb2263c3d0db3ea9e9518c6f76a60039e0 /arch/s390/kernel/entry64.S
parentf901e5d1e06b3326c100c5d0df43656311befb81 (diff)
downloadlwn-77fa22450de00d535de2cc8be653983560828000.tar.gz
lwn-77fa22450de00d535de2cc8be653983560828000.zip
[PATCH] s390: improved machine check handling
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 <schwidefsky@de.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/s390/kernel/entry64.S')
-rw-r--r--arch/s390/kernel/entry64.S97
1 files changed, 88 insertions, 9 deletions
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 51527ab8c8f9..57ca75d0ad7f 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -7,6 +7,7 @@
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
* Hartmut Penner (hp@de.ibm.com),
* Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
*/
#include <linux/sys.h>
@@ -52,9 +53,9 @@ SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
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_NEED_RESCHED)
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