[PATCH] s390: improved machine check handling
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Sat, 25 Jun 2005 21:55:30 +0000 (14:55 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Sat, 25 Jun 2005 23:24:37 +0000 (16:24 -0700)
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>
12 files changed:
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/process.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
drivers/s390/s390mach.c
drivers/s390/s390mach.h
include/asm-s390/lowcore.h
include/asm-s390/processor.h
include/asm-s390/ptrace.h
include/asm-s390/system.h
include/asm-s390/thread_info.h

index c0e09b3..5b262b5 100644 (file)
@@ -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>
@@ -49,9 +50,9 @@ SP_ILC       =  STACK_FRAME_OVERHEAD + __PT_ILC
 SP_TRAP      =  STACK_FRAME_OVERHEAD + __PT_TRAP
 SP_SIZE      =  STACK_FRAME_OVERHEAD + __PT_SIZE
 
-_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)
 
 STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
 STACK_SIZE  = 1 << STACK_SHIFT
@@ -121,7 +122,11 @@ STACK_SIZE  = 1 << STACK_SHIFT
        bz      BASED(stack_overflow)
 3:
 #endif
-2:     s       %r15,BASED(.Lc_spsize)  # make room for registers & psw
+2:
+       .endm
+
+       .macro  CREATE_STACK_FRAME psworg,savearea
+       s       %r15,BASED(.Lc_spsize)  # make room for registers & psw
        mvc     SP_PSW(8,%r15),0(%r12)  # move user PSW to stack
        la      %r12,\psworg
        st      %r2,SP_ORIG_R2(%r15)    # store original content of gpr 2
@@ -161,6 +166,13 @@ __switch_to_base:
         be      __switch_to_noper-__switch_to_base(%r1)        # we got away w/o bashing TLB's
         lctl    %c9,%c11,__THREAD_per(%r3)     # Nope we didn't
 __switch_to_noper:
+       l       %r4,__THREAD_info(%r2)          # get thread_info of prev
+       tm      __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending?
+       bz      __switch_to_no_mcck-__switch_to_base(%r1)
+       ni      __TI_flags+3(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
+       l       %r4,__THREAD_info(%r3)          # get thread_info of next
+       oi      __TI_flags+3(%r4),_TIF_MCCK_PENDING # set it in next
+__switch_to_no_mcck:
         stm     %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
        st      %r15,__THREAD_ksp(%r2)  # store kernel stack to prev->tss.ksp
        l       %r15,__THREAD_ksp(%r3)  # load kernel stack from next->tss.ksp
@@ -185,6 +197,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
        lh      %r7,0x8a          # get svc number from lowcore
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 sysc_vtime:
@@ -234,6 +247,8 @@ sysc_work_loop:
 # One of the work bits is on. Find out which one.
 #
 sysc_work:
+       tm      __TI_flags+3(%r9),_TIF_MCCK_PENDING
+       bo      BASED(sysc_mcck_pending)
        tm      __TI_flags+3(%r9),_TIF_NEED_RESCHED
        bo      BASED(sysc_reschedule)
        tm      __TI_flags+3(%r9),_TIF_SIGPENDING
@@ -252,6 +267,14 @@ sysc_reschedule:
        la      %r14,BASED(sysc_work_loop)
        br      %r1                    # call scheduler
 
+#
+# _TIF_MCCK_PENDING is set, call handler
+#
+sysc_mcck_pending:
+       l       %r1,BASED(.Ls390_handle_mcck)
+       la      %r14,BASED(sysc_work_loop)
+       br      %r1                     # TIF bit will be cleared by handler
+
 #
 # _TIF_SIGPENDING is set, call do_signal
 #
@@ -430,6 +453,7 @@ pgm_check_handler:
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         bnz     BASED(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 ?
        bz      BASED(pgm_no_vtime)
@@ -468,6 +492,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 ?
        bz      BASED(pgm_no_vtime2)
@@ -493,6 +518,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 ?
        bz      BASED(pgm_no_vtime3)
@@ -521,6 +547,7 @@ io_int_handler:
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+16
         SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0
+       CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+16
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        bz      BASED(io_no_vtime)
@@ -578,15 +605,25 @@ io_work:
        lr      %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+3(%r9),_TIF_MCCK_PENDING
+       bo      BASED(io_mcck_pending)
        tm      __TI_flags+3(%r9),_TIF_NEED_RESCHED
        bo      BASED(io_reschedule)
        tm      __TI_flags+3(%r9),_TIF_SIGPENDING
        bo      BASED(io_sigpending)
        b       BASED(io_leave)
 
+#
+# _TIF_MCCK_PENDING is set, call handler
+#
+io_mcck_pending:
+       l       %r1,BASED(.Ls390_handle_mcck)
+       l       %r14,BASED(io_work_loop)
+       br      %r1                    # TIF bit will be cleared by handler
+
 #
 # _TIF_NEED_RESCHED is set, call schedule
 #      
@@ -621,6 +658,7 @@ ext_int_handler:
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+16
         SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0
+       CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        bz      BASED(ext_no_vtime)
@@ -642,19 +680,62 @@ ext_no_vtime:
 
         .globl mcck_int_handler
 mcck_int_handler:
-       STORE_TIMER __LC_ASYNC_ENTER_TIMER
+       spt     __LC_CPU_TIMER_SAVE_AREA        # revalidate cpu timer
+       lm      %r0,%r15,__LC_GPREGS_SAVE_AREA  # revalidate gprs
        SAVE_ALL_BASE __LC_SAVE_AREA+32
-        SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32,0
+       la      %r12,__LC_MCK_OLD_PSW
+       tm      __LC_MCCK_CODE,0x80     # system damage?
+       bo      BASED(mcck_int_main)    # yes -> rest of mcck code invalid
+       tm      __LC_MCCK_CODE+5,0x02   # stored cpu timer value valid?
+       bo      BASED(0f)
+       spt     __LC_LAST_UPDATE_TIMER  # revalidate cpu 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?
+       bno     BASED(mcck_no_vtime)    # no -> skip cleanup critical
+       tm      __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
        bz      BASED(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
+0:
+       tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
+       bno     BASED(mcck_int_main)    # no -> skip cleanup critical
+       tm      __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
+       bnz     BASED(mcck_int_main)    # from user -> load async stack
+       clc     __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_end)
+       bhe     BASED(mcck_int_main)
+       clc     __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_start)
+       bl      BASED(mcck_int_main)
+       l       %r14,BASED(.Lcleanup_critical)
+       basr    %r14,%r14
+mcck_int_main:
+       l       %r14,__LC_PANIC_STACK   # are we already on the panic stack?
+       slr     %r14,%r15
+       sra     %r14,PAGE_SHIFT
+       be      BASED(0f)
+       l       %r15,__LC_PANIC_STACK   # load panic stack
+0:     CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32
+       l       %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
+       la      %r2,SP_PTREGS(%r15)     # load pt_regs
        l       %r1,BASED(.Ls390_mcck)
-       basr    %r14,%r1          # call machine check handler
+       basr    %r14,%r1                # call machine check handler
+       tm      SP_PSW+1(%r15),0x01     # returning to user ?
+       bno     BASED(mcck_return)
+       l       %r1,__LC_KERNEL_STACK   # switch to kernel stack
+       s       %r1,BASED(.Lc_spsize)
+       mvc     SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+       xc      __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+       lr      %r15,%r1
+       stosm   __SF_EMPTY(%r15),0x04   # turn dat on
+       tm      __TI_flags+3(%r9),_TIF_MCCK_PENDING
+       bno     BASED(mcck_return)
+       l       %r1,BASED(.Ls390_handle_mcck)
+       basr    %r14,%r1                # call machine check handler
 mcck_return:
         RESTORE_ALL 0
 
@@ -742,7 +823,7 @@ cleanup_critical:
        clc     4(4,%r12),BASED(cleanup_table_sysc_work_loop)
        bl      BASED(0f)
        clc     4(4,%r12),BASED(cleanup_table_sysc_work_loop+4)
-       bl      BASED(cleanup_sysc_leave)
+       bl      BASED(cleanup_sysc_return)
 0:
        br      %r14
 
@@ -760,6 +841,7 @@ cleanup_system_call:
        mvc     __LC_SAVE_AREA(16),__LC_SAVE_AREA+16
 0:     st      %r13,__LC_SAVE_AREA+20
        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        st      %r15,__LC_SAVE_AREA+28
        lh      %r7,0x8a
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -834,6 +916,8 @@ cleanup_sysc_leave_insn:
  * Symbol constants
  */
 .Ls390_mcck:   .long  s390_do_machine_check
+.Ls390_handle_mcck:
+              .long  s390_handle_mcck
 .Ldo_IRQ:      .long  do_IRQ
 .Ldo_extint:   .long  do_extint
 .Ldo_signal:   .long  do_signal
index 51527ab..57ca75d 100644 (file)
@@ -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
@@ -249,6 +264,13 @@ sysc_reschedule:
        larl    %r14,sysc_work_loop
         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
 #
@@ -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,15 +647,24 @@ 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
        jo      io_sigpending
        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
 #      
@@ -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
index 7aea25d..9f3dff6 100644 (file)
@@ -91,13 +91,12 @@ void do_monitor_call(struct pt_regs *regs, long interruption_code)
                            (void *)(long) smp_processor_id());
 }
 
+extern void s390_handle_mcck(void);
 /*
  * The idle loop on a S390...
  */
 void default_idle(void)
 {
-       psw_t wait_psw;
-       unsigned long reg;
        int cpu, rc;
 
        local_irq_disable();
@@ -125,38 +124,17 @@ void default_idle(void)
                cpu_die();
 #endif
 
-       /* 
-        * Wait for external, I/O or machine check interrupt and
-        * switch off machine check bit after the wait has ended.
-        */
-       wait_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK | PSW_MASK_WAIT |
-               PSW_MASK_IO | PSW_MASK_EXT;
-#ifndef CONFIG_ARCH_S390X
-       asm volatile (
-               "    basr %0,0\n"
-               "0:  la   %0,1f-0b(%0)\n"
-               "    st   %0,4(%1)\n"
-               "    oi   4(%1),0x80\n"
-               "    lpsw 0(%1)\n"
-               "1:  la   %0,2f-1b(%0)\n"
-               "    st   %0,4(%1)\n"
-               "    oi   4(%1),0x80\n"
-               "    ni   1(%1),0xf9\n"
-               "    lpsw 0(%1)\n"
-               "2:"
-               : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
-#else /* CONFIG_ARCH_S390X */
-       asm volatile (
-               "    larl  %0,0f\n"
-               "    stg   %0,8(%1)\n"
-               "    lpswe 0(%1)\n"
-               "0:  larl  %0,1f\n"
-               "    stg   %0,8(%1)\n"
-               "    ni    1(%1),0xf9\n"
-               "    lpswe 0(%1)\n"
-               "1:"
-               : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
-#endif /* CONFIG_ARCH_S390X */
+       local_mcck_disable();
+       if (test_thread_flag(TIF_MCCK_PENDING)) {
+               local_mcck_enable();
+               local_irq_enable();
+               s390_handle_mcck();
+               return;
+       }
+
+       /* Wait for external, I/O or machine check interrupt. */
+       __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT |
+                       PSW_MASK_IO | PSW_MASK_EXT);
 }
 
 void cpu_idle(void)
index df83215..eb7be0a 100644 (file)
@@ -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;
index 93c71fe..50c3350 100644 (file)
@@ -773,13 +773,24 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
 
                *(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)
index ffa996c..5bb255e 100644 (file)
@@ -31,14 +31,14 @@ extern void css_reiterate_subchannels(void);
 extern struct workqueue_struct *slow_path_wq;
 extern struct work_struct slow_path_work;
 
-static void
+static NORET_TYPE void
 s390_handle_damage(char *msg)
 {
-       printk(KERN_EMERG "%s\n", msg);
 #ifdef CONFIG_SMP
        smp_send_stop();
 #endif
        disabled_wait((unsigned long) __builtin_return_address(0));
+       for(;;);
 }
 
 /*
@@ -122,40 +122,39 @@ repeat:
        return 0;
 }
 
+struct mcck_struct {
+       int kill_task;
+       int channel_report;
+       int warning;
+       unsigned long long mcck_code;
+};
+
+static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck);
+
 /*
- * machine check handler.
+ * Main machine check handler function. Will be called with interrupts enabled
+ * or disabled and machine checks enabled or disabled.
  */
 void
-s390_do_machine_check(void)
+s390_handle_mcck(void)
 {
-       struct mci *mci;
-
-       mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
+       unsigned long flags;
+       struct mcck_struct mcck;
 
-       if (mci->sd)            /* system damage */
-               s390_handle_damage("received system damage machine check\n");
+       /*
+        * Disable machine checks and get the current state of accumulated
+        * machine checks. Afterwards delete the old state and enable machine
+        * checks again.
+        */
+       local_irq_save(flags);
+       local_mcck_disable();
+       mcck = __get_cpu_var(cpu_mcck);
+       memset(&__get_cpu_var(cpu_mcck), 0, sizeof(struct mcck_struct));
+       clear_thread_flag(TIF_MCCK_PENDING);
+       local_mcck_enable();
+       local_irq_restore(flags);
 
-       if (mci->pd)            /* instruction processing damage */
-               s390_handle_damage("received instruction processing "
-                                  "damage machine check\n");
-
-       if (mci->se)            /* storage error uncorrected */
-               s390_handle_damage("received storage error uncorrected "
-                                  "machine check\n");
-
-       if (mci->sc)            /* storage error corrected */
-               printk(KERN_WARNING
-                      "received storage error corrected machine check\n");
-
-       if (mci->ke)            /* storage key-error uncorrected */
-               s390_handle_damage("received storage key-error uncorrected "
-                                  "machine check\n");
-
-       if (mci->ds && mci->fa) /* storage degradation */
-               s390_handle_damage("received storage degradation machine "
-                                  "check\n");
-
-       if (mci->cp)            /* channel report word pending */
+       if (mcck.channel_report)
                up(&m_sem);
 
 #ifdef CONFIG_MACHCHK_WARNING
@@ -168,7 +167,7 @@ s390_do_machine_check(void)
  * On VM we only get one interrupt per virtally presented machinecheck.
  * Though one suffices, we may get one interrupt per (virtual) processor.
  */
-       if (mci->w) {   /* WARNING pending ? */
+       if (mcck.warning) {     /* WARNING pending ? */
                static int mchchk_wng_posted = 0;
                /*
                 * Use single machine clear, as we cannot handle smp right now
@@ -178,6 +177,261 @@ s390_do_machine_check(void)
                        kill_proc(1, SIGPWR, 1);
        }
 #endif
+
+       if (mcck.kill_task) {
+               local_irq_enable();
+               printk(KERN_EMERG "mcck: Terminating task because of machine "
+                      "malfunction (code 0x%016llx).\n", mcck.mcck_code);
+               printk(KERN_EMERG "mcck: task: %s, pid: %d.\n",
+                      current->comm, current->pid);
+               do_exit(SIGSEGV);
+       }
+}
+
+/*
+ * returns 0 if all registers could be validated
+ * returns 1 otherwise
+ */
+static int
+s390_revalidate_registers(struct mci *mci)
+{
+       int kill_task;
+       u64 tmpclock;
+       u64 zero;
+       void *fpt_save_area, *fpt_creg_save_area;
+
+       kill_task = 0;
+       zero = 0;
+       /* General purpose registers */
+       if (!mci->gr)
+               /*
+                * General purpose registers couldn't be restored and have
+                * unknown contents. Process needs to be terminated.
+                */
+               kill_task = 1;
+
+       /* Revalidate floating point registers */
+       if (!mci->fp)
+               /*
+                * Floating point registers can't be restored and
+                * therefore the process needs to be terminated.
+                */
+               kill_task = 1;
+
+#ifndef __s390x__
+       asm volatile("ld 0,0(%0)\n"
+                    "ld 2,8(%0)\n"
+                    "ld 4,16(%0)\n"
+                    "ld 6,24(%0)"
+                    : : "a" (&S390_lowcore.floating_pt_save_area));
+#endif
+
+       if (MACHINE_HAS_IEEE) {
+#ifdef __s390x__
+               fpt_save_area = &S390_lowcore.floating_pt_save_area;
+               fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area;
+#else
+               fpt_save_area = (void *) S390_lowcore.extended_save_area_addr;
+               fpt_creg_save_area = fpt_save_area+128;
+#endif
+               /* Floating point control register */
+               if (!mci->fc) {
+                       /*
+                        * Floating point control register can't be restored.
+                        * Task will be terminated.
+                        */
+                       asm volatile ("lfpc 0(%0)" : : "a" (&zero));
+                       kill_task = 1;
+
+               }
+               else
+                       asm volatile (
+                               "lfpc 0(%0)"
+                               : : "a" (fpt_creg_save_area));
+
+               asm volatile("ld  0,0(%0)\n"
+                            "ld  1,8(%0)\n"
+                            "ld  2,16(%0)\n"
+                            "ld  3,24(%0)\n"
+                            "ld  4,32(%0)\n"
+                            "ld  5,40(%0)\n"
+                            "ld  6,48(%0)\n"
+                            "ld  7,56(%0)\n"
+                            "ld  8,64(%0)\n"
+                            "ld  9,72(%0)\n"
+                            "ld 10,80(%0)\n"
+                            "ld 11,88(%0)\n"
+                            "ld 12,96(%0)\n"
+                            "ld 13,104(%0)\n"
+                            "ld 14,112(%0)\n"
+                            "ld 15,120(%0)\n"
+                            : : "a" (fpt_save_area));
+       }
+
+       /* Revalidate access registers */
+       asm volatile("lam 0,15,0(%0)"
+                    : : "a" (&S390_lowcore.access_regs_save_area));
+       if (!mci->ar)
+               /*
+                * Access registers have unknown contents.
+                * Terminating task.
+                */
+               kill_task = 1;
+
+       /* Revalidate control registers */
+       if (!mci->cr)
+               /*
+                * Control registers have unknown contents.
+                * Can't recover and therefore stopping machine.
+                */
+               s390_handle_damage("invalid control registers.");
+       else
+#ifdef __s390x__
+               asm volatile("lctlg 0,15,0(%0)"
+                            : : "a" (&S390_lowcore.cregs_save_area));
+#else
+               asm volatile("lctl 0,15,0(%0)"
+                            : : "a" (&S390_lowcore.cregs_save_area));
+#endif
+
+       /*
+        * We don't even try to revalidate the TOD register, since we simply
+        * can't write something sensible into that register.
+        */
+
+#ifdef __s390x__
+       /*
+        * See if we can revalidate the TOD programmable register with its
+        * old contents (should be zero) otherwise set it to zero.
+        */
+       if (!mci->pr)
+               asm volatile("sr 0,0\n"
+                            "sckpf"
+                            : : : "0", "cc");
+       else
+               asm volatile(
+                       "l 0,0(%0)\n"
+                       "sckpf"
+                       : : "a" (&S390_lowcore.tod_progreg_save_area) : "0", "cc");
+#endif
+
+       /* Revalidate clock comparator register */
+       asm volatile ("stck 0(%1)\n"
+                     "sckc 0(%1)"
+                     : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory");
+
+       /* Check if old PSW is valid */
+       if (!mci->wp)
+               /*
+                * Can't tell if we come from user or kernel mode
+                * -> stopping machine.
+                */
+               s390_handle_damage("old psw invalid.");
+
+       if (!mci->ms || !mci->pm || !mci->ia)
+               kill_task = 1;
+
+       return kill_task;
+}
+
+/*
+ * machine check handler.
+ */
+void
+s390_do_machine_check(struct pt_regs *regs)
+{
+       struct mci *mci;
+       struct mcck_struct *mcck;
+       int umode;
+
+       mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
+       mcck = &__get_cpu_var(cpu_mcck);
+       umode = user_mode(regs);
+
+       if (mci->sd)
+               /* System damage -> stopping machine */
+               s390_handle_damage("received system damage machine check.");
+
+       if (mci->pd) {
+               if (mci->b) {
+                       /* Processing backup -> verify if we can survive this */
+                       u64 z_mcic, o_mcic, t_mcic;
+#ifdef __s390x__
+                       z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<29);
+                       o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 |
+                                 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 |
+                                 1ULL<<30 | 1ULL<<21 | 1ULL<<20 | 1ULL<<17 |
+                                 1ULL<<16);
+#else
+                       z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<57 | 1ULL<<50 |
+                                 1ULL<<29);
+                       o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 |
+                                 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 |
+                                 1ULL<<30 | 1ULL<<20 | 1ULL<<17 | 1ULL<<16);
+#endif
+                       t_mcic = *(u64 *)mci;
+
+                       if (((t_mcic & z_mcic) != 0) ||
+                           ((t_mcic & o_mcic) != o_mcic)) {
+                               s390_handle_damage("processing backup machine "
+                                                  "check with damage.");
+                       }
+                       if (!umode)
+                               s390_handle_damage("processing backup machine "
+                                                  "check in kernel mode.");
+                       mcck->kill_task = 1;
+                       mcck->mcck_code = *(unsigned long long *) mci;
+               }
+               else {
+                       /* Processing damage -> stopping machine */
+                       s390_handle_damage("received instruction processing "
+                                          "damage machine check.");
+               }
+       }
+       if (s390_revalidate_registers(mci)) {
+               if (umode) {
+                       /*
+                        * Couldn't restore all register contents while in
+                        * user mode -> mark task for termination.
+                        */
+                       mcck->kill_task = 1;
+                       mcck->mcck_code = *(unsigned long long *) mci;
+                       set_thread_flag(TIF_MCCK_PENDING);
+               }
+               else
+                       /*
+                        * Couldn't restore all register contents while in
+                        * kernel mode -> stopping machine.
+                        */
+                       s390_handle_damage("unable to revalidate registers.");
+       }
+
+       if (mci->se)
+               /* Storage error uncorrected */
+               s390_handle_damage("received storage error uncorrected "
+                                  "machine check.");
+
+       if (mci->ke)
+               /* Storage key-error uncorrected */
+               s390_handle_damage("received storage key-error uncorrected "
+                                  "machine check.");
+
+       if (mci->ds && mci->fa)
+               /* Storage degradation */
+               s390_handle_damage("received storage degradation machine "
+                                  "check.");
+
+       if (mci->cp) {
+               /* Channel report word pending */
+               mcck->channel_report = 1;
+               set_thread_flag(TIF_MCCK_PENDING);
+       }
+
+       if (mci->w) {
+               /* Warning pending */
+               mcck->warning = 1;
+               set_thread_flag(TIF_MCCK_PENDING);
+       }
 }
 
 /*
@@ -189,9 +443,8 @@ static int
 machine_check_init(void)
 {
        init_MUTEX_LOCKED(&m_sem);
-       ctl_clear_bit(14, 25);  /* disable damage MCH */
-       ctl_set_bit(14, 26);    /* enable degradation MCH */
-       ctl_set_bit(14, 27);    /* enable system recovery MCH */
+       ctl_clear_bit(14, 25);  /* disable external damage MCH */
+       ctl_set_bit(14, 27);    /* enable system recovery MCH */
 #ifdef CONFIG_MACHCHK_WARNING
        ctl_set_bit(14, 24);    /* enable warning MCH */
 #endif
index 7e26f0f..4eaa701 100644 (file)
@@ -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 */
 };
 
 /*
index df5172f..76b5b19 100644 (file)
 
 #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 */
index fb46e90..8bd14de 100644 (file)
@@ -206,6 +206,18 @@ unsigned long get_wchan(struct task_struct *p);
        asm volatile ("ex 0,%0" : : "i" (__LC_DIAG44_OPCODE) : "memory")
 #endif /* __s390x__ */
 
+/*
+ * Set PSW to specified value.
+ */
+static inline void __load_psw(psw_t psw)
+{
+#ifndef __s390x__
+       asm volatile ("lpsw  0(%0)" : : "a" (&psw), "m" (psw) : "cc" );
+#else
+       asm volatile ("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc" );
+#endif
+}
+
 /*
  * Set PSW mask to specified value, while leaving the
  * PSW addr pointing to the next instruction.
@@ -214,8 +226,8 @@ unsigned long get_wchan(struct task_struct *p);
 static inline void __load_psw_mask (unsigned long mask)
 {
        unsigned long addr;
-
        psw_t psw;
+
        psw.mask = mask;
 
 #ifndef __s390x__
@@ -241,30 +253,8 @@ static inline void __load_psw_mask (unsigned long mask)
  */
 static inline void enabled_wait(void)
 {
-       unsigned long reg;
-       psw_t wait_psw;
-
-       wait_psw.mask = PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT |
-               PSW_MASK_MCHECK | PSW_MASK_WAIT | PSW_DEFAULT_KEY;
-#ifndef __s390x__
-       asm volatile (
-               "    basr %0,0\n"
-               "0:  la   %0,1f-0b(%0)\n"
-               "    st   %0,4(%1)\n"
-               "    oi   4(%1),0x80\n"
-               "    lpsw 0(%1)\n"
-               "1:"
-               : "=&a" (reg) : "a" (&wait_psw), "m" (wait_psw)
-               : "memory", "cc" );
-#else /* __s390x__ */
-       asm volatile (
-               "    larl  %0,0f\n"
-               "    stg   %0,8(%1)\n"
-               "    lpswe 0(%1)\n"
-               "0:"
-               : "=&a" (reg) : "a" (&wait_psw), "m" (wait_psw)
-               : "memory", "cc" );
-#endif /* __s390x__ */
+       __load_psw_mask(PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT |
+                       PSW_MASK_MCHECK | PSW_MASK_WAIT | PSW_DEFAULT_KEY);
 }
 
 /*
@@ -273,13 +263,11 @@ static inline void enabled_wait(void)
 
 static inline void disabled_wait(unsigned long code)
 {
-        char psw_buffer[2*sizeof(psw_t)];
         unsigned long ctl_buf;
-        psw_t *dw_psw = (psw_t *)(((unsigned long) &psw_buffer+sizeof(psw_t)-1)
-                                  & -sizeof(psw_t));
+        psw_t dw_psw;
 
-        dw_psw->mask = PSW_BASE_BITS | PSW_MASK_WAIT;
-        dw_psw->addr = code;
+        dw_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT;
+        dw_psw.addr = code;
         /* 
          * Store status and then load disabled wait psw,
          * the processor is dead afterwards
@@ -301,7 +289,7 @@ static inline void disabled_wait(unsigned long code)
                       "    oi    0x1c0,0x10\n" /* fake protection bit */
                       "    lpsw 0(%1)"
                       : "=m" (ctl_buf)
-                     : "a" (dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc" );
+                     : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc" );
 #else /* __s390x__ */
         asm volatile ("    stctg 0,0,0(%2)\n"
                       "    ni    4(%2),0xef\n" /* switch off protection */
@@ -333,7 +321,7 @@ static inline void disabled_wait(unsigned long code)
                       "    oi    0x384(1),0x10\n" /* fake protection bit */
                       "    lpswe 0(%1)"
                       : "=m" (ctl_buf)
-                     : "a" (dw_psw), "a" (&ctl_buf),
+                     : "a" (&dw_psw), "a" (&ctl_buf),
                        "m" (dw_psw) : "cc", "0", "1");
 #endif /* __s390x__ */
 }
index 4eff8f2..fc7c96e 100644 (file)
@@ -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)
index 81514d7..e3cb3ce 100644 (file)
@@ -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 long old, unsigned long new, int size)
 
 #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 long old, unsigned long new, int size)
 
 #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 long old, unsigned long new, int size)
 /* 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);
index fe101d4..6c18a3f 100644 (file)
@@ -96,6 +96,7 @@ static inline struct thread_info *current_thread_info(void)
 #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 *current_thread_info(void)
 #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)