Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 77fa2245 authored by Heiko Carstens's avatar Heiko Carstens Committed by Linus Torvalds
Browse files

[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: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f901e5d1
Loading
Loading
Loading
Loading
+93 −9
Original line number Original line Diff line number Diff line
@@ -7,6 +7,7 @@
 *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
 *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
 *               Hartmut Penner (hp@de.ibm.com),
 *               Hartmut Penner (hp@de.ibm.com),
 *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
 *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
 *		 Heiko Carstens <heiko.carstens@de.ibm.com>
 */
 */


#include <linux/sys.h>
#include <linux/sys.h>
@@ -49,9 +50,9 @@ SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
SP_TRAP      =  STACK_FRAME_OVERHEAD + __PT_TRAP
SP_TRAP      =  STACK_FRAME_OVERHEAD + __PT_TRAP
SP_SIZE      =  STACK_FRAME_OVERHEAD + __PT_SIZE
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_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_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE  = 1 << STACK_SHIFT
STACK_SIZE  = 1 << STACK_SHIFT
@@ -121,7 +122,11 @@ STACK_SIZE = 1 << STACK_SHIFT
	bz	BASED(stack_overflow)
	bz	BASED(stack_overflow)
3:
3:
#endif
#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
	mvc	SP_PSW(8,%r15),0(%r12)	# move user PSW to stack
	la	%r12,\psworg
	la	%r12,\psworg
	st	%r2,SP_ORIG_R2(%r15)	# store original content of gpr 2
	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
        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
        lctl    %c9,%c11,__THREAD_per(%r3)	# Nope we didn't
__switch_to_noper:
__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
        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
	st	%r15,__THREAD_ksp(%r2)	# store kernel stack to prev->tss.ksp
	l	%r15,__THREAD_ksp(%r3)	# load kernel stack from next->tss.ksp
	l	%r15,__THREAD_ksp(%r3)	# load kernel stack from next->tss.ksp
@@ -185,6 +197,7 @@ system_call:
sysc_saveall:
sysc_saveall:
	SAVE_ALL_BASE __LC_SAVE_AREA
	SAVE_ALL_BASE __LC_SAVE_AREA
        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
        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
	lh	%r7,0x8a	  # get svc number from lowcore
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
sysc_vtime:
sysc_vtime:
@@ -234,6 +247,8 @@ sysc_work_loop:
# One of the work bits is on. Find out which one.
# One of the work bits is on. Find out which one.
#
#
sysc_work:
sysc_work:
	tm	__TI_flags+3(%r9),_TIF_MCCK_PENDING
	bo	BASED(sysc_mcck_pending)
	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
	bo	BASED(sysc_reschedule)
	bo	BASED(sysc_reschedule)
	tm	__TI_flags+3(%r9),_TIF_SIGPENDING
	tm	__TI_flags+3(%r9),_TIF_SIGPENDING
@@ -252,6 +267,14 @@ sysc_reschedule:
	la      %r14,BASED(sysc_work_loop)
	la      %r14,BASED(sysc_work_loop)
	br      %r1		       # call scheduler
	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
# _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
        tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
        bnz     BASED(pgm_per)           # got per exception -> special case
        bnz     BASED(pgm_per)           # got per exception -> special case
	SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
	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
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	bz	BASED(pgm_no_vtime)
	bz	BASED(pgm_no_vtime)
@@ -468,6 +492,7 @@ pgm_per:
#
#
pgm_per_std:
pgm_per_std:
	SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
	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
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	bz	BASED(pgm_no_vtime2)
	bz	BASED(pgm_no_vtime2)
@@ -493,6 +518,7 @@ pgm_no_vtime2:
#
#
pgm_svcper:
pgm_svcper:
	SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
	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
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	bz	BASED(pgm_no_vtime3)
	bz	BASED(pgm_no_vtime3)
@@ -521,6 +547,7 @@ io_int_handler:
	stck	__LC_INT_CLOCK
	stck	__LC_INT_CLOCK
	SAVE_ALL_BASE __LC_SAVE_AREA+16
	SAVE_ALL_BASE __LC_SAVE_AREA+16
        SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0
        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
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	bz	BASED(io_no_vtime)
	bz	BASED(io_no_vtime)
@@ -578,15 +605,25 @@ io_work:
	lr	%r15,%r1
	lr	%r15,%r1
#
#
# One of the work bits is on. Find out which one.
# 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:
io_work_loop:
	tm	__TI_flags+3(%r9),_TIF_MCCK_PENDING
	bo      BASED(io_mcck_pending)
	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
	bo	BASED(io_reschedule)
	bo	BASED(io_reschedule)
	tm	__TI_flags+3(%r9),_TIF_SIGPENDING
	tm	__TI_flags+3(%r9),_TIF_SIGPENDING
	bo	BASED(io_sigpending)
	bo	BASED(io_sigpending)
	b	BASED(io_leave)
	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
# _TIF_NEED_RESCHED is set, call schedule
#	
#	
@@ -621,6 +658,7 @@ ext_int_handler:
	stck	__LC_INT_CLOCK
	stck	__LC_INT_CLOCK
	SAVE_ALL_BASE __LC_SAVE_AREA+16
	SAVE_ALL_BASE __LC_SAVE_AREA+16
        SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0
        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
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	bz	BASED(ext_no_vtime)
	bz	BASED(ext_no_vtime)
@@ -642,19 +680,62 @@ ext_no_vtime:


        .globl mcck_int_handler
        .globl mcck_int_handler
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_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
#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)
	bz	BASED(mcck_no_vtime)
	UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
	UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
mcck_no_vtime:
mcck_no_vtime:
#endif
#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)
	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:
mcck_return:
        RESTORE_ALL 0
        RESTORE_ALL 0


@@ -742,7 +823,7 @@ cleanup_critical:
	clc	4(4,%r12),BASED(cleanup_table_sysc_work_loop)
	clc	4(4,%r12),BASED(cleanup_table_sysc_work_loop)
	bl	BASED(0f)
	bl	BASED(0f)
	clc	4(4,%r12),BASED(cleanup_table_sysc_work_loop+4)
	clc	4(4,%r12),BASED(cleanup_table_sysc_work_loop+4)
	bl	BASED(cleanup_sysc_leave)
	bl	BASED(cleanup_sysc_return)
0:
0:
	br	%r14
	br	%r14


@@ -760,6 +841,7 @@ cleanup_system_call:
	mvc	__LC_SAVE_AREA(16),__LC_SAVE_AREA+16
	mvc	__LC_SAVE_AREA(16),__LC_SAVE_AREA+16
0:	st	%r13,__LC_SAVE_AREA+20
0:	st	%r13,__LC_SAVE_AREA+20
	SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
	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
	st	%r15,__LC_SAVE_AREA+28
	lh	%r7,0x8a
	lh	%r7,0x8a
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -834,6 +916,8 @@ cleanup_sysc_leave_insn:
 * Symbol constants
 * Symbol constants
 */
 */
.Ls390_mcck:   .long  s390_do_machine_check
.Ls390_mcck:   .long  s390_do_machine_check
.Ls390_handle_mcck:
	       .long  s390_handle_mcck
.Ldo_IRQ:      .long  do_IRQ
.Ldo_IRQ:      .long  do_IRQ
.Ldo_extint:   .long  do_extint
.Ldo_extint:   .long  do_extint
.Ldo_signal:   .long  do_signal
.Ldo_signal:   .long  do_signal
+88 −9
Original line number Original line Diff line number Diff line
@@ -7,6 +7,7 @@
 *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
 *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
 *               Hartmut Penner (hp@de.ibm.com),
 *               Hartmut Penner (hp@de.ibm.com),
 *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
 *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
 *		 Heiko Carstens <heiko.carstens@de.ibm.com>
 */
 */


#include <linux/sys.h>
#include <linux/sys.h>
@@ -52,9 +53,9 @@ SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE  = 1 << STACK_SHIFT
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_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)
#define BASED(name) name-system_call(%r13)


@@ -114,7 +115,11 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
	jz	stack_overflow
	jz	stack_overflow
3:
3:
#endif
#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
	mvc     SP_PSW(16,%r15),0(%r12)	# move user PSW to stack
	la	%r12,\psworg
	la	%r12,\psworg
	stg	%r2,SP_ORIG_R2(%r15)	# store original content of gpr 2
	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
        je      __switch_to_noper            # we got away without bashing TLB's
        lctlg   %c9,%c11,__THREAD_per(%r3)	# Nope we didn't
        lctlg   %c9,%c11,__THREAD_per(%r3)	# Nope we didn't
__switch_to_noper:
__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
        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
	stg	%r15,__THREAD_ksp(%r2)	# store kernel stack to prev->tss.ksp
	lg	%r15,__THREAD_ksp(%r3)	# load kernel stack from next->tss.ksp
	lg	%r15,__THREAD_ksp(%r3)	# load kernel stack from next->tss.ksp
@@ -176,6 +188,7 @@ system_call:
sysc_saveall:
sysc_saveall:
	SAVE_ALL_BASE __LC_SAVE_AREA
	SAVE_ALL_BASE __LC_SAVE_AREA
        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
        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
	llgh    %r7,__LC_SVC_INT_CODE # get svc number from lowcore
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
sysc_vtime:
sysc_vtime:
@@ -232,6 +245,8 @@ sysc_work_loop:
# One of the work bits is on. Find out which one.
# One of the work bits is on. Find out which one.
#
#
sysc_work:
sysc_work:
	tm	__TI_flags+7(%r9),_TIF_MCCK_PENDING
	jo	sysc_mcck_pending
	tm	__TI_flags+7(%r9),_TIF_NEED_RESCHED
	tm	__TI_flags+7(%r9),_TIF_NEED_RESCHED
	jo	sysc_reschedule
	jo	sysc_reschedule
	tm	__TI_flags+7(%r9),_TIF_SIGPENDING
	tm	__TI_flags+7(%r9),_TIF_SIGPENDING
@@ -249,6 +264,13 @@ sysc_reschedule:
	larl    %r14,sysc_work_loop
	larl    %r14,sysc_work_loop
        jg      schedule            # return point is sysc_return
        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
# _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
        tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
        jnz     pgm_per                  # got per exception -> special case
        jnz     pgm_per                  # got per exception -> special case
	SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
	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
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	jz	pgm_no_vtime
	jz	pgm_no_vtime
@@ -512,6 +535,7 @@ pgm_per:
#
#
pgm_per_std:
pgm_per_std:
	SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
	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
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	jz	pgm_no_vtime2
	jz	pgm_no_vtime2
@@ -537,6 +561,7 @@ pgm_no_vtime2:
#
#
pgm_svcper:
pgm_svcper:
	SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
	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
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	jz	pgm_no_vtime3
	jz	pgm_no_vtime3
@@ -564,6 +589,7 @@ io_int_handler:
	stck	__LC_INT_CLOCK
	stck	__LC_INT_CLOCK
	SAVE_ALL_BASE __LC_SAVE_AREA+32
	SAVE_ALL_BASE __LC_SAVE_AREA+32
        SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0
        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
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	jz	io_no_vtime
	jz	io_no_vtime
@@ -621,15 +647,24 @@ io_work:
	lgr	%r15,%r1
	lgr	%r15,%r1
#
#
# One of the work bits is on. Find out which one.
# 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:
io_work_loop:
	tm	__TI_flags+7(%r9),_TIF_MCCK_PENDING
	jo	io_mcck_pending
	tm	__TI_flags+7(%r9),_TIF_NEED_RESCHED
	tm	__TI_flags+7(%r9),_TIF_NEED_RESCHED
	jo	io_reschedule
	jo	io_reschedule
	tm	__TI_flags+7(%r9),_TIF_SIGPENDING
	tm	__TI_flags+7(%r9),_TIF_SIGPENDING
	jo	io_sigpending
	jo	io_sigpending
	j	io_leave
	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
# _TIF_NEED_RESCHED is set, call schedule
#	
#	
@@ -661,6 +696,7 @@ ext_int_handler:
	stck	__LC_INT_CLOCK
	stck	__LC_INT_CLOCK
	SAVE_ALL_BASE __LC_SAVE_AREA+32
	SAVE_ALL_BASE __LC_SAVE_AREA+32
        SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0
        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
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
	jz	ext_no_vtime
	jz	ext_no_vtime
@@ -680,18 +716,60 @@ ext_no_vtime:
 */
 */
        .globl mcck_int_handler
        .globl mcck_int_handler
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_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
#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
	jz	mcck_no_vtime
	UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
	UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
mcck_no_vtime:
mcck_no_vtime:
#endif
#endif
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
	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:
mcck_return:
        RESTORE_ALL 0
        RESTORE_ALL 0


@@ -775,7 +853,7 @@ cleanup_critical:
	clc	8(8,%r12),BASED(cleanup_table_sysc_work_loop)
	clc	8(8,%r12),BASED(cleanup_table_sysc_work_loop)
	jl	0f
	jl	0f
	clc	8(8,%r12),BASED(cleanup_table_sysc_work_loop+8)
	clc	8(8,%r12),BASED(cleanup_table_sysc_work_loop+8)
	jl	cleanup_sysc_leave
	jl	cleanup_sysc_return
0:
0:
	br	%r14
	br	%r14


@@ -793,6 +871,7 @@ cleanup_system_call:
	mvc	__LC_SAVE_AREA(32),__LC_SAVE_AREA+32
	mvc	__LC_SAVE_AREA(32),__LC_SAVE_AREA+32
0:	stg	%r13,__LC_SAVE_AREA+40
0:	stg	%r13,__LC_SAVE_AREA+40
	SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
	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
	stg	%r15,__LC_SAVE_AREA+56
	llgh	%r7,__LC_SVC_INT_CODE
	llgh	%r7,__LC_SVC_INT_CODE
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+12 −34
Original line number Original line Diff line number Diff line
@@ -91,13 +91,12 @@ void do_monitor_call(struct pt_regs *regs, long interruption_code)
			    (void *)(long) smp_processor_id());
			    (void *)(long) smp_processor_id());
}
}


extern void s390_handle_mcck(void);
/*
/*
 * The idle loop on a S390...
 * The idle loop on a S390...
 */
 */
void default_idle(void)
void default_idle(void)
{
{
	psw_t wait_psw;
	unsigned long reg;
	int cpu, rc;
	int cpu, rc;


	local_irq_disable();
	local_irq_disable();
@@ -125,38 +124,17 @@ void default_idle(void)
		cpu_die();
		cpu_die();
#endif
#endif


	/* 
	local_mcck_disable();
	 * Wait for external, I/O or machine check interrupt and
	if (test_thread_flag(TIF_MCCK_PENDING)) {
	 * switch off machine check bit after the wait has ended.
		local_mcck_enable();
	 */
		local_irq_enable();
	wait_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK | PSW_MASK_WAIT |
		s390_handle_mcck();
		PSW_MASK_IO | PSW_MASK_EXT;
		return;
#ifndef CONFIG_ARCH_S390X
	}
	asm volatile (

		"    basr %0,0\n"
	/* Wait for external, I/O or machine check interrupt. */
		"0:  la   %0,1f-0b(%0)\n"
	__load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT |
		"    st   %0,4(%1)\n"
			PSW_MASK_IO | PSW_MASK_EXT);
		"    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 */
}
}


void cpu_idle(void)
void cpu_idle(void)
+10 −3
Original line number Original line Diff line number Diff line
@@ -414,7 +414,8 @@ setup_lowcore(void)
	lc->program_new_psw.mask = PSW_KERNEL_BITS;
	lc->program_new_psw.mask = PSW_KERNEL_BITS;
	lc->program_new_psw.addr =
	lc->program_new_psw.addr =
		PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
		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 =
	lc->mcck_new_psw.addr =
		PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
		PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
	lc->io_new_psw.mask = PSW_KERNEL_BITS;
	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->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
	lc->async_stack = (unsigned long)
	lc->async_stack = (unsigned long)
		__alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
		__alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
#ifdef CONFIG_CHECK_STACK
	lc->panic_stack = (unsigned long)
	lc->panic_stack = (unsigned long)
		__alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE;
		__alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE;
#endif
	lc->current_task = (unsigned long) init_thread_union.thread_info.task;
	lc->current_task = (unsigned long) init_thread_union.thread_info.task;
	lc->thread_info = (unsigned long) &init_thread_union;
	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
#ifdef CONFIG_ARCH_S390X
	if (MACHINE_HAS_DIAG44)
	if (MACHINE_HAS_DIAG44)
		lc->diag44_opcode = 0x83000044;
		lc->diag44_opcode = 0x83000044;
+12 −1
Original line number Original line Diff line number Diff line
@@ -773,13 +773,24 @@ void __init smp_prepare_cpus(unsigned int max_cpus)


		*(lowcore_ptr[i]) = S390_lowcore;
		*(lowcore_ptr[i]) = S390_lowcore;
		lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE);
		lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE);
#ifdef CONFIG_CHECK_STACK
		stack = __get_free_pages(GFP_KERNEL,0);
		stack = __get_free_pages(GFP_KERNEL,0);
		if (stack == 0ULL)
		if (stack == 0ULL)
			panic("smp_boot_cpus failed to allocate memory\n");
			panic("smp_boot_cpus failed to allocate memory\n");
		lowcore_ptr[i]->panic_stack = stack + (PAGE_SIZE);
		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
#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()]);
	set_prefix((u32)(unsigned long) lowcore_ptr[smp_processor_id()]);


	for_each_cpu(cpu)
	for_each_cpu(cpu)
Loading