aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2010-10-25 10:10:37 -0400
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2010-10-25 10:10:19 -0400
commit1e54622e0403891b10f2105663e0f9dd595a1f17 (patch)
tree4d16341d7a3d0f3c46fcc275560a9206bccac07f /arch/s390/kernel
parent84afdcee620b1640f2a145c07febae4ed68947f9 (diff)
[S390] cleanup lowcore access from program checks
Read all required fields for program checks from the lowcore in the first level interrupt handler in entry[64].S. If the context that caused the fault was enabled for interrupts we can now re-enable the irqs in entry[64].S. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r--arch/s390/kernel/asm-offsets.c1
-rw-r--r--arch/s390/kernel/entry.S35
-rw-r--r--arch/s390/kernel/entry.h2
-rw-r--r--arch/s390/kernel/entry64.S36
-rw-r--r--arch/s390/kernel/traps.c172
5 files changed, 96 insertions, 150 deletions
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 5232278d79ad..76328deb31f7 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -84,6 +84,7 @@ int main(void)
84 DEFINE(__LC_SVC_INT_CODE, offsetof(struct _lowcore, svc_code)); 84 DEFINE(__LC_SVC_INT_CODE, offsetof(struct _lowcore, svc_code));
85 DEFINE(__LC_PGM_ILC, offsetof(struct _lowcore, pgm_ilc)); 85 DEFINE(__LC_PGM_ILC, offsetof(struct _lowcore, pgm_ilc));
86 DEFINE(__LC_PGM_INT_CODE, offsetof(struct _lowcore, pgm_code)); 86 DEFINE(__LC_PGM_INT_CODE, offsetof(struct _lowcore, pgm_code));
87 DEFINE(__LC_TRANS_EXC_CODE, offsetof(struct _lowcore, trans_exc_code));
87 DEFINE(__LC_PER_ATMID, offsetof(struct _lowcore, per_perc_atmid)); 88 DEFINE(__LC_PER_ATMID, offsetof(struct _lowcore, per_perc_atmid));
88 DEFINE(__LC_PER_ADDRESS, offsetof(struct _lowcore, per_address)); 89 DEFINE(__LC_PER_ADDRESS, offsetof(struct _lowcore, per_address));
89 DEFINE(__LC_PER_ACCESS_ID, offsetof(struct _lowcore, per_access_id)); 90 DEFINE(__LC_PER_ACCESS_ID, offsetof(struct _lowcore, per_access_id));
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index bea9ee37ac9d..adf25246f72e 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -72,25 +72,9 @@ STACK_SIZE = 1 << STACK_SHIFT
72 l %r1,BASED(.Ltrace_irq_off_caller) 72 l %r1,BASED(.Ltrace_irq_off_caller)
73 basr %r14,%r1 73 basr %r14,%r1
74 .endm 74 .endm
75
76 .macro TRACE_IRQS_CHECK_ON
77 tm SP_PSW(%r15),0x03 # irqs enabled?
78 bz BASED(0f)
79 TRACE_IRQS_ON
800:
81 .endm
82
83 .macro TRACE_IRQS_CHECK_OFF
84 tm SP_PSW(%r15),0x03 # irqs enabled?
85 bz BASED(0f)
86 TRACE_IRQS_OFF
870:
88 .endm
89#else 75#else
90#define TRACE_IRQS_ON 76#define TRACE_IRQS_ON
91#define TRACE_IRQS_OFF 77#define TRACE_IRQS_OFF
92#define TRACE_IRQS_CHECK_ON
93#define TRACE_IRQS_CHECK_OFF
94#endif 78#endif
95 79
96#ifdef CONFIG_LOCKDEP 80#ifdef CONFIG_LOCKDEP
@@ -198,6 +182,12 @@ STACK_SIZE = 1 << STACK_SHIFT
198 lpsw \psworg # back to caller 182 lpsw \psworg # back to caller
199 .endm 183 .endm
200 184
185 .macro REENABLE_IRQS
186 mvc __SF_EMPTY(1,%r15),SP_PSW(%r15)
187 ni __SF_EMPTY(%r15),0xbf
188 ssm __SF_EMPTY(%r15)
189 .endm
190
201/* 191/*
202 * Scheduler resume function, called by switch_to 192 * Scheduler resume function, called by switch_to
203 * gpr2 = (task_struct *) prev 193 * gpr2 = (task_struct *) prev
@@ -440,13 +430,11 @@ kernel_execve:
440 br %r14 430 br %r14
441 # execve succeeded. 431 # execve succeeded.
4420: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts 4320: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts
443 TRACE_IRQS_OFF
444 l %r15,__LC_KERNEL_STACK # load ksp 433 l %r15,__LC_KERNEL_STACK # load ksp
445 s %r15,BASED(.Lc_spsize) # make room for registers & psw 434 s %r15,BASED(.Lc_spsize) # make room for registers & psw
446 l %r9,__LC_THREAD_INFO 435 l %r9,__LC_THREAD_INFO
447 mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs 436 mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs
448 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) 437 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
449 TRACE_IRQS_ON
450 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts 438 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
451 l %r1,BASED(.Lexecve_tail) 439 l %r1,BASED(.Lexecve_tail)
452 basr %r14,%r1 440 basr %r14,%r1
@@ -483,9 +471,10 @@ pgm_check_handler:
483 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER 471 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
484 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER 472 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
485pgm_no_vtime: 473pgm_no_vtime:
486 TRACE_IRQS_CHECK_OFF
487 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct 474 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
488 l %r3,__LC_PGM_ILC # load program interruption code 475 l %r3,__LC_PGM_ILC # load program interruption code
476 l %r4,__LC_TRANS_EXC_CODE
477 REENABLE_IRQS
489 la %r8,0x7f 478 la %r8,0x7f
490 nr %r8,%r3 479 nr %r8,%r3
491pgm_do_call: 480pgm_do_call:
@@ -495,7 +484,6 @@ pgm_do_call:
495 la %r2,SP_PTREGS(%r15) # address of register-save area 484 la %r2,SP_PTREGS(%r15) # address of register-save area
496 basr %r14,%r7 # branch to interrupt-handler 485 basr %r14,%r7 # branch to interrupt-handler
497pgm_exit: 486pgm_exit:
498 TRACE_IRQS_CHECK_ON
499 b BASED(sysc_return) 487 b BASED(sysc_return)
500 488
501# 489#
@@ -523,7 +511,6 @@ pgm_per_std:
523 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER 511 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
524 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER 512 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
525pgm_no_vtime2: 513pgm_no_vtime2:
526 TRACE_IRQS_CHECK_OFF
527 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct 514 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
528 l %r1,__TI_task(%r9) 515 l %r1,__TI_task(%r9)
529 tm SP_PSW+1(%r15),0x01 # kernel per event ? 516 tm SP_PSW+1(%r15),0x01 # kernel per event ?
@@ -533,6 +520,8 @@ pgm_no_vtime2:
533 mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID 520 mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
534 oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP 521 oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
535 l %r3,__LC_PGM_ILC # load program interruption code 522 l %r3,__LC_PGM_ILC # load program interruption code
523 l %r4,__LC_TRANS_EXC_CODE
524 REENABLE_IRQS
536 la %r8,0x7f 525 la %r8,0x7f
537 nr %r8,%r3 # clear per-event-bit and ilc 526 nr %r8,%r3 # clear per-event-bit and ilc
538 be BASED(pgm_exit2) # only per or per+check ? 527 be BASED(pgm_exit2) # only per or per+check ?
@@ -542,8 +531,6 @@ pgm_no_vtime2:
542 la %r2,SP_PTREGS(%r15) # address of register-save area 531 la %r2,SP_PTREGS(%r15) # address of register-save area
543 basr %r14,%r7 # branch to interrupt-handler 532 basr %r14,%r7 # branch to interrupt-handler
544pgm_exit2: 533pgm_exit2:
545 TRACE_IRQS_ON
546 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
547 b BASED(sysc_return) 534 b BASED(sysc_return)
548 535
549# 536#
@@ -557,13 +544,11 @@ pgm_svcper:
557 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER 544 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
558 lh %r7,0x8a # get svc number from lowcore 545 lh %r7,0x8a # get svc number from lowcore
559 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct 546 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
560 TRACE_IRQS_OFF
561 l %r8,__TI_task(%r9) 547 l %r8,__TI_task(%r9)
562 mvc __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID 548 mvc __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
563 mvc __THREAD_per+__PER_address(4,%r8),__LC_PER_ADDRESS 549 mvc __THREAD_per+__PER_address(4,%r8),__LC_PER_ADDRESS
564 mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID 550 mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
565 oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP 551 oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
566 TRACE_IRQS_ON
567 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts 552 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
568 lm %r2,%r6,SP_R2(%r15) # load svc arguments 553 lm %r2,%r6,SP_R2(%r15) # load svc arguments
569 b BASED(sysc_do_svc) 554 b BASED(sysc_do_svc)
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index ff579b6bde06..714ff2e57c6b 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -5,7 +5,7 @@
5#include <linux/signal.h> 5#include <linux/signal.h>
6#include <asm/ptrace.h> 6#include <asm/ptrace.h>
7 7
8typedef void pgm_check_handler_t(struct pt_regs *, long); 8typedef void pgm_check_handler_t(struct pt_regs *, long, unsigned long);
9extern pgm_check_handler_t *pgm_check_table[128]; 9extern pgm_check_handler_t *pgm_check_table[128];
10pgm_check_handler_t do_protection_exception; 10pgm_check_handler_t do_protection_exception;
11pgm_check_handler_t do_dat_exception; 11pgm_check_handler_t do_dat_exception;
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 8bccec15ea90..2d205e4e7bb6 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -79,25 +79,9 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
79 basr %r2,%r0 79 basr %r2,%r0
80 brasl %r14,trace_hardirqs_off_caller 80 brasl %r14,trace_hardirqs_off_caller
81 .endm 81 .endm
82
83 .macro TRACE_IRQS_CHECK_ON
84 tm SP_PSW(%r15),0x03 # irqs enabled?
85 jz 0f
86 TRACE_IRQS_ON
870:
88 .endm
89
90 .macro TRACE_IRQS_CHECK_OFF
91 tm SP_PSW(%r15),0x03 # irqs enabled?
92 jz 0f
93 TRACE_IRQS_OFF
940:
95 .endm
96#else 82#else
97#define TRACE_IRQS_ON 83#define TRACE_IRQS_ON
98#define TRACE_IRQS_OFF 84#define TRACE_IRQS_OFF
99#define TRACE_IRQS_CHECK_ON
100#define TRACE_IRQS_CHECK_OFF
101#endif 85#endif
102 86
103#ifdef CONFIG_LOCKDEP 87#ifdef CONFIG_LOCKDEP
@@ -207,6 +191,12 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
2070: 1910:
208 .endm 192 .endm
209 193
194 .macro REENABLE_IRQS
195 mvc __SF_EMPTY(1,%r15),SP_PSW(%r15)
196 ni __SF_EMPTY(%r15),0xbf
197 ssm __SF_EMPTY(%r15)
198 .endm
199
210/* 200/*
211 * Scheduler resume function, called by switch_to 201 * Scheduler resume function, called by switch_to
212 * gpr2 = (task_struct *) prev 202 * gpr2 = (task_struct *) prev
@@ -443,14 +433,12 @@ kernel_execve:
443 br %r14 433 br %r14
444 # execve succeeded. 434 # execve succeeded.
4450: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts 4350: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts
446# TRACE_IRQS_OFF
447 lg %r15,__LC_KERNEL_STACK # load ksp 436 lg %r15,__LC_KERNEL_STACK # load ksp
448 aghi %r15,-SP_SIZE # make room for registers & psw 437 aghi %r15,-SP_SIZE # make room for registers & psw
449 lg %r13,__LC_SVC_NEW_PSW+8 438 lg %r13,__LC_SVC_NEW_PSW+8
450 mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs 439 mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs
451 lg %r12,__LC_THREAD_INFO 440 lg %r12,__LC_THREAD_INFO
452 xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) 441 xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
453# TRACE_IRQS_ON
454 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts 442 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
455 brasl %r14,execve_tail 443 brasl %r14,execve_tail
456 j sysc_return 444 j sysc_return
@@ -490,19 +478,18 @@ pgm_check_handler:
490 LAST_BREAK 478 LAST_BREAK
491pgm_no_vtime: 479pgm_no_vtime:
492 HANDLE_SIE_INTERCEPT 480 HANDLE_SIE_INTERCEPT
493 TRACE_IRQS_CHECK_OFF
494 stg %r11,SP_ARGS(%r15) 481 stg %r11,SP_ARGS(%r15)
495 lgf %r3,__LC_PGM_ILC # load program interruption code 482 lgf %r3,__LC_PGM_ILC # load program interruption code
483 lg %r4,__LC_TRANS_EXC_CODE
484 REENABLE_IRQS
496 lghi %r8,0x7f 485 lghi %r8,0x7f
497 ngr %r8,%r3 486 ngr %r8,%r3
498pgm_do_call:
499 sll %r8,3 487 sll %r8,3
500 larl %r1,pgm_check_table 488 larl %r1,pgm_check_table
501 lg %r1,0(%r8,%r1) # load address of handler routine 489 lg %r1,0(%r8,%r1) # load address of handler routine
502 la %r2,SP_PTREGS(%r15) # address of register-save area 490 la %r2,SP_PTREGS(%r15) # address of register-save area
503 basr %r14,%r1 # branch to interrupt-handler 491 basr %r14,%r1 # branch to interrupt-handler
504pgm_exit: 492pgm_exit:
505 TRACE_IRQS_CHECK_ON
506 j sysc_return 493 j sysc_return
507 494
508# 495#
@@ -533,7 +520,6 @@ pgm_per_std:
533 LAST_BREAK 520 LAST_BREAK
534pgm_no_vtime2: 521pgm_no_vtime2:
535 HANDLE_SIE_INTERCEPT 522 HANDLE_SIE_INTERCEPT
536 TRACE_IRQS_CHECK_OFF
537 lg %r1,__TI_task(%r12) 523 lg %r1,__TI_task(%r12)
538 tm SP_PSW+1(%r15),0x01 # kernel per event ? 524 tm SP_PSW+1(%r15),0x01 # kernel per event ?
539 jz kernel_per 525 jz kernel_per
@@ -542,6 +528,8 @@ pgm_no_vtime2:
542 mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID 528 mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
543 oi __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP 529 oi __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
544 lgf %r3,__LC_PGM_ILC # load program interruption code 530 lgf %r3,__LC_PGM_ILC # load program interruption code
531 lg %r4,__LC_TRANS_EXC_CODE
532 REENABLE_IRQS
545 lghi %r8,0x7f 533 lghi %r8,0x7f
546 ngr %r8,%r3 # clear per-event-bit and ilc 534 ngr %r8,%r3 # clear per-event-bit and ilc
547 je pgm_exit2 535 je pgm_exit2
@@ -551,8 +539,6 @@ pgm_no_vtime2:
551 la %r2,SP_PTREGS(%r15) # address of register-save area 539 la %r2,SP_PTREGS(%r15) # address of register-save area
552 basr %r14,%r1 # branch to interrupt-handler 540 basr %r14,%r1 # branch to interrupt-handler
553pgm_exit2: 541pgm_exit2:
554 TRACE_IRQS_ON
555 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
556 j sysc_return 542 j sysc_return
557 543
558# 544#
@@ -568,13 +554,11 @@ pgm_svcper:
568 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER 554 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
569 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER 555 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
570 LAST_BREAK 556 LAST_BREAK
571 TRACE_IRQS_OFF
572 lg %r8,__TI_task(%r12) 557 lg %r8,__TI_task(%r12)
573 mvc __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID 558 mvc __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
574 mvc __THREAD_per+__PER_address(8,%r8),__LC_PER_ADDRESS 559 mvc __THREAD_per+__PER_address(8,%r8),__LC_PER_ADDRESS
575 mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID 560 mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
576 oi __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP 561 oi __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
577 TRACE_IRQS_ON
578 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts 562 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
579 lmg %r2,%r6,SP_R2(%r15) # load svc arguments 563 lmg %r2,%r6,SP_R2(%r15) # load svc arguments
580 j sysc_do_svc 564 j sysc_do_svc
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 5d8f0f3d0250..e9b063e7d75f 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -329,27 +329,19 @@ int is_valid_bugaddr(unsigned long addr)
329 return 1; 329 return 1;
330} 330}
331 331
332static void __kprobes inline do_trap(long interruption_code, int signr, 332static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str,
333 char *str, struct pt_regs *regs, 333 struct pt_regs *regs, siginfo_t *info)
334 siginfo_t *info)
335{ 334{
336 /* 335 if (notify_die(DIE_TRAP, str, regs, pgm_int_code,
337 * We got all needed information from the lowcore and can 336 pgm_int_code, signr) == NOTIFY_STOP)
338 * now safely switch on interrupts.
339 */
340 if (regs->psw.mask & PSW_MASK_PSTATE)
341 local_irq_enable();
342
343 if (notify_die(DIE_TRAP, str, regs, interruption_code,
344 interruption_code, signr) == NOTIFY_STOP)
345 return; 337 return;
346 338
347 if (regs->psw.mask & PSW_MASK_PSTATE) { 339 if (regs->psw.mask & PSW_MASK_PSTATE) {
348 struct task_struct *tsk = current; 340 struct task_struct *tsk = current;
349 341
350 tsk->thread.trap_no = interruption_code & 0xffff; 342 tsk->thread.trap_no = pgm_int_code & 0xffff;
351 force_sig_info(signr, info, tsk); 343 force_sig_info(signr, info, tsk);
352 report_user_fault(regs, interruption_code, signr); 344 report_user_fault(regs, pgm_int_code, signr);
353 } else { 345 } else {
354 const struct exception_table_entry *fixup; 346 const struct exception_table_entry *fixup;
355 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); 347 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
@@ -361,14 +353,16 @@ static void __kprobes inline do_trap(long interruption_code, int signr,
361 btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs); 353 btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);
362 if (btt == BUG_TRAP_TYPE_WARN) 354 if (btt == BUG_TRAP_TYPE_WARN)
363 return; 355 return;
364 die(str, regs, interruption_code); 356 die(str, regs, pgm_int_code);
365 } 357 }
366 } 358 }
367} 359}
368 360
369static inline void __user *get_check_address(struct pt_regs *regs) 361static inline void __user *get_psw_address(struct pt_regs *regs,
362 long pgm_int_code)
370{ 363{
371 return (void __user *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN); 364 return (void __user *)
365 ((regs->psw.addr - (pgm_int_code >> 16)) & PSW_ADDR_INSN);
372} 366}
373 367
374void __kprobes do_single_step(struct pt_regs *regs) 368void __kprobes do_single_step(struct pt_regs *regs)
@@ -381,57 +375,57 @@ void __kprobes do_single_step(struct pt_regs *regs)
381 force_sig(SIGTRAP, current); 375 force_sig(SIGTRAP, current);
382} 376}
383 377
384static void default_trap_handler(struct pt_regs * regs, long interruption_code) 378static void default_trap_handler(struct pt_regs *regs, long pgm_int_code,
379 unsigned long trans_exc_code)
385{ 380{
386 if (regs->psw.mask & PSW_MASK_PSTATE) { 381 if (regs->psw.mask & PSW_MASK_PSTATE) {
387 local_irq_enable(); 382 report_user_fault(regs, pgm_int_code, SIGSEGV);
388 report_user_fault(regs, interruption_code, SIGSEGV);
389 do_exit(SIGSEGV); 383 do_exit(SIGSEGV);
390 } else 384 } else
391 die("Unknown program exception", regs, interruption_code); 385 die("Unknown program exception", regs, pgm_int_code);
392} 386}
393 387
394#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \ 388#define DO_ERROR_INFO(name, signr, sicode, str) \
395static void name(struct pt_regs * regs, long interruption_code) \ 389static void name(struct pt_regs *regs, long pgm_int_code, \
390 unsigned long trans_exc_code) \
396{ \ 391{ \
397 siginfo_t info; \ 392 siginfo_t info; \
398 info.si_signo = signr; \ 393 info.si_signo = signr; \
399 info.si_errno = 0; \ 394 info.si_errno = 0; \
400 info.si_code = sicode; \ 395 info.si_code = sicode; \
401 info.si_addr = siaddr; \ 396 info.si_addr = get_psw_address(regs, pgm_int_code); \
402 do_trap(interruption_code, signr, str, regs, &info); \ 397 do_trap(pgm_int_code, signr, str, regs, &info); \
403} 398}
404 399
405DO_ERROR_INFO(SIGILL, "addressing exception", addressing_exception, 400DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
406 ILL_ILLADR, get_check_address(regs)) 401 "addressing exception")
407DO_ERROR_INFO(SIGILL, "execute exception", execute_exception, 402DO_ERROR_INFO(execute_exception, SIGILL, ILL_ILLOPN,
408 ILL_ILLOPN, get_check_address(regs)) 403 "execute exception")
409DO_ERROR_INFO(SIGFPE, "fixpoint divide exception", divide_exception, 404DO_ERROR_INFO(divide_exception, SIGFPE, FPE_INTDIV,
410 FPE_INTDIV, get_check_address(regs)) 405 "fixpoint divide exception")
411DO_ERROR_INFO(SIGFPE, "fixpoint overflow exception", overflow_exception, 406DO_ERROR_INFO(overflow_exception, SIGFPE, FPE_INTOVF,
412 FPE_INTOVF, get_check_address(regs)) 407 "fixpoint overflow exception")
413DO_ERROR_INFO(SIGFPE, "HFP overflow exception", hfp_overflow_exception, 408DO_ERROR_INFO(hfp_overflow_exception, SIGFPE, FPE_FLTOVF,
414 FPE_FLTOVF, get_check_address(regs)) 409 "HFP overflow exception")
415DO_ERROR_INFO(SIGFPE, "HFP underflow exception", hfp_underflow_exception, 410DO_ERROR_INFO(hfp_underflow_exception, SIGFPE, FPE_FLTUND,
416 FPE_FLTUND, get_check_address(regs)) 411 "HFP underflow exception")
417DO_ERROR_INFO(SIGFPE, "HFP significance exception", hfp_significance_exception, 412DO_ERROR_INFO(hfp_significance_exception, SIGFPE, FPE_FLTRES,
418 FPE_FLTRES, get_check_address(regs)) 413 "HFP significance exception")
419DO_ERROR_INFO(SIGFPE, "HFP divide exception", hfp_divide_exception, 414DO_ERROR_INFO(hfp_divide_exception, SIGFPE, FPE_FLTDIV,
420 FPE_FLTDIV, get_check_address(regs)) 415 "HFP divide exception")
421DO_ERROR_INFO(SIGFPE, "HFP square root exception", hfp_sqrt_exception, 416DO_ERROR_INFO(hfp_sqrt_exception, SIGFPE, FPE_FLTINV,
422 FPE_FLTINV, get_check_address(regs)) 417 "HFP square root exception")
423DO_ERROR_INFO(SIGILL, "operand exception", operand_exception, 418DO_ERROR_INFO(operand_exception, SIGILL, ILL_ILLOPN,
424 ILL_ILLOPN, get_check_address(regs)) 419 "operand exception")
425DO_ERROR_INFO(SIGILL, "privileged operation", privileged_op, 420DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC,
426 ILL_PRVOPC, get_check_address(regs)) 421 "privileged operation")
427DO_ERROR_INFO(SIGILL, "special operation exception", special_op_exception, 422DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
428 ILL_ILLOPN, get_check_address(regs)) 423 "special operation exception")
429DO_ERROR_INFO(SIGILL, "translation exception", translation_exception, 424DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN,
430 ILL_ILLOPN, get_check_address(regs)) 425 "translation exception")
431 426
432static inline void 427static inline void do_fp_trap(struct pt_regs *regs, void __user *location,
433do_fp_trap(struct pt_regs *regs, void __user *location, 428 int fpc, long pgm_int_code)
434 int fpc, long interruption_code)
435{ 429{
436 siginfo_t si; 430 siginfo_t si;
437 431
@@ -454,25 +448,19 @@ do_fp_trap(struct pt_regs *regs, void __user *location,
454 si.si_code = FPE_FLTRES; 448 si.si_code = FPE_FLTRES;
455 } 449 }
456 current->thread.ieee_instruction_pointer = (addr_t) location; 450 current->thread.ieee_instruction_pointer = (addr_t) location;
457 do_trap(interruption_code, SIGFPE, 451 do_trap(pgm_int_code, SIGFPE,
458 "floating point exception", regs, &si); 452 "floating point exception", regs, &si);
459} 453}
460 454
461static void illegal_op(struct pt_regs * regs, long interruption_code) 455static void illegal_op(struct pt_regs *regs, long pgm_int_code,
456 unsigned long trans_exc_code)
462{ 457{
463 siginfo_t info; 458 siginfo_t info;
464 __u8 opcode[6]; 459 __u8 opcode[6];
465 __u16 __user *location; 460 __u16 __user *location;
466 int signal = 0; 461 int signal = 0;
467 462
468 location = get_check_address(regs); 463 location = get_psw_address(regs, pgm_int_code);
469
470 /*
471 * We got all needed information from the lowcore and can
472 * now safely switch on interrupts.
473 */
474 if (regs->psw.mask & PSW_MASK_PSTATE)
475 local_irq_enable();
476 464
477 if (regs->psw.mask & PSW_MASK_PSTATE) { 465 if (regs->psw.mask & PSW_MASK_PSTATE) {
478 if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) 466 if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
@@ -512,7 +500,7 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
512 * If we get an illegal op in kernel mode, send it through the 500 * If we get an illegal op in kernel mode, send it through the
513 * kprobes notifier. If kprobes doesn't pick it up, SIGILL 501 * kprobes notifier. If kprobes doesn't pick it up, SIGILL
514 */ 502 */
515 if (notify_die(DIE_BPT, "bpt", regs, interruption_code, 503 if (notify_die(DIE_BPT, "bpt", regs, pgm_int_code,
516 3, SIGTRAP) != NOTIFY_STOP) 504 3, SIGTRAP) != NOTIFY_STOP)
517 signal = SIGILL; 505 signal = SIGILL;
518 } 506 }
@@ -520,13 +508,13 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
520#ifdef CONFIG_MATHEMU 508#ifdef CONFIG_MATHEMU
521 if (signal == SIGFPE) 509 if (signal == SIGFPE)
522 do_fp_trap(regs, location, 510 do_fp_trap(regs, location,
523 current->thread.fp_regs.fpc, interruption_code); 511 current->thread.fp_regs.fpc, pgm_int_code);
524 else if (signal == SIGSEGV) { 512 else if (signal == SIGSEGV) {
525 info.si_signo = signal; 513 info.si_signo = signal;
526 info.si_errno = 0; 514 info.si_errno = 0;
527 info.si_code = SEGV_MAPERR; 515 info.si_code = SEGV_MAPERR;
528 info.si_addr = (void __user *) location; 516 info.si_addr = (void __user *) location;
529 do_trap(interruption_code, signal, 517 do_trap(pgm_int_code, signal,
530 "user address fault", regs, &info); 518 "user address fault", regs, &info);
531 } else 519 } else
532#endif 520#endif
@@ -535,28 +523,22 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
535 info.si_errno = 0; 523 info.si_errno = 0;
536 info.si_code = ILL_ILLOPC; 524 info.si_code = ILL_ILLOPC;
537 info.si_addr = (void __user *) location; 525 info.si_addr = (void __user *) location;
538 do_trap(interruption_code, signal, 526 do_trap(pgm_int_code, signal,
539 "illegal operation", regs, &info); 527 "illegal operation", regs, &info);
540 } 528 }
541} 529}
542 530
543 531
544#ifdef CONFIG_MATHEMU 532#ifdef CONFIG_MATHEMU
545asmlinkage void 533asmlinkage void specification_exception(struct pt_regs *regs,
546specification_exception(struct pt_regs * regs, long interruption_code) 534 long pgm_int_code,
535 unsigned long trans_exc_code)
547{ 536{
548 __u8 opcode[6]; 537 __u8 opcode[6];
549 __u16 __user *location = NULL; 538 __u16 __user *location = NULL;
550 int signal = 0; 539 int signal = 0;
551 540
552 location = (__u16 __user *) get_check_address(regs); 541 location = (__u16 __user *) get_psw_address(regs, pgm_int_code);
553
554 /*
555 * We got all needed information from the lowcore and can
556 * now safely switch on interrupts.
557 */
558 if (regs->psw.mask & PSW_MASK_PSTATE)
559 local_irq_enable();
560 542
561 if (regs->psw.mask & PSW_MASK_PSTATE) { 543 if (regs->psw.mask & PSW_MASK_PSTATE) {
562 get_user(*((__u16 *) opcode), location); 544 get_user(*((__u16 *) opcode), location);
@@ -592,35 +574,29 @@ specification_exception(struct pt_regs * regs, long interruption_code)
592 574
593 if (signal == SIGFPE) 575 if (signal == SIGFPE)
594 do_fp_trap(regs, location, 576 do_fp_trap(regs, location,
595 current->thread.fp_regs.fpc, interruption_code); 577 current->thread.fp_regs.fpc, pgm_int_code);
596 else if (signal) { 578 else if (signal) {
597 siginfo_t info; 579 siginfo_t info;
598 info.si_signo = signal; 580 info.si_signo = signal;
599 info.si_errno = 0; 581 info.si_errno = 0;
600 info.si_code = ILL_ILLOPN; 582 info.si_code = ILL_ILLOPN;
601 info.si_addr = location; 583 info.si_addr = location;
602 do_trap(interruption_code, signal, 584 do_trap(pgm_int_code, signal,
603 "specification exception", regs, &info); 585 "specification exception", regs, &info);
604 } 586 }
605} 587}
606#else 588#else
607DO_ERROR_INFO(SIGILL, "specification exception", specification_exception, 589DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
608 ILL_ILLOPN, get_check_address(regs)); 590 "specification exception");
609#endif 591#endif
610 592
611static void data_exception(struct pt_regs * regs, long interruption_code) 593static void data_exception(struct pt_regs *regs, long pgm_int_code,
594 unsigned long trans_exc_code)
612{ 595{
613 __u16 __user *location; 596 __u16 __user *location;
614 int signal = 0; 597 int signal = 0;
615 598
616 location = get_check_address(regs); 599 location = get_psw_address(regs, pgm_int_code);
617
618 /*
619 * We got all needed information from the lowcore and can
620 * now safely switch on interrupts.
621 */
622 if (regs->psw.mask & PSW_MASK_PSTATE)
623 local_irq_enable();
624 600
625 if (MACHINE_HAS_IEEE) 601 if (MACHINE_HAS_IEEE)
626 asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); 602 asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
@@ -686,19 +662,19 @@ static void data_exception(struct pt_regs * regs, long interruption_code)
686 signal = SIGILL; 662 signal = SIGILL;
687 if (signal == SIGFPE) 663 if (signal == SIGFPE)
688 do_fp_trap(regs, location, 664 do_fp_trap(regs, location,
689 current->thread.fp_regs.fpc, interruption_code); 665 current->thread.fp_regs.fpc, pgm_int_code);
690 else if (signal) { 666 else if (signal) {
691 siginfo_t info; 667 siginfo_t info;
692 info.si_signo = signal; 668 info.si_signo = signal;
693 info.si_errno = 0; 669 info.si_errno = 0;
694 info.si_code = ILL_ILLOPN; 670 info.si_code = ILL_ILLOPN;
695 info.si_addr = location; 671 info.si_addr = location;
696 do_trap(interruption_code, signal, 672 do_trap(pgm_int_code, signal, "data exception", regs, &info);
697 "data exception", regs, &info);
698 } 673 }
699} 674}
700 675
701static void space_switch_exception(struct pt_regs * regs, long int_code) 676static void space_switch_exception(struct pt_regs *regs, long pgm_int_code,
677 unsigned long trans_exc_code)
702{ 678{
703 siginfo_t info; 679 siginfo_t info;
704 680
@@ -709,8 +685,8 @@ static void space_switch_exception(struct pt_regs * regs, long int_code)
709 info.si_signo = SIGILL; 685 info.si_signo = SIGILL;
710 info.si_errno = 0; 686 info.si_errno = 0;
711 info.si_code = ILL_PRVOPC; 687 info.si_code = ILL_PRVOPC;
712 info.si_addr = get_check_address(regs); 688 info.si_addr = get_psw_address(regs, pgm_int_code);
713 do_trap(int_code, SIGILL, "space switch event", regs, &info); 689 do_trap(pgm_int_code, SIGILL, "space switch event", regs, &info);
714} 690}
715 691
716asmlinkage void kernel_stack_overflow(struct pt_regs * regs) 692asmlinkage void kernel_stack_overflow(struct pt_regs * regs)