diff options
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/include/asm/kdebug.h | 2 | ||||
-rw-r--r-- | arch/s390/include/asm/processor.h | 2 | ||||
-rw-r--r-- | arch/s390/include/asm/ptrace.h | 3 | ||||
-rw-r--r-- | arch/s390/include/asm/syscall.h | 2 | ||||
-rw-r--r-- | arch/s390/kernel/asm-offsets.c | 3 | ||||
-rw-r--r-- | arch/s390/kernel/compat_signal.c | 8 | ||||
-rw-r--r-- | arch/s390/kernel/entry.S | 22 | ||||
-rw-r--r-- | arch/s390/kernel/entry.h | 10 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 27 | ||||
-rw-r--r-- | arch/s390/kernel/signal.c | 20 | ||||
-rw-r--r-- | arch/s390/kernel/traps.c | 168 | ||||
-rw-r--r-- | arch/s390/mm/fault.c | 101 |
12 files changed, 158 insertions, 210 deletions
diff --git a/arch/s390/include/asm/kdebug.h b/arch/s390/include/asm/kdebug.h index 40db27cd6e60..5c1abd47612a 100644 --- a/arch/s390/include/asm/kdebug.h +++ b/arch/s390/include/asm/kdebug.h | |||
@@ -22,6 +22,6 @@ enum die_val { | |||
22 | DIE_NMI_IPI, | 22 | DIE_NMI_IPI, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | extern void die(const char *, struct pt_regs *, long); | 25 | extern void die(struct pt_regs *, const char *); |
26 | 26 | ||
27 | #endif | 27 | #endif |
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 5f33d37d032c..27272f6a14c2 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h | |||
@@ -80,8 +80,6 @@ struct thread_struct { | |||
80 | unsigned int acrs[NUM_ACRS]; | 80 | unsigned int acrs[NUM_ACRS]; |
81 | unsigned long ksp; /* kernel stack pointer */ | 81 | unsigned long ksp; /* kernel stack pointer */ |
82 | mm_segment_t mm_segment; | 82 | mm_segment_t mm_segment; |
83 | unsigned long prot_addr; /* address of protection-excep. */ | ||
84 | unsigned int trap_no; | ||
85 | unsigned long gmap_addr; /* address of last gmap fault. */ | 83 | unsigned long gmap_addr; /* address of last gmap fault. */ |
86 | struct per_regs per_user; /* User specified PER registers */ | 84 | struct per_regs per_user; /* User specified PER registers */ |
87 | struct per_event per_event; /* Cause of the last PER trap */ | 85 | struct per_event per_event; /* Cause of the last PER trap */ |
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index a65846340d51..56da355678f4 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h | |||
@@ -324,7 +324,8 @@ struct pt_regs | |||
324 | psw_t psw; | 324 | psw_t psw; |
325 | unsigned long gprs[NUM_GPRS]; | 325 | unsigned long gprs[NUM_GPRS]; |
326 | unsigned long orig_gpr2; | 326 | unsigned long orig_gpr2; |
327 | unsigned int svc_code; | 327 | unsigned int int_code; |
328 | unsigned long int_parm_long; | ||
328 | }; | 329 | }; |
329 | 330 | ||
330 | /* | 331 | /* |
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h index b239ff53b189..fb214dd9b7e0 100644 --- a/arch/s390/include/asm/syscall.h +++ b/arch/s390/include/asm/syscall.h | |||
@@ -27,7 +27,7 @@ static inline long syscall_get_nr(struct task_struct *task, | |||
27 | struct pt_regs *regs) | 27 | struct pt_regs *regs) |
28 | { | 28 | { |
29 | return test_tsk_thread_flag(task, TIF_SYSCALL) ? | 29 | return test_tsk_thread_flag(task, TIF_SYSCALL) ? |
30 | (regs->svc_code & 0xffff) : -1; | 30 | (regs->int_code & 0xffff) : -1; |
31 | } | 31 | } |
32 | 32 | ||
33 | static inline void syscall_rollback(struct task_struct *task, | 33 | static inline void syscall_rollback(struct task_struct *task, |
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 |
188 | sysc_do_svc: | 188 | sysc_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 |
199 | sysc_nr_ok: | 199 | sysc_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 |
408 | 0: l %r3,__LC_PGM_ILC # load program interruption code | 410 | 0: 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 | ||
9 | extern void (*pgm_check_table[128])(struct pt_regs *, long, unsigned long); | 9 | extern void (*pgm_check_table[128])(struct pt_regs *); |
10 | extern void *restart_stack; | 10 | extern void *restart_stack; |
11 | 11 | ||
12 | asmlinkage long do_syscall_trace_enter(struct pt_regs *regs); | 12 | asmlinkage long do_syscall_trace_enter(struct pt_regs *regs); |
13 | asmlinkage void do_syscall_trace_exit(struct pt_regs *regs); | 13 | asmlinkage void do_syscall_trace_exit(struct pt_regs *regs); |
14 | 14 | ||
15 | void do_protection_exception(struct pt_regs *, long, unsigned long); | 15 | void do_protection_exception(struct pt_regs *regs); |
16 | void do_dat_exception(struct pt_regs *, long, unsigned long); | 16 | void do_dat_exception(struct pt_regs *regs); |
17 | void do_asce_exception(struct pt_regs *, long, unsigned long); | 17 | void do_asce_exception(struct pt_regs *regs); |
18 | 18 | ||
19 | void do_per_trap(struct pt_regs *regs); | 19 | void do_per_trap(struct pt_regs *regs); |
20 | void syscall_trace(struct pt_regs *regs, int entryexit); | 20 | 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 | void do_restart(void); | 28 | void do_restart(void); |
29 | int __cpuinit start_secondary(void *cpuvoid); | 29 | int __cpuinit start_secondary(void *cpuvoid); |
30 | void __init startup_init(void); | 30 | void __init startup_init(void); |
31 | void die(const char * str, struct pt_regs * regs, long err); | 31 | void die(struct pt_regs *regs, const char *str); |
32 | 32 | ||
33 | void __init time_init(void); | 33 | void __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 |
204 | sysc_do_svc: | 203 | sysc_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 |
215 | sysc_nr_ok: | 214 | sysc_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: | |||
318 | sysc_tracesys: | 317 | sysc_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 |
424 | 0: lgf %r3,__LC_PGM_ILC # load program interruption code | 425 | 0: 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 | ||
46 | void (*pgm_check_table[128])(struct pt_regs *, long, unsigned long); | 46 | void (*pgm_check_table[128])(struct pt_regs *regs); |
47 | 47 | ||
48 | int show_unhandled_signals; | 48 | int show_unhandled_signals; |
49 | 49 | ||
@@ -234,7 +234,7 @@ void show_regs(struct pt_regs *regs) | |||
234 | 234 | ||
235 | static DEFINE_SPINLOCK(die_lock); | 235 | static DEFINE_SPINLOCK(die_lock); |
236 | 236 | ||
237 | void die(const char * str, struct pt_regs * regs, long err) | 237 | void 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 | ||
270 | static void inline report_user_fault(struct pt_regs *regs, long int_code, | 270 | static 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 | ||
290 | static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str, | 289 | static 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 | |||
295 | static 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 | ||
319 | static 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 | |||
326 | void __kprobes do_per_trap(struct pt_regs *regs) | 327 | void __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 | ||
342 | static void default_trap_handler(struct pt_regs *regs, long pgm_int_code, | 343 | static 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) \ |
353 | static void name(struct pt_regs *regs, long pgm_int_code, \ | 353 | static 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 | ||
364 | DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR, | 358 | DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR, |
@@ -388,42 +382,34 @@ DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN, | |||
388 | DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, | 382 | DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, |
389 | "translation exception") | 383 | "translation exception") |
390 | 384 | ||
391 | static inline void do_fp_trap(struct pt_regs *regs, void __user *location, | 385 | static 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 | ||
418 | static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_code, | 405 | static 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 |
500 | void specification_exception(struct pt_regs *regs, long pgm_int_code, | 474 | void 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 |
555 | DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN, | 520 | DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN, |
556 | "specification exception"); | 521 | "specification exception"); |
557 | #endif | 522 | #endif |
558 | 523 | ||
559 | static void data_exception(struct pt_regs *regs, long pgm_int_code, | 524 | static 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 | ||
642 | static void space_switch_exception(struct pt_regs *regs, long pgm_int_code, | 599 | static 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 | ||
658 | void __kprobes kernel_stack_overflow(struct pt_regs * regs) | 608 | void __kprobes kernel_stack_overflow(struct pt_regs * regs) |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index a9d3583922ec..354dd39073ef 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
@@ -125,8 +125,7 @@ static inline int user_space_fault(unsigned long trans_exc_code) | |||
125 | return trans_exc_code != 3; | 125 | return trans_exc_code != 3; |
126 | } | 126 | } |
127 | 127 | ||
128 | static inline void report_user_fault(struct pt_regs *regs, long int_code, | 128 | static inline void report_user_fault(struct pt_regs *regs, long signr) |
129 | int signr, unsigned long address) | ||
130 | { | 129 | { |
131 | if ((task_pid_nr(current) > 1) && !show_unhandled_signals) | 130 | if ((task_pid_nr(current) > 1) && !show_unhandled_signals) |
132 | return; | 131 | return; |
@@ -134,10 +133,12 @@ static inline void report_user_fault(struct pt_regs *regs, long int_code, | |||
134 | return; | 133 | return; |
135 | if (!printk_ratelimit()) | 134 | if (!printk_ratelimit()) |
136 | return; | 135 | return; |
137 | printk("User process fault: interruption code 0x%lX ", int_code); | 136 | printk(KERN_ALERT "User process fault: interruption code 0x%X ", |
137 | regs->int_code); | ||
138 | print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN); | 138 | print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN); |
139 | printk("\n"); | 139 | printk(KERN_CONT "\n"); |
140 | printk("failing address: %lX\n", address); | 140 | printk(KERN_ALERT "failing address: %lX\n", |
141 | regs->int_parm_long & __FAIL_ADDR_MASK); | ||
141 | show_regs(regs); | 142 | show_regs(regs); |
142 | } | 143 | } |
143 | 144 | ||
@@ -145,24 +146,18 @@ static inline void report_user_fault(struct pt_regs *regs, long int_code, | |||
145 | * Send SIGSEGV to task. This is an external routine | 146 | * Send SIGSEGV to task. This is an external routine |
146 | * to keep the stack usage of do_page_fault small. | 147 | * to keep the stack usage of do_page_fault small. |
147 | */ | 148 | */ |
148 | static noinline void do_sigsegv(struct pt_regs *regs, long int_code, | 149 | static noinline void do_sigsegv(struct pt_regs *regs, int si_code) |
149 | int si_code, unsigned long trans_exc_code) | ||
150 | { | 150 | { |
151 | struct siginfo si; | 151 | struct siginfo si; |
152 | unsigned long address; | ||
153 | 152 | ||
154 | address = trans_exc_code & __FAIL_ADDR_MASK; | 153 | report_user_fault(regs, SIGSEGV); |
155 | current->thread.prot_addr = address; | ||
156 | current->thread.trap_no = int_code; | ||
157 | report_user_fault(regs, int_code, SIGSEGV, address); | ||
158 | si.si_signo = SIGSEGV; | 154 | si.si_signo = SIGSEGV; |
159 | si.si_code = si_code; | 155 | si.si_code = si_code; |
160 | si.si_addr = (void __user *) address; | 156 | si.si_addr = (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK); |
161 | force_sig_info(SIGSEGV, &si, current); | 157 | force_sig_info(SIGSEGV, &si, current); |
162 | } | 158 | } |
163 | 159 | ||
164 | static noinline void do_no_context(struct pt_regs *regs, long int_code, | 160 | static noinline void do_no_context(struct pt_regs *regs) |
165 | unsigned long trans_exc_code) | ||
166 | { | 161 | { |
167 | const struct exception_table_entry *fixup; | 162 | const struct exception_table_entry *fixup; |
168 | unsigned long address; | 163 | unsigned long address; |
@@ -178,55 +173,48 @@ static noinline void do_no_context(struct pt_regs *regs, long int_code, | |||
178 | * Oops. The kernel tried to access some bad page. We'll have to | 173 | * Oops. The kernel tried to access some bad page. We'll have to |
179 | * terminate things with extreme prejudice. | 174 | * terminate things with extreme prejudice. |
180 | */ | 175 | */ |
181 | address = trans_exc_code & __FAIL_ADDR_MASK; | 176 | address = regs->int_parm_long & __FAIL_ADDR_MASK; |
182 | if (!user_space_fault(trans_exc_code)) | 177 | if (!user_space_fault(regs->int_parm_long)) |
183 | printk(KERN_ALERT "Unable to handle kernel pointer dereference" | 178 | printk(KERN_ALERT "Unable to handle kernel pointer dereference" |
184 | " at virtual kernel address %p\n", (void *)address); | 179 | " at virtual kernel address %p\n", (void *)address); |
185 | else | 180 | else |
186 | printk(KERN_ALERT "Unable to handle kernel paging request" | 181 | printk(KERN_ALERT "Unable to handle kernel paging request" |
187 | " at virtual user address %p\n", (void *)address); | 182 | " at virtual user address %p\n", (void *)address); |
188 | 183 | ||
189 | die("Oops", regs, int_code); | 184 | die(regs, "Oops"); |
190 | do_exit(SIGKILL); | 185 | do_exit(SIGKILL); |
191 | } | 186 | } |
192 | 187 | ||
193 | static noinline void do_low_address(struct pt_regs *regs, long int_code, | 188 | static noinline void do_low_address(struct pt_regs *regs) |
194 | unsigned long trans_exc_code) | ||
195 | { | 189 | { |
196 | /* Low-address protection hit in kernel mode means | 190 | /* Low-address protection hit in kernel mode means |
197 | NULL pointer write access in kernel mode. */ | 191 | NULL pointer write access in kernel mode. */ |
198 | if (regs->psw.mask & PSW_MASK_PSTATE) { | 192 | if (regs->psw.mask & PSW_MASK_PSTATE) { |
199 | /* Low-address protection hit in user mode 'cannot happen'. */ | 193 | /* Low-address protection hit in user mode 'cannot happen'. */ |
200 | die ("Low-address protection", regs, int_code); | 194 | die (regs, "Low-address protection"); |
201 | do_exit(SIGKILL); | 195 | do_exit(SIGKILL); |
202 | } | 196 | } |
203 | 197 | ||
204 | do_no_context(regs, int_code, trans_exc_code); | 198 | do_no_context(regs); |
205 | } | 199 | } |
206 | 200 | ||
207 | static noinline void do_sigbus(struct pt_regs *regs, long int_code, | 201 | static noinline void do_sigbus(struct pt_regs *regs) |
208 | unsigned long trans_exc_code) | ||
209 | { | 202 | { |
210 | struct task_struct *tsk = current; | 203 | struct task_struct *tsk = current; |
211 | unsigned long address; | ||
212 | struct siginfo si; | 204 | struct siginfo si; |
213 | 205 | ||
214 | /* | 206 | /* |
215 | * Send a sigbus, regardless of whether we were in kernel | 207 | * Send a sigbus, regardless of whether we were in kernel |
216 | * or user mode. | 208 | * or user mode. |
217 | */ | 209 | */ |
218 | address = trans_exc_code & __FAIL_ADDR_MASK; | ||
219 | tsk->thread.prot_addr = address; | ||
220 | tsk->thread.trap_no = int_code; | ||
221 | si.si_signo = SIGBUS; | 210 | si.si_signo = SIGBUS; |
222 | si.si_errno = 0; | 211 | si.si_errno = 0; |
223 | si.si_code = BUS_ADRERR; | 212 | si.si_code = BUS_ADRERR; |
224 | si.si_addr = (void __user *) address; | 213 | si.si_addr = (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK); |
225 | force_sig_info(SIGBUS, &si, tsk); | 214 | force_sig_info(SIGBUS, &si, tsk); |
226 | } | 215 | } |
227 | 216 | ||
228 | static noinline void do_fault_error(struct pt_regs *regs, long int_code, | 217 | static noinline void do_fault_error(struct pt_regs *regs, int fault) |
229 | unsigned long trans_exc_code, int fault) | ||
230 | { | 218 | { |
231 | int si_code; | 219 | int si_code; |
232 | 220 | ||
@@ -238,24 +226,24 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code, | |||
238 | /* User mode accesses just cause a SIGSEGV */ | 226 | /* User mode accesses just cause a SIGSEGV */ |
239 | si_code = (fault == VM_FAULT_BADMAP) ? | 227 | si_code = (fault == VM_FAULT_BADMAP) ? |
240 | SEGV_MAPERR : SEGV_ACCERR; | 228 | SEGV_MAPERR : SEGV_ACCERR; |
241 | do_sigsegv(regs, int_code, si_code, trans_exc_code); | 229 | do_sigsegv(regs, si_code); |
242 | return; | 230 | return; |
243 | } | 231 | } |
244 | case VM_FAULT_BADCONTEXT: | 232 | case VM_FAULT_BADCONTEXT: |
245 | do_no_context(regs, int_code, trans_exc_code); | 233 | do_no_context(regs); |
246 | break; | 234 | break; |
247 | default: /* fault & VM_FAULT_ERROR */ | 235 | default: /* fault & VM_FAULT_ERROR */ |
248 | if (fault & VM_FAULT_OOM) { | 236 | if (fault & VM_FAULT_OOM) { |
249 | if (!(regs->psw.mask & PSW_MASK_PSTATE)) | 237 | if (!(regs->psw.mask & PSW_MASK_PSTATE)) |
250 | do_no_context(regs, int_code, trans_exc_code); | 238 | do_no_context(regs); |
251 | else | 239 | else |
252 | pagefault_out_of_memory(); | 240 | pagefault_out_of_memory(); |
253 | } else if (fault & VM_FAULT_SIGBUS) { | 241 | } else if (fault & VM_FAULT_SIGBUS) { |
254 | /* Kernel mode? Handle exceptions or die */ | 242 | /* Kernel mode? Handle exceptions or die */ |
255 | if (!(regs->psw.mask & PSW_MASK_PSTATE)) | 243 | if (!(regs->psw.mask & PSW_MASK_PSTATE)) |
256 | do_no_context(regs, int_code, trans_exc_code); | 244 | do_no_context(regs); |
257 | else | 245 | else |
258 | do_sigbus(regs, int_code, trans_exc_code); | 246 | do_sigbus(regs); |
259 | } else | 247 | } else |
260 | BUG(); | 248 | BUG(); |
261 | break; | 249 | break; |
@@ -273,12 +261,12 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code, | |||
273 | * 11 Page translation -> Not present (nullification) | 261 | * 11 Page translation -> Not present (nullification) |
274 | * 3b Region third trans. -> Not present (nullification) | 262 | * 3b Region third trans. -> Not present (nullification) |
275 | */ | 263 | */ |
276 | static inline int do_exception(struct pt_regs *regs, int access, | 264 | static inline int do_exception(struct pt_regs *regs, int access) |
277 | unsigned long trans_exc_code) | ||
278 | { | 265 | { |
279 | struct task_struct *tsk; | 266 | struct task_struct *tsk; |
280 | struct mm_struct *mm; | 267 | struct mm_struct *mm; |
281 | struct vm_area_struct *vma; | 268 | struct vm_area_struct *vma; |
269 | unsigned long trans_exc_code; | ||
282 | unsigned long address; | 270 | unsigned long address; |
283 | unsigned int flags; | 271 | unsigned int flags; |
284 | int fault; | 272 | int fault; |
@@ -288,6 +276,7 @@ static inline int do_exception(struct pt_regs *regs, int access, | |||
288 | 276 | ||
289 | tsk = current; | 277 | tsk = current; |
290 | mm = tsk->mm; | 278 | mm = tsk->mm; |
279 | trans_exc_code = regs->int_parm_long; | ||
291 | 280 | ||
292 | /* | 281 | /* |
293 | * Verify that the fault happened in user space, that | 282 | * Verify that the fault happened in user space, that |
@@ -387,45 +376,46 @@ out: | |||
387 | return fault; | 376 | return fault; |
388 | } | 377 | } |
389 | 378 | ||
390 | void __kprobes do_protection_exception(struct pt_regs *regs, long pgm_int_code, | 379 | void __kprobes do_protection_exception(struct pt_regs *regs) |
391 | unsigned long trans_exc_code) | ||
392 | { | 380 | { |
381 | unsigned long trans_exc_code; | ||
393 | int fault; | 382 | int fault; |
394 | 383 | ||
384 | trans_exc_code = regs->int_parm_long; | ||
395 | /* Protection exception is suppressing, decrement psw address. */ | 385 | /* Protection exception is suppressing, decrement psw address. */ |
396 | regs->psw.addr = __rewind_psw(regs->psw, pgm_int_code >> 16); | 386 | regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16); |
397 | /* | 387 | /* |
398 | * Check for low-address protection. This needs to be treated | 388 | * Check for low-address protection. This needs to be treated |
399 | * as a special case because the translation exception code | 389 | * as a special case because the translation exception code |
400 | * field is not guaranteed to contain valid data in this case. | 390 | * field is not guaranteed to contain valid data in this case. |
401 | */ | 391 | */ |
402 | if (unlikely(!(trans_exc_code & 4))) { | 392 | if (unlikely(!(trans_exc_code & 4))) { |
403 | do_low_address(regs, pgm_int_code, trans_exc_code); | 393 | do_low_address(regs); |
404 | return; | 394 | return; |
405 | } | 395 | } |
406 | fault = do_exception(regs, VM_WRITE, trans_exc_code); | 396 | fault = do_exception(regs, VM_WRITE); |
407 | if (unlikely(fault)) | 397 | if (unlikely(fault)) |
408 | do_fault_error(regs, 4, trans_exc_code, fault); | 398 | do_fault_error(regs, fault); |
409 | } | 399 | } |
410 | 400 | ||
411 | void __kprobes do_dat_exception(struct pt_regs *regs, long pgm_int_code, | 401 | void __kprobes do_dat_exception(struct pt_regs *regs) |
412 | unsigned long trans_exc_code) | ||
413 | { | 402 | { |
414 | int access, fault; | 403 | int access, fault; |
415 | 404 | ||
416 | access = VM_READ | VM_EXEC | VM_WRITE; | 405 | access = VM_READ | VM_EXEC | VM_WRITE; |
417 | fault = do_exception(regs, access, trans_exc_code); | 406 | fault = do_exception(regs, access); |
418 | if (unlikely(fault)) | 407 | if (unlikely(fault)) |
419 | do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault); | 408 | do_fault_error(regs, fault); |
420 | } | 409 | } |
421 | 410 | ||
422 | #ifdef CONFIG_64BIT | 411 | #ifdef CONFIG_64BIT |
423 | void __kprobes do_asce_exception(struct pt_regs *regs, long pgm_int_code, | 412 | void __kprobes do_asce_exception(struct pt_regs *regs) |
424 | unsigned long trans_exc_code) | ||
425 | { | 413 | { |
426 | struct mm_struct *mm = current->mm; | 414 | struct mm_struct *mm = current->mm; |
427 | struct vm_area_struct *vma; | 415 | struct vm_area_struct *vma; |
416 | unsigned long trans_exc_code; | ||
428 | 417 | ||
418 | trans_exc_code = regs->int_parm_long; | ||
429 | if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm)) | 419 | if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm)) |
430 | goto no_context; | 420 | goto no_context; |
431 | 421 | ||
@@ -440,12 +430,12 @@ void __kprobes do_asce_exception(struct pt_regs *regs, long pgm_int_code, | |||
440 | 430 | ||
441 | /* User mode accesses just cause a SIGSEGV */ | 431 | /* User mode accesses just cause a SIGSEGV */ |
442 | if (regs->psw.mask & PSW_MASK_PSTATE) { | 432 | if (regs->psw.mask & PSW_MASK_PSTATE) { |
443 | do_sigsegv(regs, pgm_int_code, SEGV_MAPERR, trans_exc_code); | 433 | do_sigsegv(regs, SEGV_MAPERR); |
444 | return; | 434 | return; |
445 | } | 435 | } |
446 | 436 | ||
447 | no_context: | 437 | no_context: |
448 | do_no_context(regs, pgm_int_code, trans_exc_code); | 438 | do_no_context(regs); |
449 | } | 439 | } |
450 | #endif | 440 | #endif |
451 | 441 | ||
@@ -459,14 +449,15 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write) | |||
459 | regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT; | 449 | regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT; |
460 | regs.psw.addr = (unsigned long) __builtin_return_address(0); | 450 | regs.psw.addr = (unsigned long) __builtin_return_address(0); |
461 | regs.psw.addr |= PSW_ADDR_AMODE; | 451 | regs.psw.addr |= PSW_ADDR_AMODE; |
462 | uaddr &= PAGE_MASK; | 452 | regs.int_code = pgm_int_code; |
453 | regs.int_parm_long = (uaddr & PAGE_MASK) | 2; | ||
463 | access = write ? VM_WRITE : VM_READ; | 454 | access = write ? VM_WRITE : VM_READ; |
464 | fault = do_exception(®s, access, uaddr | 2); | 455 | fault = do_exception(®s, access); |
465 | if (unlikely(fault)) { | 456 | if (unlikely(fault)) { |
466 | if (fault & VM_FAULT_OOM) | 457 | if (fault & VM_FAULT_OOM) |
467 | return -EFAULT; | 458 | return -EFAULT; |
468 | else if (fault & VM_FAULT_SIGBUS) | 459 | else if (fault & VM_FAULT_SIGBUS) |
469 | do_sigbus(®s, pgm_int_code, uaddr); | 460 | do_sigbus(®s); |
470 | } | 461 | } |
471 | return fault ? -EFAULT : 0; | 462 | return fault ? -EFAULT : 0; |
472 | } | 463 | } |