diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2010-10-25 10:10:37 -0400 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2010-10-25 10:10:19 -0400 |
commit | 1e54622e0403891b10f2105663e0f9dd595a1f17 (patch) | |
tree | 4d16341d7a3d0f3c46fcc275560a9206bccac07f /arch/s390/kernel | |
parent | 84afdcee620b1640f2a145c07febae4ed68947f9 (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.c | 1 | ||||
-rw-r--r-- | arch/s390/kernel/entry.S | 35 | ||||
-rw-r--r-- | arch/s390/kernel/entry.h | 2 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 36 | ||||
-rw-r--r-- | arch/s390/kernel/traps.c | 172 |
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 | ||
80 | 0: | ||
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 | ||
87 | 0: | ||
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. |
442 | 0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts | 432 | 0: 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 |
485 | pgm_no_vtime: | 473 | pgm_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 |
491 | pgm_do_call: | 480 | pgm_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 |
497 | pgm_exit: | 486 | pgm_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 |
525 | pgm_no_vtime2: | 513 | pgm_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 |
544 | pgm_exit2: | 533 | pgm_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 | ||
8 | typedef void pgm_check_handler_t(struct pt_regs *, long); | 8 | typedef void pgm_check_handler_t(struct pt_regs *, long, unsigned long); |
9 | extern pgm_check_handler_t *pgm_check_table[128]; | 9 | extern pgm_check_handler_t *pgm_check_table[128]; |
10 | pgm_check_handler_t do_protection_exception; | 10 | pgm_check_handler_t do_protection_exception; |
11 | pgm_check_handler_t do_dat_exception; | 11 | pgm_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 | ||
87 | 0: | ||
88 | .endm | ||
89 | |||
90 | .macro TRACE_IRQS_CHECK_OFF | ||
91 | tm SP_PSW(%r15),0x03 # irqs enabled? | ||
92 | jz 0f | ||
93 | TRACE_IRQS_OFF | ||
94 | 0: | ||
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 | \ | |||
207 | 0: | 191 | 0: |
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. |
445 | 0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts | 435 | 0: 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 |
491 | pgm_no_vtime: | 479 | pgm_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 |
498 | pgm_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 |
504 | pgm_exit: | 492 | pgm_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 |
534 | pgm_no_vtime2: | 521 | pgm_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 |
553 | pgm_exit2: | 541 | pgm_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 | ||
332 | static void __kprobes inline do_trap(long interruption_code, int signr, | 332 | static 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 | ||
369 | static inline void __user *get_check_address(struct pt_regs *regs) | 361 | static 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 | ||
374 | void __kprobes do_single_step(struct pt_regs *regs) | 368 | void __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 | ||
384 | static void default_trap_handler(struct pt_regs * regs, long interruption_code) | 378 | static 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) \ |
395 | static void name(struct pt_regs * regs, long interruption_code) \ | 389 | static 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 | ||
405 | DO_ERROR_INFO(SIGILL, "addressing exception", addressing_exception, | 400 | DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR, |
406 | ILL_ILLADR, get_check_address(regs)) | 401 | "addressing exception") |
407 | DO_ERROR_INFO(SIGILL, "execute exception", execute_exception, | 402 | DO_ERROR_INFO(execute_exception, SIGILL, ILL_ILLOPN, |
408 | ILL_ILLOPN, get_check_address(regs)) | 403 | "execute exception") |
409 | DO_ERROR_INFO(SIGFPE, "fixpoint divide exception", divide_exception, | 404 | DO_ERROR_INFO(divide_exception, SIGFPE, FPE_INTDIV, |
410 | FPE_INTDIV, get_check_address(regs)) | 405 | "fixpoint divide exception") |
411 | DO_ERROR_INFO(SIGFPE, "fixpoint overflow exception", overflow_exception, | 406 | DO_ERROR_INFO(overflow_exception, SIGFPE, FPE_INTOVF, |
412 | FPE_INTOVF, get_check_address(regs)) | 407 | "fixpoint overflow exception") |
413 | DO_ERROR_INFO(SIGFPE, "HFP overflow exception", hfp_overflow_exception, | 408 | DO_ERROR_INFO(hfp_overflow_exception, SIGFPE, FPE_FLTOVF, |
414 | FPE_FLTOVF, get_check_address(regs)) | 409 | "HFP overflow exception") |
415 | DO_ERROR_INFO(SIGFPE, "HFP underflow exception", hfp_underflow_exception, | 410 | DO_ERROR_INFO(hfp_underflow_exception, SIGFPE, FPE_FLTUND, |
416 | FPE_FLTUND, get_check_address(regs)) | 411 | "HFP underflow exception") |
417 | DO_ERROR_INFO(SIGFPE, "HFP significance exception", hfp_significance_exception, | 412 | DO_ERROR_INFO(hfp_significance_exception, SIGFPE, FPE_FLTRES, |
418 | FPE_FLTRES, get_check_address(regs)) | 413 | "HFP significance exception") |
419 | DO_ERROR_INFO(SIGFPE, "HFP divide exception", hfp_divide_exception, | 414 | DO_ERROR_INFO(hfp_divide_exception, SIGFPE, FPE_FLTDIV, |
420 | FPE_FLTDIV, get_check_address(regs)) | 415 | "HFP divide exception") |
421 | DO_ERROR_INFO(SIGFPE, "HFP square root exception", hfp_sqrt_exception, | 416 | DO_ERROR_INFO(hfp_sqrt_exception, SIGFPE, FPE_FLTINV, |
422 | FPE_FLTINV, get_check_address(regs)) | 417 | "HFP square root exception") |
423 | DO_ERROR_INFO(SIGILL, "operand exception", operand_exception, | 418 | DO_ERROR_INFO(operand_exception, SIGILL, ILL_ILLOPN, |
424 | ILL_ILLOPN, get_check_address(regs)) | 419 | "operand exception") |
425 | DO_ERROR_INFO(SIGILL, "privileged operation", privileged_op, | 420 | DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC, |
426 | ILL_PRVOPC, get_check_address(regs)) | 421 | "privileged operation") |
427 | DO_ERROR_INFO(SIGILL, "special operation exception", special_op_exception, | 422 | DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN, |
428 | ILL_ILLOPN, get_check_address(regs)) | 423 | "special operation exception") |
429 | DO_ERROR_INFO(SIGILL, "translation exception", translation_exception, | 424 | DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, |
430 | ILL_ILLOPN, get_check_address(regs)) | 425 | "translation exception") |
431 | 426 | ||
432 | static inline void | 427 | static inline void do_fp_trap(struct pt_regs *regs, void __user *location, |
433 | do_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 | ||
461 | static void illegal_op(struct pt_regs * regs, long interruption_code) | 455 | static 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 |
545 | asmlinkage void | 533 | asmlinkage void specification_exception(struct pt_regs *regs, |
546 | specification_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 |
607 | DO_ERROR_INFO(SIGILL, "specification exception", specification_exception, | 589 | DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN, |
608 | ILL_ILLOPN, get_check_address(regs)); | 590 | "specification exception"); |
609 | #endif | 591 | #endif |
610 | 592 | ||
611 | static void data_exception(struct pt_regs * regs, long interruption_code) | 593 | static 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 | ||
701 | static void space_switch_exception(struct pt_regs * regs, long int_code) | 676 | static 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 | ||
716 | asmlinkage void kernel_stack_overflow(struct pt_regs * regs) | 692 | asmlinkage void kernel_stack_overflow(struct pt_regs * regs) |