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

Commit 1e54622e authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Martin Schwidefsky
Browse files

[S390] cleanup lowcore access from program checks



Read all required fields for program checks from the lowcore in the
first level interrupt handler in entry[64].S. If the context that
caused the fault was enabled for interrupts we can now re-enable the
irqs in entry[64].S.

Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 84afdcee
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -84,6 +84,7 @@ int main(void)
	DEFINE(__LC_SVC_INT_CODE, offsetof(struct _lowcore, svc_code));
	DEFINE(__LC_SVC_INT_CODE, offsetof(struct _lowcore, svc_code));
	DEFINE(__LC_PGM_ILC, offsetof(struct _lowcore, pgm_ilc));
	DEFINE(__LC_PGM_ILC, offsetof(struct _lowcore, pgm_ilc));
	DEFINE(__LC_PGM_INT_CODE, offsetof(struct _lowcore, pgm_code));
	DEFINE(__LC_PGM_INT_CODE, offsetof(struct _lowcore, pgm_code));
	DEFINE(__LC_TRANS_EXC_CODE, offsetof(struct _lowcore, trans_exc_code));
	DEFINE(__LC_PER_ATMID, offsetof(struct _lowcore, per_perc_atmid));
	DEFINE(__LC_PER_ATMID, offsetof(struct _lowcore, per_perc_atmid));
	DEFINE(__LC_PER_ADDRESS, offsetof(struct _lowcore, per_address));
	DEFINE(__LC_PER_ADDRESS, offsetof(struct _lowcore, per_address));
	DEFINE(__LC_PER_ACCESS_ID, offsetof(struct _lowcore, per_access_id));
	DEFINE(__LC_PER_ACCESS_ID, offsetof(struct _lowcore, per_access_id));
+10 −25
Original line number Original line Diff line number Diff line
@@ -72,25 +72,9 @@ STACK_SIZE = 1 << STACK_SHIFT
	l	%r1,BASED(.Ltrace_irq_off_caller)
	l	%r1,BASED(.Ltrace_irq_off_caller)
	basr	%r14,%r1
	basr	%r14,%r1
	.endm
	.endm

	.macro	TRACE_IRQS_CHECK_ON
	tm	SP_PSW(%r15),0x03	# irqs enabled?
	bz	BASED(0f)
	TRACE_IRQS_ON
0:
	.endm

	.macro	TRACE_IRQS_CHECK_OFF
	tm	SP_PSW(%r15),0x03	# irqs enabled?
	bz	BASED(0f)
	TRACE_IRQS_OFF
0:
	.endm
#else
#else
#define TRACE_IRQS_ON
#define TRACE_IRQS_ON
#define TRACE_IRQS_OFF
#define TRACE_IRQS_OFF
#define TRACE_IRQS_CHECK_ON
#define TRACE_IRQS_CHECK_OFF
#endif
#endif


#ifdef CONFIG_LOCKDEP
#ifdef CONFIG_LOCKDEP
@@ -198,6 +182,12 @@ STACK_SIZE = 1 << STACK_SHIFT
	lpsw	\psworg			# back to caller
	lpsw	\psworg			# back to caller
	.endm
	.endm


	.macro REENABLE_IRQS
	mvc	__SF_EMPTY(1,%r15),SP_PSW(%r15)
	ni	__SF_EMPTY(%r15),0xbf
	ssm	__SF_EMPTY(%r15)
	.endm

/*
/*
 * Scheduler resume function, called by switch_to
 * Scheduler resume function, called by switch_to
 *  gpr2 = (task_struct *) prev
 *  gpr2 = (task_struct *) prev
@@ -440,13 +430,11 @@ kernel_execve:
	br	%r14
	br	%r14
	# execve succeeded.
	# execve succeeded.
0:	stnsm	__SF_EMPTY(%r15),0xfc	# disable interrupts
0:	stnsm	__SF_EMPTY(%r15),0xfc	# disable interrupts
	TRACE_IRQS_OFF
	l	%r15,__LC_KERNEL_STACK	# load ksp
	l	%r15,__LC_KERNEL_STACK	# load ksp
	s	%r15,BASED(.Lc_spsize)	# make room for registers & psw
	s	%r15,BASED(.Lc_spsize)	# make room for registers & psw
	l	%r9,__LC_THREAD_INFO
	l	%r9,__LC_THREAD_INFO
	mvc	SP_PTREGS(__PT_SIZE,%r15),0(%r12)	# copy pt_regs
	mvc	SP_PTREGS(__PT_SIZE,%r15),0(%r12)	# copy pt_regs
	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
	TRACE_IRQS_ON
	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
	l	%r1,BASED(.Lexecve_tail)
	l	%r1,BASED(.Lexecve_tail)
	basr	%r14,%r1
	basr	%r14,%r1
@@ -483,9 +471,10 @@ pgm_check_handler:
	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_SYNC_ENTER_TIMER
	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
pgm_no_vtime:
pgm_no_vtime:
	TRACE_IRQS_CHECK_OFF
	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
	l	%r3,__LC_PGM_ILC	# load program interruption code
	l	%r3,__LC_PGM_ILC	# load program interruption code
	l	%r4,__LC_TRANS_EXC_CODE
	REENABLE_IRQS
	la	%r8,0x7f
	la	%r8,0x7f
	nr	%r8,%r3
	nr	%r8,%r3
pgm_do_call:
pgm_do_call:
@@ -495,7 +484,6 @@ pgm_do_call:
	la	%r2,SP_PTREGS(%r15)	# address of register-save area
	la	%r2,SP_PTREGS(%r15)	# address of register-save area
	basr	%r14,%r7		# branch to interrupt-handler
	basr	%r14,%r7		# branch to interrupt-handler
pgm_exit:
pgm_exit:
	TRACE_IRQS_CHECK_ON
	b	BASED(sysc_return)
	b	BASED(sysc_return)


#
#
@@ -523,7 +511,6 @@ pgm_per_std:
	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_SYNC_ENTER_TIMER
	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
pgm_no_vtime2:
pgm_no_vtime2:
	TRACE_IRQS_CHECK_OFF
	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
	l	%r1,__TI_task(%r9)
	l	%r1,__TI_task(%r9)
	tm	SP_PSW+1(%r15),0x01	# kernel per event ?
	tm	SP_PSW+1(%r15),0x01	# kernel per event ?
@@ -533,6 +520,8 @@ pgm_no_vtime2:
	mvc	__THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
	mvc	__THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
	oi	__TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
	oi	__TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
	l	%r3,__LC_PGM_ILC	# load program interruption code
	l	%r3,__LC_PGM_ILC	# load program interruption code
	l	%r4,__LC_TRANS_EXC_CODE
	REENABLE_IRQS
	la	%r8,0x7f
	la	%r8,0x7f
	nr	%r8,%r3 		# clear per-event-bit and ilc
	nr	%r8,%r3 		# clear per-event-bit and ilc
	be	BASED(pgm_exit2)	# only per or per+check ?
	be	BASED(pgm_exit2)	# only per or per+check ?
@@ -542,8 +531,6 @@ pgm_no_vtime2:
	la	%r2,SP_PTREGS(%r15)	# address of register-save area
	la	%r2,SP_PTREGS(%r15)	# address of register-save area
	basr	%r14,%r7		# branch to interrupt-handler
	basr	%r14,%r7		# branch to interrupt-handler
pgm_exit2:
pgm_exit2:
	TRACE_IRQS_ON
	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
	b	BASED(sysc_return)
	b	BASED(sysc_return)


#
#
@@ -557,13 +544,11 @@ pgm_svcper:
	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
	lh	%r7,0x8a		# get svc number from lowcore
	lh	%r7,0x8a		# get svc number from lowcore
	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
	TRACE_IRQS_OFF
	l	%r8,__TI_task(%r9)
	l	%r8,__TI_task(%r9)
	mvc	__THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
	mvc	__THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
	mvc	__THREAD_per+__PER_address(4,%r8),__LC_PER_ADDRESS
	mvc	__THREAD_per+__PER_address(4,%r8),__LC_PER_ADDRESS
	mvc	__THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
	mvc	__THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
	oi	__TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
	oi	__TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
	TRACE_IRQS_ON
	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
	lm	%r2,%r6,SP_R2(%r15)	# load svc arguments
	lm	%r2,%r6,SP_R2(%r15)	# load svc arguments
	b	BASED(sysc_do_svc)
	b	BASED(sysc_do_svc)
+1 −1
Original line number Original line Diff line number Diff line
@@ -5,7 +5,7 @@
#include <linux/signal.h>
#include <linux/signal.h>
#include <asm/ptrace.h>
#include <asm/ptrace.h>


typedef void pgm_check_handler_t(struct pt_regs *, long);
typedef void pgm_check_handler_t(struct pt_regs *, long, unsigned long);
extern pgm_check_handler_t *pgm_check_table[128];
extern pgm_check_handler_t *pgm_check_table[128];
pgm_check_handler_t do_protection_exception;
pgm_check_handler_t do_protection_exception;
pgm_check_handler_t do_dat_exception;
pgm_check_handler_t do_dat_exception;
+10 −26
Original line number Original line Diff line number Diff line
@@ -79,25 +79,9 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
	basr	%r2,%r0
	basr	%r2,%r0
	brasl	%r14,trace_hardirqs_off_caller
	brasl	%r14,trace_hardirqs_off_caller
	.endm
	.endm

	.macro TRACE_IRQS_CHECK_ON
	tm	SP_PSW(%r15),0x03	# irqs enabled?
	jz	0f
	TRACE_IRQS_ON
0:
	.endm

	.macro TRACE_IRQS_CHECK_OFF
	tm	SP_PSW(%r15),0x03	# irqs enabled?
	jz	0f
	TRACE_IRQS_OFF
0:
	.endm
#else
#else
#define TRACE_IRQS_ON
#define TRACE_IRQS_ON
#define TRACE_IRQS_OFF
#define TRACE_IRQS_OFF
#define TRACE_IRQS_CHECK_ON
#define TRACE_IRQS_CHECK_OFF
#endif
#endif


#ifdef CONFIG_LOCKDEP
#ifdef CONFIG_LOCKDEP
@@ -207,6 +191,12 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
0:
0:
	.endm
	.endm


	.macro REENABLE_IRQS
	mvc	__SF_EMPTY(1,%r15),SP_PSW(%r15)
	ni	__SF_EMPTY(%r15),0xbf
	ssm	__SF_EMPTY(%r15)
	.endm

/*
/*
 * Scheduler resume function, called by switch_to
 * Scheduler resume function, called by switch_to
 *  gpr2 = (task_struct *) prev
 *  gpr2 = (task_struct *) prev
@@ -443,14 +433,12 @@ kernel_execve:
	br	%r14
	br	%r14
	# execve succeeded.
	# execve succeeded.
0:	stnsm	__SF_EMPTY(%r15),0xfc	# disable interrupts
0:	stnsm	__SF_EMPTY(%r15),0xfc	# disable interrupts
#	TRACE_IRQS_OFF
	lg	%r15,__LC_KERNEL_STACK	# load ksp
	lg	%r15,__LC_KERNEL_STACK	# load ksp
	aghi	%r15,-SP_SIZE		# make room for registers & psw
	aghi	%r15,-SP_SIZE		# make room for registers & psw
	lg	%r13,__LC_SVC_NEW_PSW+8
	lg	%r13,__LC_SVC_NEW_PSW+8
	mvc	SP_PTREGS(__PT_SIZE,%r15),0(%r12)	# copy pt_regs
	mvc	SP_PTREGS(__PT_SIZE,%r15),0(%r12)	# copy pt_regs
	lg	%r12,__LC_THREAD_INFO
	lg	%r12,__LC_THREAD_INFO
	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
#	TRACE_IRQS_ON
	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
	brasl	%r14,execve_tail
	brasl	%r14,execve_tail
	j	sysc_return
	j	sysc_return
@@ -490,19 +478,18 @@ pgm_check_handler:
	LAST_BREAK
	LAST_BREAK
pgm_no_vtime:
pgm_no_vtime:
	HANDLE_SIE_INTERCEPT
	HANDLE_SIE_INTERCEPT
	TRACE_IRQS_CHECK_OFF
	stg	%r11,SP_ARGS(%r15)
	stg	%r11,SP_ARGS(%r15)
	lgf	%r3,__LC_PGM_ILC	# load program interruption code
	lgf	%r3,__LC_PGM_ILC	# load program interruption code
	lg	%r4,__LC_TRANS_EXC_CODE
	REENABLE_IRQS
	lghi	%r8,0x7f
	lghi	%r8,0x7f
	ngr	%r8,%r3
	ngr	%r8,%r3
pgm_do_call:
	sll	%r8,3
	sll	%r8,3
	larl	%r1,pgm_check_table
	larl	%r1,pgm_check_table
	lg	%r1,0(%r8,%r1)		# load address of handler routine
	lg	%r1,0(%r8,%r1)		# load address of handler routine
	la	%r2,SP_PTREGS(%r15)	# address of register-save area
	la	%r2,SP_PTREGS(%r15)	# address of register-save area
	basr	%r14,%r1		# branch to interrupt-handler
	basr	%r14,%r1		# branch to interrupt-handler
pgm_exit:
pgm_exit:
	TRACE_IRQS_CHECK_ON
	j	sysc_return
	j	sysc_return


#
#
@@ -533,7 +520,6 @@ pgm_per_std:
	LAST_BREAK
	LAST_BREAK
pgm_no_vtime2:
pgm_no_vtime2:
	HANDLE_SIE_INTERCEPT
	HANDLE_SIE_INTERCEPT
	TRACE_IRQS_CHECK_OFF
	lg	%r1,__TI_task(%r12)
	lg	%r1,__TI_task(%r12)
	tm	SP_PSW+1(%r15),0x01	# kernel per event ?
	tm	SP_PSW+1(%r15),0x01	# kernel per event ?
	jz	kernel_per
	jz	kernel_per
@@ -542,6 +528,8 @@ pgm_no_vtime2:
	mvc	__THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
	mvc	__THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
	oi	__TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
	oi	__TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
	lgf	%r3,__LC_PGM_ILC	# load program interruption code
	lgf	%r3,__LC_PGM_ILC	# load program interruption code
	lg	%r4,__LC_TRANS_EXC_CODE
	REENABLE_IRQS
	lghi	%r8,0x7f
	lghi	%r8,0x7f
	ngr	%r8,%r3			# clear per-event-bit and ilc
	ngr	%r8,%r3			# clear per-event-bit and ilc
	je	pgm_exit2
	je	pgm_exit2
@@ -551,8 +539,6 @@ pgm_no_vtime2:
	la	%r2,SP_PTREGS(%r15)	# address of register-save area
	la	%r2,SP_PTREGS(%r15)	# address of register-save area
	basr	%r14,%r1		# branch to interrupt-handler
	basr	%r14,%r1		# branch to interrupt-handler
pgm_exit2:
pgm_exit2:
	TRACE_IRQS_ON
	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
	j	sysc_return
	j	sysc_return


#
#
@@ -568,13 +554,11 @@ pgm_svcper:
	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_SYNC_ENTER_TIMER
	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
	LAST_BREAK
	LAST_BREAK
	TRACE_IRQS_OFF
	lg	%r8,__TI_task(%r12)
	lg	%r8,__TI_task(%r12)
	mvc	__THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
	mvc	__THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
	mvc	__THREAD_per+__PER_address(8,%r8),__LC_PER_ADDRESS
	mvc	__THREAD_per+__PER_address(8,%r8),__LC_PER_ADDRESS
	mvc	__THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
	mvc	__THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
	oi	__TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
	oi	__TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
	TRACE_IRQS_ON
	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
	lmg	%r2,%r6,SP_R2(%r15)	# load svc arguments
	lmg	%r2,%r6,SP_R2(%r15)	# load svc arguments
	j	sysc_do_svc
	j	sysc_do_svc
+74 −98
Original line number Original line Diff line number Diff line
@@ -329,27 +329,19 @@ int is_valid_bugaddr(unsigned long addr)
	return 1;
	return 1;
}
}


static void __kprobes inline do_trap(long interruption_code, int signr,
static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str,
					char *str, struct pt_regs *regs,
				     struct pt_regs *regs, siginfo_t *info)
					siginfo_t *info)
{
{
	/*
	if (notify_die(DIE_TRAP, str, regs, pgm_int_code,
	 * We got all needed information from the lowcore and can
		       pgm_int_code, signr) == NOTIFY_STOP)
	 * now safely switch on interrupts.
	 */
        if (regs->psw.mask & PSW_MASK_PSTATE)
		local_irq_enable();

	if (notify_die(DIE_TRAP, str, regs, interruption_code,
				interruption_code, signr) == NOTIFY_STOP)
		return;
		return;


        if (regs->psw.mask & PSW_MASK_PSTATE) {
        if (regs->psw.mask & PSW_MASK_PSTATE) {
                struct task_struct *tsk = current;
                struct task_struct *tsk = current;


                tsk->thread.trap_no = interruption_code & 0xffff;
		tsk->thread.trap_no = pgm_int_code & 0xffff;
		force_sig_info(signr, info, tsk);
		force_sig_info(signr, info, tsk);
		report_user_fault(regs, interruption_code, signr);
		report_user_fault(regs, pgm_int_code, signr);
        } else {
        } else {
                const struct exception_table_entry *fixup;
                const struct exception_table_entry *fixup;
                fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
                fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
@@ -361,14 +353,16 @@ static void __kprobes inline do_trap(long interruption_code, int signr,
			btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);
			btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);
			if (btt == BUG_TRAP_TYPE_WARN)
			if (btt == BUG_TRAP_TYPE_WARN)
				return;
				return;
			die(str, regs, interruption_code);
			die(str, regs, pgm_int_code);
		}
		}
        }
        }
}
}


static inline void __user *get_check_address(struct pt_regs *regs)
static inline void __user *get_psw_address(struct pt_regs *regs,
					   long pgm_int_code)
{
{
	return (void __user *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
	return (void __user *)
		((regs->psw.addr - (pgm_int_code >> 16)) & PSW_ADDR_INSN);
}
}


void __kprobes do_single_step(struct pt_regs *regs)
void __kprobes do_single_step(struct pt_regs *regs)
@@ -381,57 +375,57 @@ void __kprobes do_single_step(struct pt_regs *regs)
		force_sig(SIGTRAP, current);
		force_sig(SIGTRAP, current);
}
}


static void default_trap_handler(struct pt_regs * regs, long interruption_code)
static void default_trap_handler(struct pt_regs *regs, long pgm_int_code,
				 unsigned long trans_exc_code)
{
{
        if (regs->psw.mask & PSW_MASK_PSTATE) {
        if (regs->psw.mask & PSW_MASK_PSTATE) {
		local_irq_enable();
		report_user_fault(regs, pgm_int_code, SIGSEGV);
		report_user_fault(regs, interruption_code, SIGSEGV);
		do_exit(SIGSEGV);
		do_exit(SIGSEGV);
	} else
	} else
		die("Unknown program exception", regs, interruption_code);
		die("Unknown program exception", regs, pgm_int_code);
}
}


#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
#define DO_ERROR_INFO(name, signr, sicode, str) \
static void name(struct pt_regs * regs, long interruption_code) \
static void name(struct pt_regs *regs, long pgm_int_code, \
		 unsigned long trans_exc_code) \
{ \
{ \
        siginfo_t info; \
        siginfo_t info; \
        info.si_signo = signr; \
        info.si_signo = signr; \
        info.si_errno = 0; \
        info.si_errno = 0; \
        info.si_code = sicode; \
        info.si_code = sicode; \
	info.si_addr = siaddr; \
	info.si_addr = get_psw_address(regs, pgm_int_code); \
        do_trap(interruption_code, signr, str, regs, &info); \
	do_trap(pgm_int_code, signr, str, regs, &info);	    \
}
}


DO_ERROR_INFO(SIGILL, "addressing exception", addressing_exception,
DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
	      ILL_ILLADR, get_check_address(regs))
	      "addressing exception")
DO_ERROR_INFO(SIGILL,  "execute exception", execute_exception,
DO_ERROR_INFO(execute_exception, SIGILL, ILL_ILLOPN,
	      ILL_ILLOPN, get_check_address(regs))
	      "execute exception")
DO_ERROR_INFO(SIGFPE,  "fixpoint divide exception", divide_exception,
DO_ERROR_INFO(divide_exception, SIGFPE, FPE_INTDIV,
	      FPE_INTDIV, get_check_address(regs))
	      "fixpoint divide exception")
DO_ERROR_INFO(SIGFPE,  "fixpoint overflow exception", overflow_exception,
DO_ERROR_INFO(overflow_exception, SIGFPE, FPE_INTOVF,
	      FPE_INTOVF, get_check_address(regs))
	      "fixpoint overflow exception")
DO_ERROR_INFO(SIGFPE,  "HFP overflow exception", hfp_overflow_exception,
DO_ERROR_INFO(hfp_overflow_exception, SIGFPE, FPE_FLTOVF,
	      FPE_FLTOVF, get_check_address(regs))
	      "HFP overflow exception")
DO_ERROR_INFO(SIGFPE,  "HFP underflow exception", hfp_underflow_exception,
DO_ERROR_INFO(hfp_underflow_exception, SIGFPE, FPE_FLTUND,
	      FPE_FLTUND, get_check_address(regs))
	      "HFP underflow exception")
DO_ERROR_INFO(SIGFPE,  "HFP significance exception", hfp_significance_exception,
DO_ERROR_INFO(hfp_significance_exception, SIGFPE, FPE_FLTRES,
	      FPE_FLTRES, get_check_address(regs))
	      "HFP significance exception")
DO_ERROR_INFO(SIGFPE,  "HFP divide exception", hfp_divide_exception,
DO_ERROR_INFO(hfp_divide_exception, SIGFPE, FPE_FLTDIV,
	      FPE_FLTDIV, get_check_address(regs))
	      "HFP divide exception")
DO_ERROR_INFO(SIGFPE,  "HFP square root exception", hfp_sqrt_exception,
DO_ERROR_INFO(hfp_sqrt_exception, SIGFPE, FPE_FLTINV,
	      FPE_FLTINV, get_check_address(regs))
	      "HFP square root exception")
DO_ERROR_INFO(SIGILL,  "operand exception", operand_exception,
DO_ERROR_INFO(operand_exception, SIGILL, ILL_ILLOPN,
	      ILL_ILLOPN, get_check_address(regs))
	      "operand exception")
DO_ERROR_INFO(SIGILL,  "privileged operation", privileged_op,
DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC,
	      ILL_PRVOPC, get_check_address(regs))
	      "privileged operation")
DO_ERROR_INFO(SIGILL,  "special operation exception", special_op_exception,
DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
	      ILL_ILLOPN, get_check_address(regs))
	      "special operation exception")
DO_ERROR_INFO(SIGILL,  "translation exception", translation_exception,
DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN,
	      ILL_ILLOPN, get_check_address(regs))
	      "translation exception")


static inline void
static inline void do_fp_trap(struct pt_regs *regs, void __user *location,
do_fp_trap(struct pt_regs *regs, void __user *location,
			      int fpc, long pgm_int_code)
           int fpc, long interruption_code)
{
{
	siginfo_t si;
	siginfo_t si;


@@ -454,25 +448,19 @@ do_fp_trap(struct pt_regs *regs, void __user *location,
			si.si_code = FPE_FLTRES;
			si.si_code = FPE_FLTRES;
	}
	}
	current->thread.ieee_instruction_pointer = (addr_t) location;
	current->thread.ieee_instruction_pointer = (addr_t) location;
	do_trap(interruption_code, SIGFPE,
	do_trap(pgm_int_code, SIGFPE,
		"floating point exception", regs, &si);
		"floating point exception", regs, &si);
}
}


static void illegal_op(struct pt_regs * regs, long interruption_code)
static void illegal_op(struct pt_regs *regs, long pgm_int_code,
		       unsigned long trans_exc_code)
{
{
	siginfo_t info;
	siginfo_t info;
        __u8 opcode[6];
        __u8 opcode[6];
	__u16 __user *location;
	__u16 __user *location;
	int signal = 0;
	int signal = 0;


	location = get_check_address(regs);
	location = get_psw_address(regs, pgm_int_code);

	/*
	 * We got all needed information from the lowcore and can
	 * now safely switch on interrupts.
	 */
	if (regs->psw.mask & PSW_MASK_PSTATE)
		local_irq_enable();


	if (regs->psw.mask & PSW_MASK_PSTATE) {
	if (regs->psw.mask & PSW_MASK_PSTATE) {
		if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
		if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
@@ -512,7 +500,7 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
		 * If we get an illegal op in kernel mode, send it through the
		 * If we get an illegal op in kernel mode, send it through the
		 * kprobes notifier. If kprobes doesn't pick it up, SIGILL
		 * kprobes notifier. If kprobes doesn't pick it up, SIGILL
		 */
		 */
		if (notify_die(DIE_BPT, "bpt", regs, interruption_code,
		if (notify_die(DIE_BPT, "bpt", regs, pgm_int_code,
			       3, SIGTRAP) != NOTIFY_STOP)
			       3, SIGTRAP) != NOTIFY_STOP)
			signal = SIGILL;
			signal = SIGILL;
	}
	}
@@ -520,13 +508,13 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
#ifdef CONFIG_MATHEMU
#ifdef CONFIG_MATHEMU
        if (signal == SIGFPE)
        if (signal == SIGFPE)
		do_fp_trap(regs, location,
		do_fp_trap(regs, location,
                           current->thread.fp_regs.fpc, interruption_code);
			   current->thread.fp_regs.fpc, pgm_int_code);
        else if (signal == SIGSEGV) {
        else if (signal == SIGSEGV) {
		info.si_signo = signal;
		info.si_signo = signal;
		info.si_errno = 0;
		info.si_errno = 0;
		info.si_code = SEGV_MAPERR;
		info.si_code = SEGV_MAPERR;
		info.si_addr = (void __user *) location;
		info.si_addr = (void __user *) location;
		do_trap(interruption_code, signal,
		do_trap(pgm_int_code, signal,
			"user address fault", regs, &info);
			"user address fault", regs, &info);
	} else
	} else
#endif
#endif
@@ -535,28 +523,22 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
		info.si_errno = 0;
		info.si_errno = 0;
		info.si_code = ILL_ILLOPC;
		info.si_code = ILL_ILLOPC;
		info.si_addr = (void __user *) location;
		info.si_addr = (void __user *) location;
		do_trap(interruption_code, signal,
		do_trap(pgm_int_code, signal,
			"illegal operation", regs, &info);
			"illegal operation", regs, &info);
	}
	}
}
}




#ifdef CONFIG_MATHEMU
#ifdef CONFIG_MATHEMU
asmlinkage void 
asmlinkage void specification_exception(struct pt_regs *regs,
specification_exception(struct pt_regs * regs, long interruption_code)
					long pgm_int_code,
					unsigned long trans_exc_code)
{
{
        __u8 opcode[6];
        __u8 opcode[6];
	__u16 __user *location = NULL;
	__u16 __user *location = NULL;
	int signal = 0;
	int signal = 0;


	location = (__u16 __user *) get_check_address(regs);
	location = (__u16 __user *) get_psw_address(regs, pgm_int_code);

	/*
	 * We got all needed information from the lowcore and can
	 * now safely switch on interrupts.
	 */
        if (regs->psw.mask & PSW_MASK_PSTATE)
		local_irq_enable();


        if (regs->psw.mask & PSW_MASK_PSTATE) {
        if (regs->psw.mask & PSW_MASK_PSTATE) {
		get_user(*((__u16 *) opcode), location);
		get_user(*((__u16 *) opcode), location);
@@ -592,35 +574,29 @@ specification_exception(struct pt_regs * regs, long interruption_code)


        if (signal == SIGFPE)
        if (signal == SIGFPE)
		do_fp_trap(regs, location,
		do_fp_trap(regs, location,
                           current->thread.fp_regs.fpc, interruption_code);
			   current->thread.fp_regs.fpc, pgm_int_code);
        else if (signal) {
        else if (signal) {
		siginfo_t info;
		siginfo_t info;
		info.si_signo = signal;
		info.si_signo = signal;
		info.si_errno = 0;
		info.si_errno = 0;
		info.si_code = ILL_ILLOPN;
		info.si_code = ILL_ILLOPN;
		info.si_addr = location;
		info.si_addr = location;
		do_trap(interruption_code, signal, 
		do_trap(pgm_int_code, signal,
			"specification exception", regs, &info);
			"specification exception", regs, &info);
	}
	}
}
}
#else
#else
DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
	      ILL_ILLOPN, get_check_address(regs));
	      "specification exception");
#endif
#endif


static void data_exception(struct pt_regs * regs, long interruption_code)
static void data_exception(struct pt_regs *regs, long pgm_int_code,
			   unsigned long trans_exc_code)
{
{
	__u16 __user *location;
	__u16 __user *location;
	int signal = 0;
	int signal = 0;


	location = get_check_address(regs);
	location = get_psw_address(regs, pgm_int_code);

	/*
	 * We got all needed information from the lowcore and can
	 * now safely switch on interrupts.
	 */
	if (regs->psw.mask & PSW_MASK_PSTATE)
		local_irq_enable();


	if (MACHINE_HAS_IEEE)
	if (MACHINE_HAS_IEEE)
		asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
		asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
@@ -686,19 +662,19 @@ static void data_exception(struct pt_regs * regs, long interruption_code)
		signal = SIGILL;
		signal = SIGILL;
        if (signal == SIGFPE)
        if (signal == SIGFPE)
		do_fp_trap(regs, location,
		do_fp_trap(regs, location,
                           current->thread.fp_regs.fpc, interruption_code);
			   current->thread.fp_regs.fpc, pgm_int_code);
        else if (signal) {
        else if (signal) {
		siginfo_t info;
		siginfo_t info;
		info.si_signo = signal;
		info.si_signo = signal;
		info.si_errno = 0;
		info.si_errno = 0;
		info.si_code = ILL_ILLOPN;
		info.si_code = ILL_ILLOPN;
		info.si_addr = location;
		info.si_addr = location;
		do_trap(interruption_code, signal, 
		do_trap(pgm_int_code, signal, "data exception", regs, &info);
			"data exception", regs, &info);
	}
	}
}
}


static void space_switch_exception(struct pt_regs * regs, long int_code)
static void space_switch_exception(struct pt_regs *regs, long pgm_int_code,
				   unsigned long trans_exc_code)
{
{
        siginfo_t info;
        siginfo_t info;


@@ -709,8 +685,8 @@ static void space_switch_exception(struct pt_regs * regs, long int_code)
        info.si_signo = SIGILL;
        info.si_signo = SIGILL;
        info.si_errno = 0;
        info.si_errno = 0;
        info.si_code = ILL_PRVOPC;
        info.si_code = ILL_PRVOPC;
        info.si_addr = get_check_address(regs);
	info.si_addr = get_psw_address(regs, pgm_int_code);
        do_trap(int_code, SIGILL, "space switch event", regs, &info);
	do_trap(pgm_int_code, SIGILL, "space switch event", regs, &info);
}
}


asmlinkage void kernel_stack_overflow(struct pt_regs * regs)
asmlinkage void kernel_stack_overflow(struct pt_regs * regs)
Loading