Commit aa33c8cb authored by Martin Schwidefsky's avatar Martin Schwidefsky

[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: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 679e2ea7
...@@ -22,6 +22,6 @@ enum die_val { ...@@ -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 { ...@@ -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 ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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) ...@@ -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) ...@@ -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: ...@@ -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 @@ ...@@ -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); ...@@ -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);
......
/* /*
* 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: ...@@ -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: ...@@ -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: ...@@ -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) ...@@ -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) ...@@ -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: ...@@ -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, ...@@ -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) {
regs->gprs[6] = task_thread_info(current)->last_break; /* 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;
}
/* 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) ...@@ -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) ...@@ -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) ...@@ -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:
......
This diff is collapsed.
...@@ -125,8 +125,7 @@ static inline int user_space_fault(unsigned long trans_exc_code) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 @@ static inline int do_exception(struct pt_regs *regs, int access, ...@@ -387,45 +376,46 @@ static inline int do_exception(struct pt_regs *regs, int access,
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, ...@@ -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) ...@@ -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(&regs, access, uaddr | 2); fault = do_exception(&regs, 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(&regs, pgm_int_code, uaddr); do_sigbus(&regs);
} }
return fault ? -EFAULT : 0; return fault ? -EFAULT : 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment