[S390] cleanup trap handling
Move the program interruption code and the translation exception identifier to the pt_regs structure as 'int_code' and 'int_parm_long' and make the first level interrupt handler in entry[64].S store the two values. That makes it possible to drop 'prot_addr' and 'trap_no' from the thread_struct and to reduce the number of arguments to a lot of functions. Finally un-inline do_trap. Overall this saves 5812 bytes in the .text section of the 64 bit kernel. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
		
					parent
					
						
							
								679e2ea733
							
						
					
				
			
			
				commit
				
					
						aa33c8cbba
					
				
			
		
					 12 changed files with 158 additions and 210 deletions
				
			
		| 
						 | 
					@ -22,6 +22,6 @@ enum die_val {
 | 
				
			||||||
	DIE_NMI_IPI,
 | 
						DIE_NMI_IPI,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void die(const char *, struct pt_regs *, long);
 | 
					extern void die(struct pt_regs *, const char *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -80,8 +80,6 @@ struct thread_struct {
 | 
				
			||||||
	unsigned int  acrs[NUM_ACRS];
 | 
						unsigned int  acrs[NUM_ACRS];
 | 
				
			||||||
        unsigned long ksp;              /* kernel stack pointer             */
 | 
					        unsigned long ksp;              /* kernel stack pointer             */
 | 
				
			||||||
	mm_segment_t mm_segment;
 | 
						mm_segment_t mm_segment;
 | 
				
			||||||
        unsigned long prot_addr;        /* address of protection-excep.     */
 | 
					 | 
				
			||||||
        unsigned int trap_no;
 | 
					 | 
				
			||||||
	unsigned long gmap_addr;	/* address of last gmap fault. */
 | 
						unsigned long gmap_addr;	/* address of last gmap fault. */
 | 
				
			||||||
	struct per_regs per_user;	/* User specified PER registers */
 | 
						struct per_regs per_user;	/* User specified PER registers */
 | 
				
			||||||
	struct per_event per_event;	/* Cause of the last PER trap */
 | 
						struct per_event per_event;	/* Cause of the last PER trap */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -324,7 +324,8 @@ struct pt_regs
 | 
				
			||||||
	psw_t psw;
 | 
						psw_t psw;
 | 
				
			||||||
	unsigned long gprs[NUM_GPRS];
 | 
						unsigned long gprs[NUM_GPRS];
 | 
				
			||||||
	unsigned long orig_gpr2;
 | 
						unsigned long orig_gpr2;
 | 
				
			||||||
	unsigned int svc_code;
 | 
						unsigned int int_code;
 | 
				
			||||||
 | 
						unsigned long int_parm_long;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,7 @@ static inline long syscall_get_nr(struct task_struct *task,
 | 
				
			||||||
				  struct pt_regs *regs)
 | 
									  struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return test_tsk_thread_flag(task, TIF_SYSCALL) ?
 | 
						return test_tsk_thread_flag(task, TIF_SYSCALL) ?
 | 
				
			||||||
		(regs->svc_code & 0xffff) : -1;
 | 
							(regs->int_code & 0xffff) : -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void syscall_rollback(struct task_struct *task,
 | 
					static inline void syscall_rollback(struct task_struct *task,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,7 +45,8 @@ int main(void)
 | 
				
			||||||
	DEFINE(__PT_PSW, offsetof(struct pt_regs, psw));
 | 
						DEFINE(__PT_PSW, offsetof(struct pt_regs, psw));
 | 
				
			||||||
	DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs));
 | 
						DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs));
 | 
				
			||||||
	DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2));
 | 
						DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2));
 | 
				
			||||||
	DEFINE(__PT_SVC_CODE, offsetof(struct pt_regs, svc_code));
 | 
						DEFINE(__PT_INT_CODE, offsetof(struct pt_regs, int_code));
 | 
				
			||||||
 | 
						DEFINE(__PT_INT_PARM_LONG, offsetof(struct pt_regs, int_parm_long));
 | 
				
			||||||
	DEFINE(__PT_SIZE, sizeof(struct pt_regs));
 | 
						DEFINE(__PT_SIZE, sizeof(struct pt_regs));
 | 
				
			||||||
	BLANK();
 | 
						BLANK();
 | 
				
			||||||
	DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain));
 | 
						DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -501,8 +501,12 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* We forgot to include these in the sigcontext.
 | 
						/* We forgot to include these in the sigcontext.
 | 
				
			||||||
	   To avoid breaking binary compatibility, they are passed as args. */
 | 
						   To avoid breaking binary compatibility, they are passed as args. */
 | 
				
			||||||
	regs->gprs[4] = current->thread.trap_no;
 | 
						if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
 | 
				
			||||||
	regs->gprs[5] = current->thread.prot_addr;
 | 
						    sig == SIGTRAP || sig == SIGFPE) {
 | 
				
			||||||
 | 
							/* set extra registers only for synchronous signals */
 | 
				
			||||||
 | 
							regs->gprs[4] = regs->int_code & 127;
 | 
				
			||||||
 | 
							regs->gprs[5] = regs->int_parm_long;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Place signal number on stack to allow backtrace from handler.  */
 | 
						/* Place signal number on stack to allow backtrace from handler.  */
 | 
				
			||||||
	if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo))
 | 
						if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -184,16 +184,16 @@ sysc_vtime:
 | 
				
			||||||
	stm	%r0,%r7,__PT_R0(%r11)
 | 
						stm	%r0,%r7,__PT_R0(%r11)
 | 
				
			||||||
	mvc	__PT_R8(32,%r11),__LC_SAVE_AREA_SYNC
 | 
						mvc	__PT_R8(32,%r11),__LC_SAVE_AREA_SYNC
 | 
				
			||||||
	mvc	__PT_PSW(8,%r11),__LC_SVC_OLD_PSW
 | 
						mvc	__PT_PSW(8,%r11),__LC_SVC_OLD_PSW
 | 
				
			||||||
	mvc	__PT_SVC_CODE(4,%r11),__LC_SVC_ILC
 | 
						mvc	__PT_INT_CODE(4,%r11),__LC_SVC_ILC
 | 
				
			||||||
sysc_do_svc:
 | 
					sysc_do_svc:
 | 
				
			||||||
	oi	__TI_flags+3(%r12),_TIF_SYSCALL
 | 
						oi	__TI_flags+3(%r12),_TIF_SYSCALL
 | 
				
			||||||
	lh	%r8,__PT_SVC_CODE+2(%r11)
 | 
						lh	%r8,__PT_INT_CODE+2(%r11)
 | 
				
			||||||
	sla	%r8,2				# shift and test for svc0
 | 
						sla	%r8,2				# shift and test for svc0
 | 
				
			||||||
	jnz	sysc_nr_ok
 | 
						jnz	sysc_nr_ok
 | 
				
			||||||
	# svc 0: system call number in %r1
 | 
						# svc 0: system call number in %r1
 | 
				
			||||||
	cl	%r1,BASED(.Lnr_syscalls)
 | 
						cl	%r1,BASED(.Lnr_syscalls)
 | 
				
			||||||
	jnl	sysc_nr_ok
 | 
						jnl	sysc_nr_ok
 | 
				
			||||||
	sth	%r1,__PT_SVC_CODE+2(%r11)
 | 
						sth	%r1,__PT_INT_CODE+2(%r11)
 | 
				
			||||||
	lr	%r8,%r1
 | 
						lr	%r8,%r1
 | 
				
			||||||
	sla	%r8,2
 | 
						sla	%r8,2
 | 
				
			||||||
sysc_nr_ok:
 | 
					sysc_nr_ok:
 | 
				
			||||||
| 
						 | 
					@ -266,9 +266,9 @@ sysc_sigpending:
 | 
				
			||||||
	jno	sysc_return
 | 
						jno	sysc_return
 | 
				
			||||||
	lm	%r2,%r7,__PT_R2(%r11)	# load svc arguments
 | 
						lm	%r2,%r7,__PT_R2(%r11)	# load svc arguments
 | 
				
			||||||
	xr	%r8,%r8			# svc 0 returns -ENOSYS
 | 
						xr	%r8,%r8			# svc 0 returns -ENOSYS
 | 
				
			||||||
	clc	__PT_SVC_CODE+2(2,%r11),BASED(.Lnr_syscalls+2)
 | 
						clc	__PT_INT_CODE+2(2,%r11),BASED(.Lnr_syscalls+2)
 | 
				
			||||||
	jnl	sysc_nr_ok		# invalid svc number -> do svc 0
 | 
						jnl	sysc_nr_ok		# invalid svc number -> do svc 0
 | 
				
			||||||
	lh	%r8,__PT_SVC_CODE+2(%r11)	# load new svc number
 | 
						lh	%r8,__PT_INT_CODE+2(%r11)	# load new svc number
 | 
				
			||||||
	sla	%r8,2
 | 
						sla	%r8,2
 | 
				
			||||||
	j	sysc_nr_ok		# restart svc
 | 
						j	sysc_nr_ok		# restart svc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -300,7 +300,7 @@ sysc_tracesys:
 | 
				
			||||||
	lr	%r2,%r11		# pass pointer to pt_regs
 | 
						lr	%r2,%r11		# pass pointer to pt_regs
 | 
				
			||||||
	la	%r3,0
 | 
						la	%r3,0
 | 
				
			||||||
	xr	%r0,%r0
 | 
						xr	%r0,%r0
 | 
				
			||||||
	icm	%r0,3,__PT_SVC_CODE+2(%r11)
 | 
						icm	%r0,3,__PT_INT_CODE+2(%r11)
 | 
				
			||||||
	st	%r0,__PT_R2(%r11)
 | 
						st	%r0,__PT_R2(%r11)
 | 
				
			||||||
	basr	%r14,%r1		# call do_syscall_trace_enter
 | 
						basr	%r14,%r1		# call do_syscall_trace_enter
 | 
				
			||||||
	cl	%r2,BASED(.Lnr_syscalls)
 | 
						cl	%r2,BASED(.Lnr_syscalls)
 | 
				
			||||||
| 
						 | 
					@ -396,6 +396,8 @@ ENTRY(pgm_check_handler)
 | 
				
			||||||
	stm	%r0,%r7,__PT_R0(%r11)
 | 
						stm	%r0,%r7,__PT_R0(%r11)
 | 
				
			||||||
	mvc	__PT_R8(32,%r11),__LC_SAVE_AREA_SYNC
 | 
						mvc	__PT_R8(32,%r11),__LC_SAVE_AREA_SYNC
 | 
				
			||||||
	stm	%r8,%r9,__PT_PSW(%r11)
 | 
						stm	%r8,%r9,__PT_PSW(%r11)
 | 
				
			||||||
 | 
						mvc	__PT_INT_CODE(4,%r11),__LC_PGM_ILC
 | 
				
			||||||
 | 
						mvc	__PT_INT_PARM_LONG(4,%r11),__LC_TRANS_EXC_CODE
 | 
				
			||||||
	tm	__LC_PGM_ILC+3,0x80	# check for per exception
 | 
						tm	__LC_PGM_ILC+3,0x80	# check for per exception
 | 
				
			||||||
	jz	0f
 | 
						jz	0f
 | 
				
			||||||
	l	%r1,__TI_task(%r12)
 | 
						l	%r1,__TI_task(%r12)
 | 
				
			||||||
| 
						 | 
					@ -405,13 +407,11 @@ ENTRY(pgm_check_handler)
 | 
				
			||||||
	mvc	__THREAD_per_address(4,%r1),__LC_PER_ADDRESS
 | 
						mvc	__THREAD_per_address(4,%r1),__LC_PER_ADDRESS
 | 
				
			||||||
	mvc	__THREAD_per_cause(2,%r1),__LC_PER_CAUSE
 | 
						mvc	__THREAD_per_cause(2,%r1),__LC_PER_CAUSE
 | 
				
			||||||
	mvc	__THREAD_per_paid(1,%r1),__LC_PER_PAID
 | 
						mvc	__THREAD_per_paid(1,%r1),__LC_PER_PAID
 | 
				
			||||||
0:	l	%r3,__LC_PGM_ILC	# load program interruption code
 | 
					0:	REENABLE_IRQS
 | 
				
			||||||
	l	%r4,__LC_TRANS_EXC_CODE
 | 
					 | 
				
			||||||
	REENABLE_IRQS
 | 
					 | 
				
			||||||
	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
 | 
						xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
 | 
				
			||||||
	l	%r1,BASED(.Ljump_table)
 | 
						l	%r1,BASED(.Ljump_table)
 | 
				
			||||||
	la	%r10,0x7f
 | 
						la	%r10,0x7f
 | 
				
			||||||
	nr	%r10,%r3
 | 
						n	%r10,__PT_INT_CODE(%r11)
 | 
				
			||||||
	je	sysc_return
 | 
						je	sysc_return
 | 
				
			||||||
	sll	%r10,2
 | 
						sll	%r10,2
 | 
				
			||||||
	l	%r1,0(%r10,%r1)		# load address of handler routine
 | 
						l	%r1,0(%r10,%r1)		# load address of handler routine
 | 
				
			||||||
| 
						 | 
					@ -858,7 +858,7 @@ cleanup_system_call:
 | 
				
			||||||
	mvc	__PT_R8(32,%r15),__LC_SAVE_AREA_SYNC
 | 
						mvc	__PT_R8(32,%r15),__LC_SAVE_AREA_SYNC
 | 
				
			||||||
	stm	%r0,%r7,__PT_R0(%r15)
 | 
						stm	%r0,%r7,__PT_R0(%r15)
 | 
				
			||||||
	mvc	__PT_PSW(8,%r15),__LC_SVC_OLD_PSW
 | 
						mvc	__PT_PSW(8,%r15),__LC_SVC_OLD_PSW
 | 
				
			||||||
	mvc	__PT_SVC_CODE(4,%r15),__LC_SVC_ILC
 | 
						mvc	__PT_INT_CODE(4,%r15),__LC_SVC_ILC
 | 
				
			||||||
	# setup saved register 15
 | 
						# setup saved register 15
 | 
				
			||||||
	ahi	%r15,-STACK_FRAME_OVERHEAD
 | 
						ahi	%r15,-STACK_FRAME_OVERHEAD
 | 
				
			||||||
	st	%r15,28(%r11)		# r15 stack pointer
 | 
						st	%r15,28(%r11)		# r15 stack pointer
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,15 +6,15 @@
 | 
				
			||||||
#include <asm/ptrace.h>
 | 
					#include <asm/ptrace.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void (*pgm_check_table[128])(struct pt_regs *, long, unsigned long);
 | 
					extern void (*pgm_check_table[128])(struct pt_regs *);
 | 
				
			||||||
extern void *restart_stack;
 | 
					extern void *restart_stack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
asmlinkage long do_syscall_trace_enter(struct pt_regs *regs);
 | 
					asmlinkage long do_syscall_trace_enter(struct pt_regs *regs);
 | 
				
			||||||
asmlinkage void do_syscall_trace_exit(struct pt_regs *regs);
 | 
					asmlinkage void do_syscall_trace_exit(struct pt_regs *regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void do_protection_exception(struct pt_regs *, long, unsigned long);
 | 
					void do_protection_exception(struct pt_regs *regs);
 | 
				
			||||||
void do_dat_exception(struct pt_regs *, long, unsigned long);
 | 
					void do_dat_exception(struct pt_regs *regs);
 | 
				
			||||||
void do_asce_exception(struct pt_regs *, long, unsigned long);
 | 
					void do_asce_exception(struct pt_regs *regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void do_per_trap(struct pt_regs *regs);
 | 
					void do_per_trap(struct pt_regs *regs);
 | 
				
			||||||
void syscall_trace(struct pt_regs *regs, int entryexit);
 | 
					void syscall_trace(struct pt_regs *regs, int entryexit);
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@ void do_extint(struct pt_regs *regs, unsigned int, unsigned int, unsigned long);
 | 
				
			||||||
void do_restart(void);
 | 
					void do_restart(void);
 | 
				
			||||||
int __cpuinit start_secondary(void *cpuvoid);
 | 
					int __cpuinit start_secondary(void *cpuvoid);
 | 
				
			||||||
void __init startup_init(void);
 | 
					void __init startup_init(void);
 | 
				
			||||||
void die(const char * str, struct pt_regs * regs, long err);
 | 
					void die(struct pt_regs *regs, const char *str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void __init time_init(void);
 | 
					void __init time_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,3 @@
 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  arch/s390/kernel/entry64.S
 | 
					 *  arch/s390/kernel/entry64.S
 | 
				
			||||||
 *    S390 low-level entry points.
 | 
					 *    S390 low-level entry points.
 | 
				
			||||||
| 
						 | 
					@ -200,17 +199,17 @@ sysc_vtime:
 | 
				
			||||||
	stmg	%r0,%r7,__PT_R0(%r11)
 | 
						stmg	%r0,%r7,__PT_R0(%r11)
 | 
				
			||||||
	mvc	__PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
 | 
						mvc	__PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
 | 
				
			||||||
	mvc	__PT_PSW(16,%r11),__LC_SVC_OLD_PSW
 | 
						mvc	__PT_PSW(16,%r11),__LC_SVC_OLD_PSW
 | 
				
			||||||
	mvc	__PT_SVC_CODE(4,%r11),__LC_SVC_ILC
 | 
						mvc	__PT_INT_CODE(4,%r11),__LC_SVC_ILC
 | 
				
			||||||
sysc_do_svc:
 | 
					sysc_do_svc:
 | 
				
			||||||
	oi	__TI_flags+7(%r12),_TIF_SYSCALL
 | 
						oi	__TI_flags+7(%r12),_TIF_SYSCALL
 | 
				
			||||||
	llgh	%r8,__PT_SVC_CODE+2(%r11)
 | 
						llgh	%r8,__PT_INT_CODE+2(%r11)
 | 
				
			||||||
	slag	%r8,%r8,2			# shift and test for svc 0
 | 
						slag	%r8,%r8,2			# shift and test for svc 0
 | 
				
			||||||
	jnz	sysc_nr_ok
 | 
						jnz	sysc_nr_ok
 | 
				
			||||||
	# svc 0: system call number in %r1
 | 
						# svc 0: system call number in %r1
 | 
				
			||||||
	llgfr	%r1,%r1				# clear high word in r1
 | 
						llgfr	%r1,%r1				# clear high word in r1
 | 
				
			||||||
	cghi	%r1,NR_syscalls
 | 
						cghi	%r1,NR_syscalls
 | 
				
			||||||
	jnl	sysc_nr_ok
 | 
						jnl	sysc_nr_ok
 | 
				
			||||||
	sth	%r1,__PT_SVC_CODE+2(%r11)
 | 
						sth	%r1,__PT_INT_CODE+2(%r11)
 | 
				
			||||||
	slag	%r8,%r1,2
 | 
						slag	%r8,%r1,2
 | 
				
			||||||
sysc_nr_ok:
 | 
					sysc_nr_ok:
 | 
				
			||||||
	larl	%r10,sys_call_table		# 64 bit system call table
 | 
						larl	%r10,sys_call_table		# 64 bit system call table
 | 
				
			||||||
| 
						 | 
					@ -288,7 +287,7 @@ sysc_sigpending:
 | 
				
			||||||
	jno	sysc_return
 | 
						jno	sysc_return
 | 
				
			||||||
	lmg	%r2,%r7,__PT_R2(%r11)	# load svc arguments
 | 
						lmg	%r2,%r7,__PT_R2(%r11)	# load svc arguments
 | 
				
			||||||
	lghi	%r8,0			# svc 0 returns -ENOSYS
 | 
						lghi	%r8,0			# svc 0 returns -ENOSYS
 | 
				
			||||||
	lh	%r1,__PT_SVC_CODE+2(%r11)	# load new svc number
 | 
						lh	%r1,__PT_INT_CODE+2(%r11)	# load new svc number
 | 
				
			||||||
	cghi	%r1,NR_syscalls
 | 
						cghi	%r1,NR_syscalls
 | 
				
			||||||
	jnl	sysc_nr_ok		# invalid svc number -> do svc 0
 | 
						jnl	sysc_nr_ok		# invalid svc number -> do svc 0
 | 
				
			||||||
	slag	%r8,%r1,2
 | 
						slag	%r8,%r1,2
 | 
				
			||||||
| 
						 | 
					@ -318,7 +317,7 @@ sysc_singlestep:
 | 
				
			||||||
sysc_tracesys:
 | 
					sysc_tracesys:
 | 
				
			||||||
	lgr	%r2,%r11		# pass pointer to pt_regs
 | 
						lgr	%r2,%r11		# pass pointer to pt_regs
 | 
				
			||||||
	la	%r3,0
 | 
						la	%r3,0
 | 
				
			||||||
	llgh	%r0,__PT_SVC_CODE+2(%r11)
 | 
						llgh	%r0,__PT_INT_CODE+2(%r11)
 | 
				
			||||||
	stg	%r0,__PT_R2(%r11)
 | 
						stg	%r0,__PT_R2(%r11)
 | 
				
			||||||
	brasl	%r14,do_syscall_trace_enter
 | 
						brasl	%r14,do_syscall_trace_enter
 | 
				
			||||||
	lghi	%r0,NR_syscalls
 | 
						lghi	%r0,NR_syscalls
 | 
				
			||||||
| 
						 | 
					@ -411,6 +410,8 @@ ENTRY(pgm_check_handler)
 | 
				
			||||||
	stmg	%r0,%r7,__PT_R0(%r11)
 | 
						stmg	%r0,%r7,__PT_R0(%r11)
 | 
				
			||||||
	mvc	__PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
 | 
						mvc	__PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
 | 
				
			||||||
	stmg	%r8,%r9,__PT_PSW(%r11)
 | 
						stmg	%r8,%r9,__PT_PSW(%r11)
 | 
				
			||||||
 | 
						mvc	__PT_INT_CODE(4,%r11),__LC_PGM_ILC
 | 
				
			||||||
 | 
						mvc	__PT_INT_PARM_LONG(8,%r11),__LC_TRANS_EXC_CODE
 | 
				
			||||||
	stg	%r10,__PT_ARGS(%r11)
 | 
						stg	%r10,__PT_ARGS(%r11)
 | 
				
			||||||
	tm	__LC_PGM_ILC+3,0x80	# check for per exception
 | 
						tm	__LC_PGM_ILC+3,0x80	# check for per exception
 | 
				
			||||||
	jz	0f
 | 
						jz	0f
 | 
				
			||||||
| 
						 | 
					@ -421,15 +422,13 @@ ENTRY(pgm_check_handler)
 | 
				
			||||||
	mvc	__THREAD_per_address(8,%r1),__LC_PER_ADDRESS
 | 
						mvc	__THREAD_per_address(8,%r1),__LC_PER_ADDRESS
 | 
				
			||||||
	mvc	__THREAD_per_cause(2,%r1),__LC_PER_CAUSE
 | 
						mvc	__THREAD_per_cause(2,%r1),__LC_PER_CAUSE
 | 
				
			||||||
	mvc	__THREAD_per_paid(1,%r1),__LC_PER_PAID
 | 
						mvc	__THREAD_per_paid(1,%r1),__LC_PER_PAID
 | 
				
			||||||
0:	lgf	%r3,__LC_PGM_ILC	# load program interruption code
 | 
					0:	REENABLE_IRQS
 | 
				
			||||||
	lg	%r4,__LC_TRANS_EXC_CODE
 | 
					 | 
				
			||||||
	REENABLE_IRQS
 | 
					 | 
				
			||||||
	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
 | 
						xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
 | 
				
			||||||
	lghi	%r10,0x7f
 | 
					 | 
				
			||||||
	ngr	%r10,%r3
 | 
					 | 
				
			||||||
	je	sysc_return
 | 
					 | 
				
			||||||
	sll	%r10,3
 | 
					 | 
				
			||||||
	larl	%r1,pgm_check_table
 | 
						larl	%r1,pgm_check_table
 | 
				
			||||||
 | 
						llgh	%r10,__PT_INT_CODE+2(%r11)
 | 
				
			||||||
 | 
						nill	%r10,0x007f
 | 
				
			||||||
 | 
						sll	%r10,3
 | 
				
			||||||
 | 
						je	sysc_return
 | 
				
			||||||
	lg	%r1,0(%r10,%r1)		# load address of handler routine
 | 
						lg	%r1,0(%r10,%r1)		# load address of handler routine
 | 
				
			||||||
	lgr	%r2,%r11		# pass pointer to pt_regs
 | 
						lgr	%r2,%r11		# pass pointer to pt_regs
 | 
				
			||||||
	basr	%r14,%r1		# branch to interrupt-handler
 | 
						basr	%r14,%r1		# branch to interrupt-handler
 | 
				
			||||||
| 
						 | 
					@ -877,7 +876,7 @@ cleanup_system_call:
 | 
				
			||||||
	mvc	__PT_R8(64,%r15),__LC_SAVE_AREA_SYNC
 | 
						mvc	__PT_R8(64,%r15),__LC_SAVE_AREA_SYNC
 | 
				
			||||||
	stmg	%r0,%r7,__PT_R0(%r15)
 | 
						stmg	%r0,%r7,__PT_R0(%r15)
 | 
				
			||||||
	mvc	__PT_PSW(16,%r15),__LC_SVC_OLD_PSW
 | 
						mvc	__PT_PSW(16,%r15),__LC_SVC_OLD_PSW
 | 
				
			||||||
	mvc	__PT_SVC_CODE(4,%r15),__LC_SVC_ILC
 | 
						mvc	__PT_INT_CODE(4,%r15),__LC_SVC_ILC
 | 
				
			||||||
	# setup saved register r15
 | 
						# setup saved register r15
 | 
				
			||||||
	aghi	%r15,-STACK_FRAME_OVERHEAD
 | 
						aghi	%r15,-STACK_FRAME_OVERHEAD
 | 
				
			||||||
	stg	%r15,56(%r11)		# r15 stack pointer
 | 
						stg	%r15,56(%r11)		# r15 stack pointer
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -302,9 +302,13 @@ static int setup_frame(int sig, struct k_sigaction *ka,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* We forgot to include these in the sigcontext.
 | 
						/* We forgot to include these in the sigcontext.
 | 
				
			||||||
	   To avoid breaking binary compatibility, they are passed as args. */
 | 
						   To avoid breaking binary compatibility, they are passed as args. */
 | 
				
			||||||
	regs->gprs[4] = current->thread.trap_no;
 | 
						if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
 | 
				
			||||||
	regs->gprs[5] = current->thread.prot_addr;
 | 
						    sig == SIGTRAP || sig == SIGFPE) {
 | 
				
			||||||
 | 
							/* set extra registers only for synchronous signals */
 | 
				
			||||||
 | 
							regs->gprs[4] = regs->int_code & 127;
 | 
				
			||||||
 | 
							regs->gprs[5] = regs->int_parm_long;
 | 
				
			||||||
		regs->gprs[6] = task_thread_info(current)->last_break;
 | 
							regs->gprs[6] = task_thread_info(current)->last_break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Place signal number on stack to allow backtrace from handler.  */
 | 
						/* Place signal number on stack to allow backtrace from handler.  */
 | 
				
			||||||
	if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
 | 
						if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
 | 
				
			||||||
| 
						 | 
					@ -434,13 +438,13 @@ void do_signal(struct pt_regs *regs)
 | 
				
			||||||
	 * call information.
 | 
						 * call information.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	current_thread_info()->system_call =
 | 
						current_thread_info()->system_call =
 | 
				
			||||||
		test_thread_flag(TIF_SYSCALL) ? regs->svc_code : 0;
 | 
							test_thread_flag(TIF_SYSCALL) ? regs->int_code : 0;
 | 
				
			||||||
	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 | 
						signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (signr > 0) {
 | 
						if (signr > 0) {
 | 
				
			||||||
		/* Whee!  Actually deliver the signal.  */
 | 
							/* Whee!  Actually deliver the signal.  */
 | 
				
			||||||
		if (current_thread_info()->system_call) {
 | 
							if (current_thread_info()->system_call) {
 | 
				
			||||||
			regs->svc_code = current_thread_info()->system_call;
 | 
								regs->int_code = current_thread_info()->system_call;
 | 
				
			||||||
			/* Check for system call restarting. */
 | 
								/* Check for system call restarting. */
 | 
				
			||||||
			switch (regs->gprs[2]) {
 | 
								switch (regs->gprs[2]) {
 | 
				
			||||||
			case -ERESTART_RESTARTBLOCK:
 | 
								case -ERESTART_RESTARTBLOCK:
 | 
				
			||||||
| 
						 | 
					@ -457,7 +461,7 @@ void do_signal(struct pt_regs *regs)
 | 
				
			||||||
				regs->gprs[2] = regs->orig_gpr2;
 | 
									regs->gprs[2] = regs->orig_gpr2;
 | 
				
			||||||
				regs->psw.addr =
 | 
									regs->psw.addr =
 | 
				
			||||||
					__rewind_psw(regs->psw,
 | 
										__rewind_psw(regs->psw,
 | 
				
			||||||
						     regs->svc_code >> 16);
 | 
											     regs->int_code >> 16);
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -488,11 +492,11 @@ void do_signal(struct pt_regs *regs)
 | 
				
			||||||
	/* No handlers present - check for system call restart */
 | 
						/* No handlers present - check for system call restart */
 | 
				
			||||||
	clear_thread_flag(TIF_SYSCALL);
 | 
						clear_thread_flag(TIF_SYSCALL);
 | 
				
			||||||
	if (current_thread_info()->system_call) {
 | 
						if (current_thread_info()->system_call) {
 | 
				
			||||||
		regs->svc_code = current_thread_info()->system_call;
 | 
							regs->int_code = current_thread_info()->system_call;
 | 
				
			||||||
		switch (regs->gprs[2]) {
 | 
							switch (regs->gprs[2]) {
 | 
				
			||||||
		case -ERESTART_RESTARTBLOCK:
 | 
							case -ERESTART_RESTARTBLOCK:
 | 
				
			||||||
			/* Restart with sys_restart_syscall */
 | 
								/* Restart with sys_restart_syscall */
 | 
				
			||||||
			regs->svc_code = __NR_restart_syscall;
 | 
								regs->int_code = __NR_restart_syscall;
 | 
				
			||||||
		/* fallthrough */
 | 
							/* fallthrough */
 | 
				
			||||||
		case -ERESTARTNOHAND:
 | 
							case -ERESTARTNOHAND:
 | 
				
			||||||
		case -ERESTARTSYS:
 | 
							case -ERESTARTSYS:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,7 +43,7 @@
 | 
				
			||||||
#include <asm/debug.h>
 | 
					#include <asm/debug.h>
 | 
				
			||||||
#include "entry.h"
 | 
					#include "entry.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void (*pgm_check_table[128])(struct pt_regs *, long, unsigned long);
 | 
					void (*pgm_check_table[128])(struct pt_regs *regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int show_unhandled_signals;
 | 
					int show_unhandled_signals;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -234,7 +234,7 @@ void show_regs(struct pt_regs *regs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DEFINE_SPINLOCK(die_lock);
 | 
					static DEFINE_SPINLOCK(die_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void die(const char * str, struct pt_regs * regs, long err)
 | 
					void die(struct pt_regs *regs, const char *str)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static int die_counter;
 | 
						static int die_counter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -243,7 +243,7 @@ void die(const char * str, struct pt_regs * regs, long err)
 | 
				
			||||||
	console_verbose();
 | 
						console_verbose();
 | 
				
			||||||
	spin_lock_irq(&die_lock);
 | 
						spin_lock_irq(&die_lock);
 | 
				
			||||||
	bust_spinlocks(1);
 | 
						bust_spinlocks(1);
 | 
				
			||||||
	printk("%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
 | 
						printk("%s: %04x [#%d] ", str, regs->int_code & 0xffff, ++die_counter);
 | 
				
			||||||
#ifdef CONFIG_PREEMPT
 | 
					#ifdef CONFIG_PREEMPT
 | 
				
			||||||
	printk("PREEMPT ");
 | 
						printk("PREEMPT ");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -254,7 +254,7 @@ void die(const char * str, struct pt_regs * regs, long err)
 | 
				
			||||||
	printk("DEBUG_PAGEALLOC");
 | 
						printk("DEBUG_PAGEALLOC");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	printk("\n");
 | 
						printk("\n");
 | 
				
			||||||
	notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
 | 
						notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV);
 | 
				
			||||||
	show_regs(regs);
 | 
						show_regs(regs);
 | 
				
			||||||
	bust_spinlocks(0);
 | 
						bust_spinlocks(0);
 | 
				
			||||||
	add_taint(TAINT_DIE);
 | 
						add_taint(TAINT_DIE);
 | 
				
			||||||
| 
						 | 
					@ -267,8 +267,7 @@ void die(const char * str, struct pt_regs * regs, long err)
 | 
				
			||||||
	do_exit(SIGSEGV);
 | 
						do_exit(SIGSEGV);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void inline report_user_fault(struct pt_regs *regs, long int_code,
 | 
					static inline void report_user_fault(struct pt_regs *regs, int signr)
 | 
				
			||||||
				     int signr)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if ((task_pid_nr(current) > 1) && !show_unhandled_signals)
 | 
						if ((task_pid_nr(current) > 1) && !show_unhandled_signals)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -276,7 +275,7 @@ static void inline report_user_fault(struct pt_regs *regs, long int_code,
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	if (!printk_ratelimit())
 | 
						if (!printk_ratelimit())
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	printk("User process fault: interruption code 0x%lX ", int_code);
 | 
						printk("User process fault: interruption code 0x%X ", regs->int_code);
 | 
				
			||||||
	print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN);
 | 
						print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN);
 | 
				
			||||||
	printk("\n");
 | 
						printk("\n");
 | 
				
			||||||
	show_regs(regs);
 | 
						show_regs(regs);
 | 
				
			||||||
| 
						 | 
					@ -287,19 +286,28 @@ int is_valid_bugaddr(unsigned long addr)
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str,
 | 
					static inline void __user *get_psw_address(struct pt_regs *regs)
 | 
				
			||||||
				     struct pt_regs *regs, siginfo_t *info)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (notify_die(DIE_TRAP, str, regs, pgm_int_code,
 | 
						return (void __user *)
 | 
				
			||||||
		       pgm_int_code, signr) == NOTIFY_STOP)
 | 
							((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void __kprobes do_trap(struct pt_regs *regs,
 | 
				
			||||||
 | 
								      int si_signo, int si_code, char *str)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						siginfo_t info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (notify_die(DIE_TRAP, str, regs, 0,
 | 
				
			||||||
 | 
							       regs->int_code, si_signo) == NOTIFY_STOP)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (regs->psw.mask & PSW_MASK_PSTATE) {
 | 
					        if (regs->psw.mask & PSW_MASK_PSTATE) {
 | 
				
			||||||
                struct task_struct *tsk = current;
 | 
							info.si_signo = si_signo;
 | 
				
			||||||
 | 
							info.si_errno = 0;
 | 
				
			||||||
		tsk->thread.trap_no = pgm_int_code & 0xffff;
 | 
							info.si_code = si_code;
 | 
				
			||||||
		force_sig_info(signr, info, tsk);
 | 
							info.si_addr = get_psw_address(regs);
 | 
				
			||||||
		report_user_fault(regs, pgm_int_code, signr);
 | 
							force_sig_info(si_signo, &info, current);
 | 
				
			||||||
 | 
							report_user_fault(regs, si_signo);
 | 
				
			||||||
        } 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);
 | 
				
			||||||
| 
						 | 
					@ -311,18 +319,11 @@ static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str,
 | 
				
			||||||
			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, pgm_int_code);
 | 
								die(regs, str);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void __user *get_psw_address(struct pt_regs *regs,
 | 
					 | 
				
			||||||
					   long pgm_int_code)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return (void __user *)
 | 
					 | 
				
			||||||
		((regs->psw.addr - (pgm_int_code >> 16)) & PSW_ADDR_INSN);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void __kprobes do_per_trap(struct pt_regs *regs)
 | 
					void __kprobes do_per_trap(struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	siginfo_t info;
 | 
						siginfo_t info;
 | 
				
			||||||
| 
						 | 
					@ -339,26 +340,19 @@ void __kprobes do_per_trap(struct pt_regs *regs)
 | 
				
			||||||
	force_sig_info(SIGTRAP, &info, current);
 | 
						force_sig_info(SIGTRAP, &info, current);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void default_trap_handler(struct pt_regs *regs, long pgm_int_code,
 | 
					static void default_trap_handler(struct pt_regs *regs)
 | 
				
			||||||
				 unsigned long trans_exc_code)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        if (regs->psw.mask & PSW_MASK_PSTATE) {
 | 
					        if (regs->psw.mask & PSW_MASK_PSTATE) {
 | 
				
			||||||
		report_user_fault(regs, pgm_int_code, SIGSEGV);
 | 
							report_user_fault(regs, SIGSEGV);
 | 
				
			||||||
		do_exit(SIGSEGV);
 | 
							do_exit(SIGSEGV);
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		die("Unknown program exception", regs, pgm_int_code);
 | 
							die(regs, "Unknown program exception");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DO_ERROR_INFO(name, signr, sicode, str) \
 | 
					#define DO_ERROR_INFO(name, signr, sicode, str) \
 | 
				
			||||||
static void name(struct pt_regs *regs, long pgm_int_code, \
 | 
					static void name(struct pt_regs *regs) \
 | 
				
			||||||
		 unsigned long trans_exc_code) \
 | 
					 | 
				
			||||||
{ \
 | 
					{ \
 | 
				
			||||||
        siginfo_t info; \
 | 
						do_trap(regs, signr, sicode, str); \
 | 
				
			||||||
        info.si_signo = signr; \
 | 
					 | 
				
			||||||
        info.si_errno = 0; \
 | 
					 | 
				
			||||||
        info.si_code = sicode; \
 | 
					 | 
				
			||||||
	info.si_addr = get_psw_address(regs, pgm_int_code); \
 | 
					 | 
				
			||||||
	do_trap(pgm_int_code, signr, str, regs, &info);	    \
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
 | 
					DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
 | 
				
			||||||
| 
						 | 
					@ -388,42 +382,34 @@ DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
 | 
				
			||||||
DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN,
 | 
					DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN,
 | 
				
			||||||
	      "translation exception")
 | 
						      "translation exception")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void do_fp_trap(struct pt_regs *regs, void __user *location,
 | 
					static inline void do_fp_trap(struct pt_regs *regs, int fpc)
 | 
				
			||||||
			      int fpc, long pgm_int_code)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	siginfo_t si;
 | 
						int si_code = 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	si.si_signo = SIGFPE;
 | 
					 | 
				
			||||||
	si.si_errno = 0;
 | 
					 | 
				
			||||||
	si.si_addr = location;
 | 
					 | 
				
			||||||
	si.si_code = 0;
 | 
					 | 
				
			||||||
	/* FPC[2] is Data Exception Code */
 | 
						/* FPC[2] is Data Exception Code */
 | 
				
			||||||
	if ((fpc & 0x00000300) == 0) {
 | 
						if ((fpc & 0x00000300) == 0) {
 | 
				
			||||||
		/* bits 6 and 7 of DXC are 0 iff IEEE exception */
 | 
							/* bits 6 and 7 of DXC are 0 iff IEEE exception */
 | 
				
			||||||
		if (fpc & 0x8000) /* invalid fp operation */
 | 
							if (fpc & 0x8000) /* invalid fp operation */
 | 
				
			||||||
			si.si_code = FPE_FLTINV;
 | 
								si_code = FPE_FLTINV;
 | 
				
			||||||
		else if (fpc & 0x4000) /* div by 0 */
 | 
							else if (fpc & 0x4000) /* div by 0 */
 | 
				
			||||||
			si.si_code = FPE_FLTDIV;
 | 
								si_code = FPE_FLTDIV;
 | 
				
			||||||
		else if (fpc & 0x2000) /* overflow */
 | 
							else if (fpc & 0x2000) /* overflow */
 | 
				
			||||||
			si.si_code = FPE_FLTOVF;
 | 
								si_code = FPE_FLTOVF;
 | 
				
			||||||
		else if (fpc & 0x1000) /* underflow */
 | 
							else if (fpc & 0x1000) /* underflow */
 | 
				
			||||||
			si.si_code = FPE_FLTUND;
 | 
								si_code = FPE_FLTUND;
 | 
				
			||||||
		else if (fpc & 0x0800) /* inexact */
 | 
							else if (fpc & 0x0800) /* inexact */
 | 
				
			||||||
			si.si_code = FPE_FLTRES;
 | 
								si_code = FPE_FLTRES;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	do_trap(pgm_int_code, SIGFPE,
 | 
						do_trap(regs, SIGFPE, si_code, "floating point exception");
 | 
				
			||||||
		"floating point exception", regs, &si);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_code,
 | 
					static void __kprobes illegal_op(struct pt_regs *regs)
 | 
				
			||||||
				 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_psw_address(regs, pgm_int_code);
 | 
						location = get_psw_address(regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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))
 | 
				
			||||||
| 
						 | 
					@ -467,44 +453,31 @@ static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_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, pgm_int_code,
 | 
							if (notify_die(DIE_BPT, "bpt", regs, 0,
 | 
				
			||||||
			       3, SIGTRAP) != NOTIFY_STOP)
 | 
								       3, SIGTRAP) != NOTIFY_STOP)
 | 
				
			||||||
			signal = SIGILL;
 | 
								signal = SIGILL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_MATHEMU
 | 
					#ifdef CONFIG_MATHEMU
 | 
				
			||||||
        if (signal == SIGFPE)
 | 
					        if (signal == SIGFPE)
 | 
				
			||||||
		do_fp_trap(regs, location,
 | 
							do_fp_trap(regs, current->thread.fp_regs.fpc);
 | 
				
			||||||
			   current->thread.fp_regs.fpc, pgm_int_code);
 | 
						else if (signal == SIGSEGV)
 | 
				
			||||||
        else if (signal == SIGSEGV) {
 | 
							do_trap(regs, signal, SEGV_MAPERR, "user address fault");
 | 
				
			||||||
		info.si_signo = signal;
 | 
						else
 | 
				
			||||||
		info.si_errno = 0;
 | 
					 | 
				
			||||||
		info.si_code = SEGV_MAPERR;
 | 
					 | 
				
			||||||
		info.si_addr = (void __user *) location;
 | 
					 | 
				
			||||||
		do_trap(pgm_int_code, signal,
 | 
					 | 
				
			||||||
			"user address fault", regs, &info);
 | 
					 | 
				
			||||||
	} else
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
        if (signal) {
 | 
						if (signal)
 | 
				
			||||||
		info.si_signo = signal;
 | 
							do_trap(regs, signal, ILL_ILLOPC, "illegal operation");
 | 
				
			||||||
		info.si_errno = 0;
 | 
					 | 
				
			||||||
		info.si_code = ILL_ILLOPC;
 | 
					 | 
				
			||||||
		info.si_addr = (void __user *) location;
 | 
					 | 
				
			||||||
		do_trap(pgm_int_code, signal,
 | 
					 | 
				
			||||||
			"illegal operation", regs, &info);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_MATHEMU
 | 
					#ifdef CONFIG_MATHEMU
 | 
				
			||||||
void specification_exception(struct pt_regs *regs, long pgm_int_code,
 | 
					void specification_exception(struct pt_regs *regs)
 | 
				
			||||||
			     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_psw_address(regs, pgm_int_code);
 | 
						location = (__u16 __user *) get_psw_address(regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (regs->psw.mask & PSW_MASK_PSTATE) {
 | 
					        if (regs->psw.mask & PSW_MASK_PSTATE) {
 | 
				
			||||||
		get_user(*((__u16 *) opcode), location);
 | 
							get_user(*((__u16 *) opcode), location);
 | 
				
			||||||
| 
						 | 
					@ -539,30 +512,21 @@ void specification_exception(struct pt_regs *regs, long pgm_int_code,
 | 
				
			||||||
		signal = SIGILL;
 | 
							signal = SIGILL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (signal == SIGFPE)
 | 
					        if (signal == SIGFPE)
 | 
				
			||||||
		do_fp_trap(regs, location,
 | 
							do_fp_trap(regs, current->thread.fp_regs.fpc);
 | 
				
			||||||
			   current->thread.fp_regs.fpc, pgm_int_code);
 | 
						else if (signal)
 | 
				
			||||||
        else if (signal) {
 | 
							do_trap(regs, signal, ILL_ILLOPN, "specification exception");
 | 
				
			||||||
		siginfo_t info;
 | 
					 | 
				
			||||||
		info.si_signo = signal;
 | 
					 | 
				
			||||||
		info.si_errno = 0;
 | 
					 | 
				
			||||||
		info.si_code = ILL_ILLOPN;
 | 
					 | 
				
			||||||
		info.si_addr = location;
 | 
					 | 
				
			||||||
		do_trap(pgm_int_code, signal,
 | 
					 | 
				
			||||||
			"specification exception", regs, &info);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
 | 
					DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
 | 
				
			||||||
	      "specification exception");
 | 
						      "specification exception");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void data_exception(struct pt_regs *regs, long pgm_int_code,
 | 
					static void data_exception(struct pt_regs *regs)
 | 
				
			||||||
			   unsigned long trans_exc_code)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	__u16 __user *location;
 | 
						__u16 __user *location;
 | 
				
			||||||
	int signal = 0;
 | 
						int signal = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	location = get_psw_address(regs, pgm_int_code);
 | 
						location = get_psw_address(regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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));
 | 
				
			||||||
| 
						 | 
					@ -627,32 +591,18 @@ static void data_exception(struct pt_regs *regs, long pgm_int_code,
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		signal = SIGILL;
 | 
							signal = SIGILL;
 | 
				
			||||||
        if (signal == SIGFPE)
 | 
					        if (signal == SIGFPE)
 | 
				
			||||||
		do_fp_trap(regs, location,
 | 
							do_fp_trap(regs, current->thread.fp_regs.fpc);
 | 
				
			||||||
			   current->thread.fp_regs.fpc, pgm_int_code);
 | 
						else if (signal)
 | 
				
			||||||
        else if (signal) {
 | 
							do_trap(regs, signal, ILL_ILLOPN, "data exception");
 | 
				
			||||||
		siginfo_t info;
 | 
					 | 
				
			||||||
		info.si_signo = signal;
 | 
					 | 
				
			||||||
		info.si_errno = 0;
 | 
					 | 
				
			||||||
		info.si_code = ILL_ILLOPN;
 | 
					 | 
				
			||||||
		info.si_addr = location;
 | 
					 | 
				
			||||||
		do_trap(pgm_int_code, signal, "data exception", regs, &info);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void space_switch_exception(struct pt_regs *regs, long pgm_int_code,
 | 
					static void space_switch_exception(struct pt_regs *regs)
 | 
				
			||||||
				   unsigned long trans_exc_code)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        siginfo_t info;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Set user psw back to home space mode. */
 | 
						/* Set user psw back to home space mode. */
 | 
				
			||||||
	if (regs->psw.mask & PSW_MASK_PSTATE)
 | 
						if (regs->psw.mask & PSW_MASK_PSTATE)
 | 
				
			||||||
		regs->psw.mask |= PSW_ASC_HOME;
 | 
							regs->psw.mask |= PSW_ASC_HOME;
 | 
				
			||||||
	/* Send SIGILL. */
 | 
						/* Send SIGILL. */
 | 
				
			||||||
        info.si_signo = SIGILL;
 | 
						do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");
 | 
				
			||||||
        info.si_errno = 0;
 | 
					 | 
				
			||||||
        info.si_code = ILL_PRVOPC;
 | 
					 | 
				
			||||||
	info.si_addr = get_psw_address(regs, pgm_int_code);
 | 
					 | 
				
			||||||
	do_trap(pgm_int_code, SIGILL, "space switch event", regs, &info);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void __kprobes kernel_stack_overflow(struct pt_regs * regs)
 | 
					void __kprobes kernel_stack_overflow(struct pt_regs * regs)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -125,8 +125,7 @@ static inline int user_space_fault(unsigned long trans_exc_code)
 | 
				
			||||||
	return trans_exc_code != 3;
 | 
						return trans_exc_code != 3;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void report_user_fault(struct pt_regs *regs, long int_code,
 | 
					static inline void report_user_fault(struct pt_regs *regs, long signr)
 | 
				
			||||||
				     int signr, unsigned long address)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if ((task_pid_nr(current) > 1) && !show_unhandled_signals)
 | 
						if ((task_pid_nr(current) > 1) && !show_unhandled_signals)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -134,10 +133,12 @@ static inline void report_user_fault(struct pt_regs *regs, long int_code,
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	if (!printk_ratelimit())
 | 
						if (!printk_ratelimit())
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	printk("User process fault: interruption code 0x%lX ", int_code);
 | 
						printk(KERN_ALERT "User process fault: interruption code 0x%X ",
 | 
				
			||||||
 | 
						       regs->int_code);
 | 
				
			||||||
	print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN);
 | 
						print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN);
 | 
				
			||||||
	printk("\n");
 | 
						printk(KERN_CONT "\n");
 | 
				
			||||||
	printk("failing address: %lX\n", address);
 | 
						printk(KERN_ALERT "failing address: %lX\n",
 | 
				
			||||||
 | 
						       regs->int_parm_long & __FAIL_ADDR_MASK);
 | 
				
			||||||
	show_regs(regs);
 | 
						show_regs(regs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -145,24 +146,18 @@ static inline void report_user_fault(struct pt_regs *regs, long int_code,
 | 
				
			||||||
 * Send SIGSEGV to task.  This is an external routine
 | 
					 * Send SIGSEGV to task.  This is an external routine
 | 
				
			||||||
 * to keep the stack usage of do_page_fault small.
 | 
					 * to keep the stack usage of do_page_fault small.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static noinline void do_sigsegv(struct pt_regs *regs, long int_code,
 | 
					static noinline void do_sigsegv(struct pt_regs *regs, int si_code)
 | 
				
			||||||
				int si_code, unsigned long trans_exc_code)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct siginfo si;
 | 
						struct siginfo si;
 | 
				
			||||||
	unsigned long address;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	address = trans_exc_code & __FAIL_ADDR_MASK;
 | 
						report_user_fault(regs, SIGSEGV);
 | 
				
			||||||
	current->thread.prot_addr = address;
 | 
					 | 
				
			||||||
	current->thread.trap_no = int_code;
 | 
					 | 
				
			||||||
	report_user_fault(regs, int_code, SIGSEGV, address);
 | 
					 | 
				
			||||||
	si.si_signo = SIGSEGV;
 | 
						si.si_signo = SIGSEGV;
 | 
				
			||||||
	si.si_code = si_code;
 | 
						si.si_code = si_code;
 | 
				
			||||||
	si.si_addr = (void __user *) address;
 | 
						si.si_addr = (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK);
 | 
				
			||||||
	force_sig_info(SIGSEGV, &si, current);
 | 
						force_sig_info(SIGSEGV, &si, current);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static noinline void do_no_context(struct pt_regs *regs, long int_code,
 | 
					static noinline void do_no_context(struct pt_regs *regs)
 | 
				
			||||||
				   unsigned long trans_exc_code)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct exception_table_entry *fixup;
 | 
						const struct exception_table_entry *fixup;
 | 
				
			||||||
	unsigned long address;
 | 
						unsigned long address;
 | 
				
			||||||
| 
						 | 
					@ -178,55 +173,48 @@ static noinline void do_no_context(struct pt_regs *regs, long int_code,
 | 
				
			||||||
	 * Oops. The kernel tried to access some bad page. We'll have to
 | 
						 * Oops. The kernel tried to access some bad page. We'll have to
 | 
				
			||||||
	 * terminate things with extreme prejudice.
 | 
						 * terminate things with extreme prejudice.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	address = trans_exc_code & __FAIL_ADDR_MASK;
 | 
						address = regs->int_parm_long & __FAIL_ADDR_MASK;
 | 
				
			||||||
	if (!user_space_fault(trans_exc_code))
 | 
						if (!user_space_fault(regs->int_parm_long))
 | 
				
			||||||
		printk(KERN_ALERT "Unable to handle kernel pointer dereference"
 | 
							printk(KERN_ALERT "Unable to handle kernel pointer dereference"
 | 
				
			||||||
		       " at virtual kernel address %p\n", (void *)address);
 | 
							       " at virtual kernel address %p\n", (void *)address);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		printk(KERN_ALERT "Unable to handle kernel paging request"
 | 
							printk(KERN_ALERT "Unable to handle kernel paging request"
 | 
				
			||||||
		       " at virtual user address %p\n", (void *)address);
 | 
							       " at virtual user address %p\n", (void *)address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	die("Oops", regs, int_code);
 | 
						die(regs, "Oops");
 | 
				
			||||||
	do_exit(SIGKILL);
 | 
						do_exit(SIGKILL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static noinline void do_low_address(struct pt_regs *regs, long int_code,
 | 
					static noinline void do_low_address(struct pt_regs *regs)
 | 
				
			||||||
				    unsigned long trans_exc_code)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Low-address protection hit in kernel mode means
 | 
						/* Low-address protection hit in kernel mode means
 | 
				
			||||||
	   NULL pointer write access in kernel mode.  */
 | 
						   NULL pointer write access in kernel mode.  */
 | 
				
			||||||
	if (regs->psw.mask & PSW_MASK_PSTATE) {
 | 
						if (regs->psw.mask & PSW_MASK_PSTATE) {
 | 
				
			||||||
		/* Low-address protection hit in user mode 'cannot happen'. */
 | 
							/* Low-address protection hit in user mode 'cannot happen'. */
 | 
				
			||||||
		die ("Low-address protection", regs, int_code);
 | 
							die (regs, "Low-address protection");
 | 
				
			||||||
		do_exit(SIGKILL);
 | 
							do_exit(SIGKILL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	do_no_context(regs, int_code, trans_exc_code);
 | 
						do_no_context(regs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static noinline void do_sigbus(struct pt_regs *regs, long int_code,
 | 
					static noinline void do_sigbus(struct pt_regs *regs)
 | 
				
			||||||
			       unsigned long trans_exc_code)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct task_struct *tsk = current;
 | 
						struct task_struct *tsk = current;
 | 
				
			||||||
	unsigned long address;
 | 
					 | 
				
			||||||
	struct siginfo si;
 | 
						struct siginfo si;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Send a sigbus, regardless of whether we were in kernel
 | 
						 * Send a sigbus, regardless of whether we were in kernel
 | 
				
			||||||
	 * or user mode.
 | 
						 * or user mode.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	address = trans_exc_code & __FAIL_ADDR_MASK;
 | 
					 | 
				
			||||||
	tsk->thread.prot_addr = address;
 | 
					 | 
				
			||||||
	tsk->thread.trap_no = int_code;
 | 
					 | 
				
			||||||
	si.si_signo = SIGBUS;
 | 
						si.si_signo = SIGBUS;
 | 
				
			||||||
	si.si_errno = 0;
 | 
						si.si_errno = 0;
 | 
				
			||||||
	si.si_code = BUS_ADRERR;
 | 
						si.si_code = BUS_ADRERR;
 | 
				
			||||||
	si.si_addr = (void __user *) address;
 | 
						si.si_addr = (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK);
 | 
				
			||||||
	force_sig_info(SIGBUS, &si, tsk);
 | 
						force_sig_info(SIGBUS, &si, tsk);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static noinline void do_fault_error(struct pt_regs *regs, long int_code,
 | 
					static noinline void do_fault_error(struct pt_regs *regs, int fault)
 | 
				
			||||||
				    unsigned long trans_exc_code, int fault)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int si_code;
 | 
						int si_code;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -238,24 +226,24 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code,
 | 
				
			||||||
			/* User mode accesses just cause a SIGSEGV */
 | 
								/* User mode accesses just cause a SIGSEGV */
 | 
				
			||||||
			si_code = (fault == VM_FAULT_BADMAP) ?
 | 
								si_code = (fault == VM_FAULT_BADMAP) ?
 | 
				
			||||||
				SEGV_MAPERR : SEGV_ACCERR;
 | 
									SEGV_MAPERR : SEGV_ACCERR;
 | 
				
			||||||
			do_sigsegv(regs, int_code, si_code, trans_exc_code);
 | 
								do_sigsegv(regs, si_code);
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case VM_FAULT_BADCONTEXT:
 | 
						case VM_FAULT_BADCONTEXT:
 | 
				
			||||||
		do_no_context(regs, int_code, trans_exc_code);
 | 
							do_no_context(regs);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default: /* fault & VM_FAULT_ERROR */
 | 
						default: /* fault & VM_FAULT_ERROR */
 | 
				
			||||||
		if (fault & VM_FAULT_OOM) {
 | 
							if (fault & VM_FAULT_OOM) {
 | 
				
			||||||
			if (!(regs->psw.mask & PSW_MASK_PSTATE))
 | 
								if (!(regs->psw.mask & PSW_MASK_PSTATE))
 | 
				
			||||||
				do_no_context(regs, int_code, trans_exc_code);
 | 
									do_no_context(regs);
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				pagefault_out_of_memory();
 | 
									pagefault_out_of_memory();
 | 
				
			||||||
		} else if (fault & VM_FAULT_SIGBUS) {
 | 
							} else if (fault & VM_FAULT_SIGBUS) {
 | 
				
			||||||
			/* Kernel mode? Handle exceptions or die */
 | 
								/* Kernel mode? Handle exceptions or die */
 | 
				
			||||||
			if (!(regs->psw.mask & PSW_MASK_PSTATE))
 | 
								if (!(regs->psw.mask & PSW_MASK_PSTATE))
 | 
				
			||||||
				do_no_context(regs, int_code, trans_exc_code);
 | 
									do_no_context(regs);
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				do_sigbus(regs, int_code, trans_exc_code);
 | 
									do_sigbus(regs);
 | 
				
			||||||
		} else
 | 
							} else
 | 
				
			||||||
			BUG();
 | 
								BUG();
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					@ -273,12 +261,12 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code,
 | 
				
			||||||
 *   11       Page translation     ->  Not present       (nullification)
 | 
					 *   11       Page translation     ->  Not present       (nullification)
 | 
				
			||||||
 *   3b       Region third trans.  ->  Not present       (nullification)
 | 
					 *   3b       Region third trans.  ->  Not present       (nullification)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static inline int do_exception(struct pt_regs *regs, int access,
 | 
					static inline int do_exception(struct pt_regs *regs, int access)
 | 
				
			||||||
			       unsigned long trans_exc_code)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct task_struct *tsk;
 | 
						struct task_struct *tsk;
 | 
				
			||||||
	struct mm_struct *mm;
 | 
						struct mm_struct *mm;
 | 
				
			||||||
	struct vm_area_struct *vma;
 | 
						struct vm_area_struct *vma;
 | 
				
			||||||
 | 
						unsigned long trans_exc_code;
 | 
				
			||||||
	unsigned long address;
 | 
						unsigned long address;
 | 
				
			||||||
	unsigned int flags;
 | 
						unsigned int flags;
 | 
				
			||||||
	int fault;
 | 
						int fault;
 | 
				
			||||||
| 
						 | 
					@ -288,6 +276,7 @@ static inline int do_exception(struct pt_regs *regs, int access,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tsk = current;
 | 
						tsk = current;
 | 
				
			||||||
	mm = tsk->mm;
 | 
						mm = tsk->mm;
 | 
				
			||||||
 | 
						trans_exc_code = regs->int_parm_long;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Verify that the fault happened in user space, that
 | 
						 * Verify that the fault happened in user space, that
 | 
				
			||||||
| 
						 | 
					@ -387,45 +376,46 @@ out:
 | 
				
			||||||
	return fault;
 | 
						return fault;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void __kprobes do_protection_exception(struct pt_regs *regs, long pgm_int_code,
 | 
					void __kprobes do_protection_exception(struct pt_regs *regs)
 | 
				
			||||||
				       unsigned long trans_exc_code)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						unsigned long trans_exc_code;
 | 
				
			||||||
	int fault;
 | 
						int fault;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						trans_exc_code = regs->int_parm_long;
 | 
				
			||||||
	/* Protection exception is suppressing, decrement psw address. */
 | 
						/* Protection exception is suppressing, decrement psw address. */
 | 
				
			||||||
	regs->psw.addr = __rewind_psw(regs->psw, pgm_int_code >> 16);
 | 
						regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16);
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Check for low-address protection.  This needs to be treated
 | 
						 * Check for low-address protection.  This needs to be treated
 | 
				
			||||||
	 * as a special case because the translation exception code
 | 
						 * as a special case because the translation exception code
 | 
				
			||||||
	 * field is not guaranteed to contain valid data in this case.
 | 
						 * field is not guaranteed to contain valid data in this case.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (unlikely(!(trans_exc_code & 4))) {
 | 
						if (unlikely(!(trans_exc_code & 4))) {
 | 
				
			||||||
		do_low_address(regs, pgm_int_code, trans_exc_code);
 | 
							do_low_address(regs);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	fault = do_exception(regs, VM_WRITE, trans_exc_code);
 | 
						fault = do_exception(regs, VM_WRITE);
 | 
				
			||||||
	if (unlikely(fault))
 | 
						if (unlikely(fault))
 | 
				
			||||||
		do_fault_error(regs, 4, trans_exc_code, fault);
 | 
							do_fault_error(regs, fault);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void __kprobes do_dat_exception(struct pt_regs *regs, long pgm_int_code,
 | 
					void __kprobes do_dat_exception(struct pt_regs *regs)
 | 
				
			||||||
				unsigned long trans_exc_code)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int access, fault;
 | 
						int access, fault;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	access = VM_READ | VM_EXEC | VM_WRITE;
 | 
						access = VM_READ | VM_EXEC | VM_WRITE;
 | 
				
			||||||
	fault = do_exception(regs, access, trans_exc_code);
 | 
						fault = do_exception(regs, access);
 | 
				
			||||||
	if (unlikely(fault))
 | 
						if (unlikely(fault))
 | 
				
			||||||
		do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault);
 | 
							do_fault_error(regs, fault);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_64BIT
 | 
					#ifdef CONFIG_64BIT
 | 
				
			||||||
void __kprobes do_asce_exception(struct pt_regs *regs, long pgm_int_code,
 | 
					void __kprobes do_asce_exception(struct pt_regs *regs)
 | 
				
			||||||
				 unsigned long trans_exc_code)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mm_struct *mm = current->mm;
 | 
						struct mm_struct *mm = current->mm;
 | 
				
			||||||
	struct vm_area_struct *vma;
 | 
						struct vm_area_struct *vma;
 | 
				
			||||||
 | 
						unsigned long trans_exc_code;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						trans_exc_code = regs->int_parm_long;
 | 
				
			||||||
	if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
 | 
						if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
 | 
				
			||||||
		goto no_context;
 | 
							goto no_context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -440,12 +430,12 @@ void __kprobes do_asce_exception(struct pt_regs *regs, long pgm_int_code,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* User mode accesses just cause a SIGSEGV */
 | 
						/* User mode accesses just cause a SIGSEGV */
 | 
				
			||||||
	if (regs->psw.mask & PSW_MASK_PSTATE) {
 | 
						if (regs->psw.mask & PSW_MASK_PSTATE) {
 | 
				
			||||||
		do_sigsegv(regs, pgm_int_code, SEGV_MAPERR, trans_exc_code);
 | 
							do_sigsegv(regs, SEGV_MAPERR);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
no_context:
 | 
					no_context:
 | 
				
			||||||
	do_no_context(regs, pgm_int_code, trans_exc_code);
 | 
						do_no_context(regs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -459,14 +449,15 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
 | 
				
			||||||
		regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT;
 | 
							regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT;
 | 
				
			||||||
	regs.psw.addr = (unsigned long) __builtin_return_address(0);
 | 
						regs.psw.addr = (unsigned long) __builtin_return_address(0);
 | 
				
			||||||
	regs.psw.addr |= PSW_ADDR_AMODE;
 | 
						regs.psw.addr |= PSW_ADDR_AMODE;
 | 
				
			||||||
	uaddr &= PAGE_MASK;
 | 
						regs.int_code = pgm_int_code;
 | 
				
			||||||
 | 
						regs.int_parm_long = (uaddr & PAGE_MASK) | 2;
 | 
				
			||||||
	access = write ? VM_WRITE : VM_READ;
 | 
						access = write ? VM_WRITE : VM_READ;
 | 
				
			||||||
	fault = do_exception(®s, access, uaddr | 2);
 | 
						fault = do_exception(®s, access);
 | 
				
			||||||
	if (unlikely(fault)) {
 | 
						if (unlikely(fault)) {
 | 
				
			||||||
		if (fault & VM_FAULT_OOM)
 | 
							if (fault & VM_FAULT_OOM)
 | 
				
			||||||
			return -EFAULT;
 | 
								return -EFAULT;
 | 
				
			||||||
		else if (fault & VM_FAULT_SIGBUS)
 | 
							else if (fault & VM_FAULT_SIGBUS)
 | 
				
			||||||
			do_sigbus(®s, pgm_int_code, uaddr);
 | 
								do_sigbus(®s);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return fault ? -EFAULT : 0;
 | 
						return fault ? -EFAULT : 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue