aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2011-12-27 05:27:18 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2011-12-27 05:27:12 -0500
commitaa33c8cbbae2eb98489a3a363099b362146a8f4c (patch)
tree315ac880b4a4af8f7c0c2822c2c5e5817033a5ab /arch/s390/kernel
parent679e2ea73366cac81ede4104e6d3048cb806df2c (diff)
[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>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r--arch/s390/kernel/asm-offsets.c3
-rw-r--r--arch/s390/kernel/compat_signal.c8
-rw-r--r--arch/s390/kernel/entry.S22
-rw-r--r--arch/s390/kernel/entry.h10
-rw-r--r--arch/s390/kernel/entry64.S27
-rw-r--r--arch/s390/kernel/signal.c20
-rw-r--r--arch/s390/kernel/traps.c168
7 files changed, 108 insertions, 150 deletions
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index c1a56ba5f848..6e6a72e66d60 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -45,7 +45,8 @@ int main(void)
45 DEFINE(__PT_PSW, offsetof(struct pt_regs, psw)); 45 DEFINE(__PT_PSW, offsetof(struct pt_regs, psw));
46 DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs)); 46 DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs));
47 DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2)); 47 DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2));
48 DEFINE(__PT_SVC_CODE, offsetof(struct pt_regs, svc_code)); 48 DEFINE(__PT_INT_CODE, offsetof(struct pt_regs, int_code));
49 DEFINE(__PT_INT_PARM_LONG, offsetof(struct pt_regs, int_parm_long));
49 DEFINE(__PT_SIZE, sizeof(struct pt_regs)); 50 DEFINE(__PT_SIZE, sizeof(struct pt_regs));
50 BLANK(); 51 BLANK();
51 DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain)); 52 DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain));
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index 4f68c81d3ffa..60c268b16f91 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -501,8 +501,12 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
501 501
502 /* We forgot to include these in the sigcontext. 502 /* We forgot to include these in the sigcontext.
503 To avoid breaking binary compatibility, they are passed as args. */ 503 To avoid breaking binary compatibility, they are passed as args. */
504 regs->gprs[4] = current->thread.trap_no; 504 if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
505 regs->gprs[5] = current->thread.prot_addr; 505 sig == SIGTRAP || sig == SIGFPE) {
506 /* set extra registers only for synchronous signals */
507 regs->gprs[4] = regs->int_code & 127;
508 regs->gprs[5] = regs->int_parm_long;
509 }
506 510
507 /* Place signal number on stack to allow backtrace from handler. */ 511 /* Place signal number on stack to allow backtrace from handler. */
508 if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo)) 512 if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo))
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index c2773cff89c3..3705700ed374 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -184,16 +184,16 @@ sysc_vtime:
184 stm %r0,%r7,__PT_R0(%r11) 184 stm %r0,%r7,__PT_R0(%r11)
185 mvc __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC 185 mvc __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC
186 mvc __PT_PSW(8,%r11),__LC_SVC_OLD_PSW 186 mvc __PT_PSW(8,%r11),__LC_SVC_OLD_PSW
187 mvc __PT_SVC_CODE(4,%r11),__LC_SVC_ILC 187 mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC
188sysc_do_svc: 188sysc_do_svc:
189 oi __TI_flags+3(%r12),_TIF_SYSCALL 189 oi __TI_flags+3(%r12),_TIF_SYSCALL
190 lh %r8,__PT_SVC_CODE+2(%r11) 190 lh %r8,__PT_INT_CODE+2(%r11)
191 sla %r8,2 # shift and test for svc0 191 sla %r8,2 # shift and test for svc0
192 jnz sysc_nr_ok 192 jnz sysc_nr_ok
193 # svc 0: system call number in %r1 193 # svc 0: system call number in %r1
194 cl %r1,BASED(.Lnr_syscalls) 194 cl %r1,BASED(.Lnr_syscalls)
195 jnl sysc_nr_ok 195 jnl sysc_nr_ok
196 sth %r1,__PT_SVC_CODE+2(%r11) 196 sth %r1,__PT_INT_CODE+2(%r11)
197 lr %r8,%r1 197 lr %r8,%r1
198 sla %r8,2 198 sla %r8,2
199sysc_nr_ok: 199sysc_nr_ok:
@@ -266,9 +266,9 @@ sysc_sigpending:
266 jno sysc_return 266 jno sysc_return
267 lm %r2,%r7,__PT_R2(%r11) # load svc arguments 267 lm %r2,%r7,__PT_R2(%r11) # load svc arguments
268 xr %r8,%r8 # svc 0 returns -ENOSYS 268 xr %r8,%r8 # svc 0 returns -ENOSYS
269 clc __PT_SVC_CODE+2(2,%r11),BASED(.Lnr_syscalls+2) 269 clc __PT_INT_CODE+2(2,%r11),BASED(.Lnr_syscalls+2)
270 jnl sysc_nr_ok # invalid svc number -> do svc 0 270 jnl sysc_nr_ok # invalid svc number -> do svc 0
271 lh %r8,__PT_SVC_CODE+2(%r11) # load new svc number 271 lh %r8,__PT_INT_CODE+2(%r11) # load new svc number
272 sla %r8,2 272 sla %r8,2
273 j sysc_nr_ok # restart svc 273 j sysc_nr_ok # restart svc
274 274
@@ -300,7 +300,7 @@ sysc_tracesys:
300 lr %r2,%r11 # pass pointer to pt_regs 300 lr %r2,%r11 # pass pointer to pt_regs
301 la %r3,0 301 la %r3,0
302 xr %r0,%r0 302 xr %r0,%r0
303 icm %r0,3,__PT_SVC_CODE+2(%r11) 303 icm %r0,3,__PT_INT_CODE+2(%r11)
304 st %r0,__PT_R2(%r11) 304 st %r0,__PT_R2(%r11)
305 basr %r14,%r1 # call do_syscall_trace_enter 305 basr %r14,%r1 # call do_syscall_trace_enter
306 cl %r2,BASED(.Lnr_syscalls) 306 cl %r2,BASED(.Lnr_syscalls)
@@ -396,6 +396,8 @@ ENTRY(pgm_check_handler)
396 stm %r0,%r7,__PT_R0(%r11) 396 stm %r0,%r7,__PT_R0(%r11)
397 mvc __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC 397 mvc __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC
398 stm %r8,%r9,__PT_PSW(%r11) 398 stm %r8,%r9,__PT_PSW(%r11)
399 mvc __PT_INT_CODE(4,%r11),__LC_PGM_ILC
400 mvc __PT_INT_PARM_LONG(4,%r11),__LC_TRANS_EXC_CODE
399 tm __LC_PGM_ILC+3,0x80 # check for per exception 401 tm __LC_PGM_ILC+3,0x80 # check for per exception
400 jz 0f 402 jz 0f
401 l %r1,__TI_task(%r12) 403 l %r1,__TI_task(%r12)
@@ -405,13 +407,11 @@ ENTRY(pgm_check_handler)
405 mvc __THREAD_per_address(4,%r1),__LC_PER_ADDRESS 407 mvc __THREAD_per_address(4,%r1),__LC_PER_ADDRESS
406 mvc __THREAD_per_cause(2,%r1),__LC_PER_CAUSE 408 mvc __THREAD_per_cause(2,%r1),__LC_PER_CAUSE
407 mvc __THREAD_per_paid(1,%r1),__LC_PER_PAID 409 mvc __THREAD_per_paid(1,%r1),__LC_PER_PAID
4080: l %r3,__LC_PGM_ILC # load program interruption code 4100: REENABLE_IRQS
409 l %r4,__LC_TRANS_EXC_CODE
410 REENABLE_IRQS
411 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) 411 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
412 l %r1,BASED(.Ljump_table) 412 l %r1,BASED(.Ljump_table)
413 la %r10,0x7f 413 la %r10,0x7f
414 nr %r10,%r3 414 n %r10,__PT_INT_CODE(%r11)
415 je sysc_return 415 je sysc_return
416 sll %r10,2 416 sll %r10,2
417 l %r1,0(%r10,%r1) # load address of handler routine 417 l %r1,0(%r10,%r1) # load address of handler routine
@@ -858,7 +858,7 @@ cleanup_system_call:
858 mvc __PT_R8(32,%r15),__LC_SAVE_AREA_SYNC 858 mvc __PT_R8(32,%r15),__LC_SAVE_AREA_SYNC
859 stm %r0,%r7,__PT_R0(%r15) 859 stm %r0,%r7,__PT_R0(%r15)
860 mvc __PT_PSW(8,%r15),__LC_SVC_OLD_PSW 860 mvc __PT_PSW(8,%r15),__LC_SVC_OLD_PSW
861 mvc __PT_SVC_CODE(4,%r15),__LC_SVC_ILC 861 mvc __PT_INT_CODE(4,%r15),__LC_SVC_ILC
862 # setup saved register 15 862 # setup saved register 15
863 ahi %r15,-STACK_FRAME_OVERHEAD 863 ahi %r15,-STACK_FRAME_OVERHEAD
864 st %r15,28(%r11) # r15 stack pointer 864 st %r15,28(%r11) # r15 stack pointer
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index ef8fb1d6e8d7..bf538aaf407d 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -6,15 +6,15 @@
6#include <asm/ptrace.h> 6#include <asm/ptrace.h>
7 7
8 8
9extern void (*pgm_check_table[128])(struct pt_regs *, long, unsigned long); 9extern void (*pgm_check_table[128])(struct pt_regs *);
10extern void *restart_stack; 10extern void *restart_stack;
11 11
12asmlinkage long do_syscall_trace_enter(struct pt_regs *regs); 12asmlinkage long do_syscall_trace_enter(struct pt_regs *regs);
13asmlinkage void do_syscall_trace_exit(struct pt_regs *regs); 13asmlinkage void do_syscall_trace_exit(struct pt_regs *regs);
14 14
15void do_protection_exception(struct pt_regs *, long, unsigned long); 15void do_protection_exception(struct pt_regs *regs);
16void do_dat_exception(struct pt_regs *, long, unsigned long); 16void do_dat_exception(struct pt_regs *regs);
17void do_asce_exception(struct pt_regs *, long, unsigned long); 17void do_asce_exception(struct pt_regs *regs);
18 18
19void do_per_trap(struct pt_regs *regs); 19void do_per_trap(struct pt_regs *regs);
20void syscall_trace(struct pt_regs *regs, int entryexit); 20void 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);
28void do_restart(void); 28void do_restart(void);
29int __cpuinit start_secondary(void *cpuvoid); 29int __cpuinit start_secondary(void *cpuvoid);
30void __init startup_init(void); 30void __init startup_init(void);
31void die(const char * str, struct pt_regs * regs, long err); 31void die(struct pt_regs *regs, const char *str);
32 32
33void __init time_init(void); 33void __init time_init(void);
34 34
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 73845a9e587c..412a7b8783d7 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -1,4 +1,3 @@
1
2/* 1/*
3 * arch/s390/kernel/entry64.S 2 * arch/s390/kernel/entry64.S
4 * S390 low-level entry points. 3 * S390 low-level entry points.
@@ -200,17 +199,17 @@ sysc_vtime:
200 stmg %r0,%r7,__PT_R0(%r11) 199 stmg %r0,%r7,__PT_R0(%r11)
201 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC 200 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
202 mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW 201 mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW
203 mvc __PT_SVC_CODE(4,%r11),__LC_SVC_ILC 202 mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC
204sysc_do_svc: 203sysc_do_svc:
205 oi __TI_flags+7(%r12),_TIF_SYSCALL 204 oi __TI_flags+7(%r12),_TIF_SYSCALL
206 llgh %r8,__PT_SVC_CODE+2(%r11) 205 llgh %r8,__PT_INT_CODE+2(%r11)
207 slag %r8,%r8,2 # shift and test for svc 0 206 slag %r8,%r8,2 # shift and test for svc 0
208 jnz sysc_nr_ok 207 jnz sysc_nr_ok
209 # svc 0: system call number in %r1 208 # svc 0: system call number in %r1
210 llgfr %r1,%r1 # clear high word in r1 209 llgfr %r1,%r1 # clear high word in r1
211 cghi %r1,NR_syscalls 210 cghi %r1,NR_syscalls
212 jnl sysc_nr_ok 211 jnl sysc_nr_ok
213 sth %r1,__PT_SVC_CODE+2(%r11) 212 sth %r1,__PT_INT_CODE+2(%r11)
214 slag %r8,%r1,2 213 slag %r8,%r1,2
215sysc_nr_ok: 214sysc_nr_ok:
216 larl %r10,sys_call_table # 64 bit system call table 215 larl %r10,sys_call_table # 64 bit system call table
@@ -288,7 +287,7 @@ sysc_sigpending:
288 jno sysc_return 287 jno sysc_return
289 lmg %r2,%r7,__PT_R2(%r11) # load svc arguments 288 lmg %r2,%r7,__PT_R2(%r11) # load svc arguments
290 lghi %r8,0 # svc 0 returns -ENOSYS 289 lghi %r8,0 # svc 0 returns -ENOSYS
291 lh %r1,__PT_SVC_CODE+2(%r11) # load new svc number 290 lh %r1,__PT_INT_CODE+2(%r11) # load new svc number
292 cghi %r1,NR_syscalls 291 cghi %r1,NR_syscalls
293 jnl sysc_nr_ok # invalid svc number -> do svc 0 292 jnl sysc_nr_ok # invalid svc number -> do svc 0
294 slag %r8,%r1,2 293 slag %r8,%r1,2
@@ -318,7 +317,7 @@ sysc_singlestep:
318sysc_tracesys: 317sysc_tracesys:
319 lgr %r2,%r11 # pass pointer to pt_regs 318 lgr %r2,%r11 # pass pointer to pt_regs
320 la %r3,0 319 la %r3,0
321 llgh %r0,__PT_SVC_CODE+2(%r11) 320 llgh %r0,__PT_INT_CODE+2(%r11)
322 stg %r0,__PT_R2(%r11) 321 stg %r0,__PT_R2(%r11)
323 brasl %r14,do_syscall_trace_enter 322 brasl %r14,do_syscall_trace_enter
324 lghi %r0,NR_syscalls 323 lghi %r0,NR_syscalls
@@ -411,6 +410,8 @@ ENTRY(pgm_check_handler)
411 stmg %r0,%r7,__PT_R0(%r11) 410 stmg %r0,%r7,__PT_R0(%r11)
412 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC 411 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
413 stmg %r8,%r9,__PT_PSW(%r11) 412 stmg %r8,%r9,__PT_PSW(%r11)
413 mvc __PT_INT_CODE(4,%r11),__LC_PGM_ILC
414 mvc __PT_INT_PARM_LONG(8,%r11),__LC_TRANS_EXC_CODE
414 stg %r10,__PT_ARGS(%r11) 415 stg %r10,__PT_ARGS(%r11)
415 tm __LC_PGM_ILC+3,0x80 # check for per exception 416 tm __LC_PGM_ILC+3,0x80 # check for per exception
416 jz 0f 417 jz 0f
@@ -421,15 +422,13 @@ ENTRY(pgm_check_handler)
421 mvc __THREAD_per_address(8,%r1),__LC_PER_ADDRESS 422 mvc __THREAD_per_address(8,%r1),__LC_PER_ADDRESS
422 mvc __THREAD_per_cause(2,%r1),__LC_PER_CAUSE 423 mvc __THREAD_per_cause(2,%r1),__LC_PER_CAUSE
423 mvc __THREAD_per_paid(1,%r1),__LC_PER_PAID 424 mvc __THREAD_per_paid(1,%r1),__LC_PER_PAID
4240: lgf %r3,__LC_PGM_ILC # load program interruption code 4250: REENABLE_IRQS
425 lg %r4,__LC_TRANS_EXC_CODE
426 REENABLE_IRQS
427 xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) 426 xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
428 lghi %r10,0x7f
429 ngr %r10,%r3
430 je sysc_return
431 sll %r10,3
432 larl %r1,pgm_check_table 427 larl %r1,pgm_check_table
428 llgh %r10,__PT_INT_CODE+2(%r11)
429 nill %r10,0x007f
430 sll %r10,3
431 je sysc_return
433 lg %r1,0(%r10,%r1) # load address of handler routine 432 lg %r1,0(%r10,%r1) # load address of handler routine
434 lgr %r2,%r11 # pass pointer to pt_regs 433 lgr %r2,%r11 # pass pointer to pt_regs
435 basr %r14,%r1 # branch to interrupt-handler 434 basr %r14,%r1 # branch to interrupt-handler
@@ -877,7 +876,7 @@ cleanup_system_call:
877 mvc __PT_R8(64,%r15),__LC_SAVE_AREA_SYNC 876 mvc __PT_R8(64,%r15),__LC_SAVE_AREA_SYNC
878 stmg %r0,%r7,__PT_R0(%r15) 877 stmg %r0,%r7,__PT_R0(%r15)
879 mvc __PT_PSW(16,%r15),__LC_SVC_OLD_PSW 878 mvc __PT_PSW(16,%r15),__LC_SVC_OLD_PSW
880 mvc __PT_SVC_CODE(4,%r15),__LC_SVC_ILC 879 mvc __PT_INT_CODE(4,%r15),__LC_SVC_ILC
881 # setup saved register r15 880 # setup saved register r15
882 aghi %r15,-STACK_FRAME_OVERHEAD 881 aghi %r15,-STACK_FRAME_OVERHEAD
883 stg %r15,56(%r11) # r15 stack pointer 882 stg %r15,56(%r11) # r15 stack pointer
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 7f6f9f354545..a8ba840294ff 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -302,9 +302,13 @@ static int setup_frame(int sig, struct k_sigaction *ka,
302 302
303 /* We forgot to include these in the sigcontext. 303 /* We forgot to include these in the sigcontext.
304 To avoid breaking binary compatibility, they are passed as args. */ 304 To avoid breaking binary compatibility, they are passed as args. */
305 regs->gprs[4] = current->thread.trap_no; 305 if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
306 regs->gprs[5] = current->thread.prot_addr; 306 sig == SIGTRAP || sig == SIGFPE) {
307 regs->gprs[6] = task_thread_info(current)->last_break; 307 /* set extra registers only for synchronous signals */
308 regs->gprs[4] = regs->int_code & 127;
309 regs->gprs[5] = regs->int_parm_long;
310 regs->gprs[6] = task_thread_info(current)->last_break;
311 }
308 312
309 /* Place signal number on stack to allow backtrace from handler. */ 313 /* Place signal number on stack to allow backtrace from handler. */
310 if (__put_user(regs->gprs[2], (int __user *) &frame->signo)) 314 if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
@@ -434,13 +438,13 @@ void do_signal(struct pt_regs *regs)
434 * call information. 438 * call information.
435 */ 439 */
436 current_thread_info()->system_call = 440 current_thread_info()->system_call =
437 test_thread_flag(TIF_SYSCALL) ? regs->svc_code : 0; 441 test_thread_flag(TIF_SYSCALL) ? regs->int_code : 0;
438 signr = get_signal_to_deliver(&info, &ka, regs, NULL); 442 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
439 443
440 if (signr > 0) { 444 if (signr > 0) {
441 /* Whee! Actually deliver the signal. */ 445 /* Whee! Actually deliver the signal. */
442 if (current_thread_info()->system_call) { 446 if (current_thread_info()->system_call) {
443 regs->svc_code = current_thread_info()->system_call; 447 regs->int_code = current_thread_info()->system_call;
444 /* Check for system call restarting. */ 448 /* Check for system call restarting. */
445 switch (regs->gprs[2]) { 449 switch (regs->gprs[2]) {
446 case -ERESTART_RESTARTBLOCK: 450 case -ERESTART_RESTARTBLOCK:
@@ -457,7 +461,7 @@ void do_signal(struct pt_regs *regs)
457 regs->gprs[2] = regs->orig_gpr2; 461 regs->gprs[2] = regs->orig_gpr2;
458 regs->psw.addr = 462 regs->psw.addr =
459 __rewind_psw(regs->psw, 463 __rewind_psw(regs->psw,
460 regs->svc_code >> 16); 464 regs->int_code >> 16);
461 break; 465 break;
462 } 466 }
463 } 467 }
@@ -488,11 +492,11 @@ void do_signal(struct pt_regs *regs)
488 /* No handlers present - check for system call restart */ 492 /* No handlers present - check for system call restart */
489 clear_thread_flag(TIF_SYSCALL); 493 clear_thread_flag(TIF_SYSCALL);
490 if (current_thread_info()->system_call) { 494 if (current_thread_info()->system_call) {
491 regs->svc_code = current_thread_info()->system_call; 495 regs->int_code = current_thread_info()->system_call;
492 switch (regs->gprs[2]) { 496 switch (regs->gprs[2]) {
493 case -ERESTART_RESTARTBLOCK: 497 case -ERESTART_RESTARTBLOCK:
494 /* Restart with sys_restart_syscall */ 498 /* Restart with sys_restart_syscall */
495 regs->svc_code = __NR_restart_syscall; 499 regs->int_code = __NR_restart_syscall;
496 /* fallthrough */ 500 /* fallthrough */
497 case -ERESTARTNOHAND: 501 case -ERESTARTNOHAND:
498 case -ERESTARTSYS: 502 case -ERESTARTSYS:
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index a9807dd86276..dc6cc1b0ae66 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -43,7 +43,7 @@
43#include <asm/debug.h> 43#include <asm/debug.h>
44#include "entry.h" 44#include "entry.h"
45 45
46void (*pgm_check_table[128])(struct pt_regs *, long, unsigned long); 46void (*pgm_check_table[128])(struct pt_regs *regs);
47 47
48int show_unhandled_signals; 48int show_unhandled_signals;
49 49
@@ -234,7 +234,7 @@ void show_regs(struct pt_regs *regs)
234 234
235static DEFINE_SPINLOCK(die_lock); 235static DEFINE_SPINLOCK(die_lock);
236 236
237void die(const char * str, struct pt_regs * regs, long err) 237void die(struct pt_regs *regs, const char *str)
238{ 238{
239 static int die_counter; 239 static int die_counter;
240 240
@@ -243,7 +243,7 @@ void die(const char * str, struct pt_regs * regs, long err)
243 console_verbose(); 243 console_verbose();
244 spin_lock_irq(&die_lock); 244 spin_lock_irq(&die_lock);
245 bust_spinlocks(1); 245 bust_spinlocks(1);
246 printk("%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); 246 printk("%s: %04x [#%d] ", str, regs->int_code & 0xffff, ++die_counter);
247#ifdef CONFIG_PREEMPT 247#ifdef CONFIG_PREEMPT
248 printk("PREEMPT "); 248 printk("PREEMPT ");
249#endif 249#endif
@@ -254,7 +254,7 @@ void die(const char * str, struct pt_regs * regs, long err)
254 printk("DEBUG_PAGEALLOC"); 254 printk("DEBUG_PAGEALLOC");
255#endif 255#endif
256 printk("\n"); 256 printk("\n");
257 notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV); 257 notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV);
258 show_regs(regs); 258 show_regs(regs);
259 bust_spinlocks(0); 259 bust_spinlocks(0);
260 add_taint(TAINT_DIE); 260 add_taint(TAINT_DIE);
@@ -267,8 +267,7 @@ void die(const char * str, struct pt_regs * regs, long err)
267 do_exit(SIGSEGV); 267 do_exit(SIGSEGV);
268} 268}
269 269
270static void inline report_user_fault(struct pt_regs *regs, long int_code, 270static inline void report_user_fault(struct pt_regs *regs, int signr)
271 int signr)
272{ 271{
273 if ((task_pid_nr(current) > 1) && !show_unhandled_signals) 272 if ((task_pid_nr(current) > 1) && !show_unhandled_signals)
274 return; 273 return;
@@ -276,7 +275,7 @@ static void inline report_user_fault(struct pt_regs *regs, long int_code,
276 return; 275 return;
277 if (!printk_ratelimit()) 276 if (!printk_ratelimit())
278 return; 277 return;
279 printk("User process fault: interruption code 0x%lX ", int_code); 278 printk("User process fault: interruption code 0x%X ", regs->int_code);
280 print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN); 279 print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN);
281 printk("\n"); 280 printk("\n");
282 show_regs(regs); 281 show_regs(regs);
@@ -287,19 +286,28 @@ int is_valid_bugaddr(unsigned long addr)
287 return 1; 286 return 1;
288} 287}
289 288
290static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str, 289static inline void __user *get_psw_address(struct pt_regs *regs)
291 struct pt_regs *regs, siginfo_t *info)
292{ 290{
293 if (notify_die(DIE_TRAP, str, regs, pgm_int_code, 291 return (void __user *)
294 pgm_int_code, signr) == NOTIFY_STOP) 292 ((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN);
293}
294
295static void __kprobes do_trap(struct pt_regs *regs,
296 int si_signo, int si_code, char *str)
297{
298 siginfo_t info;
299
300 if (notify_die(DIE_TRAP, str, regs, 0,
301 regs->int_code, si_signo) == NOTIFY_STOP)
295 return; 302 return;
296 303
297 if (regs->psw.mask & PSW_MASK_PSTATE) { 304 if (regs->psw.mask & PSW_MASK_PSTATE) {
298 struct task_struct *tsk = current; 305 info.si_signo = si_signo;
299 306 info.si_errno = 0;
300 tsk->thread.trap_no = pgm_int_code & 0xffff; 307 info.si_code = si_code;
301 force_sig_info(signr, info, tsk); 308 info.si_addr = get_psw_address(regs);
302 report_user_fault(regs, pgm_int_code, signr); 309 force_sig_info(si_signo, &info, current);
310 report_user_fault(regs, si_signo);
303 } else { 311 } else {
304 const struct exception_table_entry *fixup; 312 const struct exception_table_entry *fixup;
305 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); 313 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,
311 btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs); 319 btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);
312 if (btt == BUG_TRAP_TYPE_WARN) 320 if (btt == BUG_TRAP_TYPE_WARN)
313 return; 321 return;
314 die(str, regs, pgm_int_code); 322 die(regs, str);
315 } 323 }
316 } 324 }
317} 325}
318 326
319static inline void __user *get_psw_address(struct pt_regs *regs,
320 long pgm_int_code)
321{
322 return (void __user *)
323 ((regs->psw.addr - (pgm_int_code >> 16)) & PSW_ADDR_INSN);
324}
325
326void __kprobes do_per_trap(struct pt_regs *regs) 327void __kprobes do_per_trap(struct pt_regs *regs)
327{ 328{
328 siginfo_t info; 329 siginfo_t info;
@@ -339,26 +340,19 @@ void __kprobes do_per_trap(struct pt_regs *regs)
339 force_sig_info(SIGTRAP, &info, current); 340 force_sig_info(SIGTRAP, &info, current);
340} 341}
341 342
342static void default_trap_handler(struct pt_regs *regs, long pgm_int_code, 343static void default_trap_handler(struct pt_regs *regs)
343 unsigned long trans_exc_code)
344{ 344{
345 if (regs->psw.mask & PSW_MASK_PSTATE) { 345 if (regs->psw.mask & PSW_MASK_PSTATE) {
346 report_user_fault(regs, pgm_int_code, SIGSEGV); 346 report_user_fault(regs, SIGSEGV);
347 do_exit(SIGSEGV); 347 do_exit(SIGSEGV);
348 } else 348 } else
349 die("Unknown program exception", regs, pgm_int_code); 349 die(regs, "Unknown program exception");
350} 350}
351 351
352#define DO_ERROR_INFO(name, signr, sicode, str) \ 352#define DO_ERROR_INFO(name, signr, sicode, str) \
353static void name(struct pt_regs *regs, long pgm_int_code, \ 353static void name(struct pt_regs *regs) \
354 unsigned long trans_exc_code) \
355{ \ 354{ \
356 siginfo_t info; \ 355 do_trap(regs, signr, sicode, str); \
357 info.si_signo = signr; \
358 info.si_errno = 0; \
359 info.si_code = sicode; \
360 info.si_addr = get_psw_address(regs, pgm_int_code); \
361 do_trap(pgm_int_code, signr, str, regs, &info); \
362} 356}
363 357
364DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR, 358DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
@@ -388,42 +382,34 @@ DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
388DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, 382DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN,
389 "translation exception") 383 "translation exception")
390 384
391static inline void do_fp_trap(struct pt_regs *regs, void __user *location, 385static inline void do_fp_trap(struct pt_regs *regs, int fpc)
392 int fpc, long pgm_int_code)
393{ 386{
394 siginfo_t si; 387 int si_code = 0;
395
396 si.si_signo = SIGFPE;
397 si.si_errno = 0;
398 si.si_addr = location;
399 si.si_code = 0;
400 /* FPC[2] is Data Exception Code */ 388 /* FPC[2] is Data Exception Code */
401 if ((fpc & 0x00000300) == 0) { 389 if ((fpc & 0x00000300) == 0) {
402 /* bits 6 and 7 of DXC are 0 iff IEEE exception */ 390 /* bits 6 and 7 of DXC are 0 iff IEEE exception */
403 if (fpc & 0x8000) /* invalid fp operation */ 391 if (fpc & 0x8000) /* invalid fp operation */
404 si.si_code = FPE_FLTINV; 392 si_code = FPE_FLTINV;
405 else if (fpc & 0x4000) /* div by 0 */ 393 else if (fpc & 0x4000) /* div by 0 */
406 si.si_code = FPE_FLTDIV; 394 si_code = FPE_FLTDIV;
407 else if (fpc & 0x2000) /* overflow */ 395 else if (fpc & 0x2000) /* overflow */
408 si.si_code = FPE_FLTOVF; 396 si_code = FPE_FLTOVF;
409 else if (fpc & 0x1000) /* underflow */ 397 else if (fpc & 0x1000) /* underflow */
410 si.si_code = FPE_FLTUND; 398 si_code = FPE_FLTUND;
411 else if (fpc & 0x0800) /* inexact */ 399 else if (fpc & 0x0800) /* inexact */
412 si.si_code = FPE_FLTRES; 400 si_code = FPE_FLTRES;
413 } 401 }
414 do_trap(pgm_int_code, SIGFPE, 402 do_trap(regs, SIGFPE, si_code, "floating point exception");
415 "floating point exception", regs, &si);
416} 403}
417 404
418static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_code, 405static void __kprobes illegal_op(struct pt_regs *regs)
419 unsigned long trans_exc_code)
420{ 406{
421 siginfo_t info; 407 siginfo_t info;
422 __u8 opcode[6]; 408 __u8 opcode[6];
423 __u16 __user *location; 409 __u16 __user *location;
424 int signal = 0; 410 int signal = 0;
425 411
426 location = get_psw_address(regs, pgm_int_code); 412 location = get_psw_address(regs);
427 413
428 if (regs->psw.mask & PSW_MASK_PSTATE) { 414 if (regs->psw.mask & PSW_MASK_PSTATE) {
429 if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) 415 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,
467 * If we get an illegal op in kernel mode, send it through the 453 * If we get an illegal op in kernel mode, send it through the
468 * kprobes notifier. If kprobes doesn't pick it up, SIGILL 454 * kprobes notifier. If kprobes doesn't pick it up, SIGILL
469 */ 455 */
470 if (notify_die(DIE_BPT, "bpt", regs, pgm_int_code, 456 if (notify_die(DIE_BPT, "bpt", regs, 0,
471 3, SIGTRAP) != NOTIFY_STOP) 457 3, SIGTRAP) != NOTIFY_STOP)
472 signal = SIGILL; 458 signal = SIGILL;
473 } 459 }
474 460
475#ifdef CONFIG_MATHEMU 461#ifdef CONFIG_MATHEMU
476 if (signal == SIGFPE) 462 if (signal == SIGFPE)
477 do_fp_trap(regs, location, 463 do_fp_trap(regs, current->thread.fp_regs.fpc);
478 current->thread.fp_regs.fpc, pgm_int_code); 464 else if (signal == SIGSEGV)
479 else if (signal == SIGSEGV) { 465 do_trap(regs, signal, SEGV_MAPERR, "user address fault");
480 info.si_signo = signal; 466 else
481 info.si_errno = 0;
482 info.si_code = SEGV_MAPERR;
483 info.si_addr = (void __user *) location;
484 do_trap(pgm_int_code, signal,
485 "user address fault", regs, &info);
486 } else
487#endif 467#endif
488 if (signal) { 468 if (signal)
489 info.si_signo = signal; 469 do_trap(regs, signal, ILL_ILLOPC, "illegal operation");
490 info.si_errno = 0;
491 info.si_code = ILL_ILLOPC;
492 info.si_addr = (void __user *) location;
493 do_trap(pgm_int_code, signal,
494 "illegal operation", regs, &info);
495 }
496} 470}
497 471
498 472
499#ifdef CONFIG_MATHEMU 473#ifdef CONFIG_MATHEMU
500void specification_exception(struct pt_regs *regs, long pgm_int_code, 474void specification_exception(struct pt_regs *regs)
501 unsigned long trans_exc_code)
502{ 475{
503 __u8 opcode[6]; 476 __u8 opcode[6];
504 __u16 __user *location = NULL; 477 __u16 __user *location = NULL;
505 int signal = 0; 478 int signal = 0;
506 479
507 location = (__u16 __user *) get_psw_address(regs, pgm_int_code); 480 location = (__u16 __user *) get_psw_address(regs);
508 481
509 if (regs->psw.mask & PSW_MASK_PSTATE) { 482 if (regs->psw.mask & PSW_MASK_PSTATE) {
510 get_user(*((__u16 *) opcode), location); 483 get_user(*((__u16 *) opcode), location);
@@ -539,30 +512,21 @@ void specification_exception(struct pt_regs *regs, long pgm_int_code,
539 signal = SIGILL; 512 signal = SIGILL;
540 513
541 if (signal == SIGFPE) 514 if (signal == SIGFPE)
542 do_fp_trap(regs, location, 515 do_fp_trap(regs, current->thread.fp_regs.fpc);
543 current->thread.fp_regs.fpc, pgm_int_code); 516 else if (signal)
544 else if (signal) { 517 do_trap(regs, signal, ILL_ILLOPN, "specification exception");
545 siginfo_t info;
546 info.si_signo = signal;
547 info.si_errno = 0;
548 info.si_code = ILL_ILLOPN;
549 info.si_addr = location;
550 do_trap(pgm_int_code, signal,
551 "specification exception", regs, &info);
552 }
553} 518}
554#else 519#else
555DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN, 520DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
556 "specification exception"); 521 "specification exception");
557#endif 522#endif
558 523
559static void data_exception(struct pt_regs *regs, long pgm_int_code, 524static void data_exception(struct pt_regs *regs)
560 unsigned long trans_exc_code)
561{ 525{
562 __u16 __user *location; 526 __u16 __user *location;
563 int signal = 0; 527 int signal = 0;
564 528
565 location = get_psw_address(regs, pgm_int_code); 529 location = get_psw_address(regs);
566 530
567 if (MACHINE_HAS_IEEE) 531 if (MACHINE_HAS_IEEE)
568 asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); 532 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,
627 else 591 else
628 signal = SIGILL; 592 signal = SIGILL;
629 if (signal == SIGFPE) 593 if (signal == SIGFPE)
630 do_fp_trap(regs, location, 594 do_fp_trap(regs, current->thread.fp_regs.fpc);
631 current->thread.fp_regs.fpc, pgm_int_code); 595 else if (signal)
632 else if (signal) { 596 do_trap(regs, signal, ILL_ILLOPN, "data exception");
633 siginfo_t info;
634 info.si_signo = signal;
635 info.si_errno = 0;
636 info.si_code = ILL_ILLOPN;
637 info.si_addr = location;
638 do_trap(pgm_int_code, signal, "data exception", regs, &info);
639 }
640} 597}
641 598
642static void space_switch_exception(struct pt_regs *regs, long pgm_int_code, 599static void space_switch_exception(struct pt_regs *regs)
643 unsigned long trans_exc_code)
644{ 600{
645 siginfo_t info;
646
647 /* Set user psw back to home space mode. */ 601 /* Set user psw back to home space mode. */
648 if (regs->psw.mask & PSW_MASK_PSTATE) 602 if (regs->psw.mask & PSW_MASK_PSTATE)
649 regs->psw.mask |= PSW_ASC_HOME; 603 regs->psw.mask |= PSW_ASC_HOME;
650 /* Send SIGILL. */ 604 /* Send SIGILL. */
651 info.si_signo = SIGILL; 605 do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");
652 info.si_errno = 0;
653 info.si_code = ILL_PRVOPC;
654 info.si_addr = get_psw_address(regs, pgm_int_code);
655 do_trap(pgm_int_code, SIGILL, "space switch event", regs, &info);
656} 606}
657 607
658void __kprobes kernel_stack_overflow(struct pt_regs * regs) 608void __kprobes kernel_stack_overflow(struct pt_regs * regs)