Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[S390] cleanup trap handling

Move the program interruption code and the translation exception identifier
to the pt_regs structure as 'int_code' and 'int_parm_long' and make the
first level interrupt handler in entry[64].S store the two values. That
makes it possible to drop 'prot_addr' and 'trap_no' from the thread_struct
and to reduce the number of arguments to a lot of functions. Finally
un-inline do_trap. Overall this saves 5812 bytes in the .text section of
the 64 bit kernel.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

+158 -210
+1 -1
arch/s390/include/asm/kdebug.h
··· 22 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 27 #endif
-2
arch/s390/include/asm/processor.h
··· 80 80 unsigned int acrs[NUM_ACRS]; 81 81 unsigned long ksp; /* kernel stack pointer */ 82 82 mm_segment_t mm_segment; 83 - unsigned long prot_addr; /* address of protection-excep. */ 84 - unsigned int trap_no; 85 83 unsigned long gmap_addr; /* address of last gmap fault. */ 86 84 struct per_regs per_user; /* User specified PER registers */ 87 85 struct per_event per_event; /* Cause of the last PER trap */
+2 -1
arch/s390/include/asm/ptrace.h
··· 324 324 psw_t psw; 325 325 unsigned long gprs[NUM_GPRS]; 326 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 /*
+1 -1
arch/s390/include/asm/syscall.h
··· 27 27 struct pt_regs *regs) 28 28 { 29 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 33 static inline void syscall_rollback(struct task_struct *task,
+2 -1
arch/s390/kernel/asm-offsets.c
··· 45 45 DEFINE(__PT_PSW, offsetof(struct pt_regs, psw)); 46 46 DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs)); 47 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 50 DEFINE(__PT_SIZE, sizeof(struct pt_regs)); 50 51 BLANK(); 51 52 DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain));
+6 -2
arch/s390/kernel/compat_signal.c
··· 501 501 502 502 /* We forgot to include these in the sigcontext. 503 503 To avoid breaking binary compatibility, they are passed as args. */ 504 - regs->gprs[4] = current->thread.trap_no; 505 - regs->gprs[5] = current->thread.prot_addr; 504 + if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || 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 511 /* Place signal number on stack to allow backtrace from handler. */ 508 512 if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo))
+11 -11
arch/s390/kernel/entry.S
··· 184 184 stm %r0,%r7,__PT_R0(%r11) 185 185 mvc __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC 186 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 188 sysc_do_svc: 189 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 191 sla %r8,2 # shift and test for svc0 192 192 jnz sysc_nr_ok 193 193 # svc 0: system call number in %r1 194 194 cl %r1,BASED(.Lnr_syscalls) 195 195 jnl sysc_nr_ok 196 - sth %r1,__PT_SVC_CODE+2(%r11) 196 + sth %r1,__PT_INT_CODE+2(%r11) 197 197 lr %r8,%r1 198 198 sla %r8,2 199 199 sysc_nr_ok: ··· 266 266 jno sysc_return 267 267 lm %r2,%r7,__PT_R2(%r11) # load svc arguments 268 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 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 272 sla %r8,2 273 273 j sysc_nr_ok # restart svc 274 274 ··· 300 300 lr %r2,%r11 # pass pointer to pt_regs 301 301 la %r3,0 302 302 xr %r0,%r0 303 - icm %r0,3,__PT_SVC_CODE+2(%r11) 303 + icm %r0,3,__PT_INT_CODE+2(%r11) 304 304 st %r0,__PT_R2(%r11) 305 305 basr %r14,%r1 # call do_syscall_trace_enter 306 306 cl %r2,BASED(.Lnr_syscalls) ··· 396 396 stm %r0,%r7,__PT_R0(%r11) 397 397 mvc __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC 398 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 401 tm __LC_PGM_ILC+3,0x80 # check for per exception 400 402 jz 0f 401 403 l %r1,__TI_task(%r12) ··· 407 405 mvc __THREAD_per_address(4,%r1),__LC_PER_ADDRESS 408 406 mvc __THREAD_per_cause(2,%r1),__LC_PER_CAUSE 409 407 mvc __THREAD_per_paid(1,%r1),__LC_PER_PAID 410 - 0: l %r3,__LC_PGM_ILC # load program interruption code 411 - l %r4,__LC_TRANS_EXC_CODE 412 - REENABLE_IRQS 408 + 0: REENABLE_IRQS 413 409 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) 414 410 l %r1,BASED(.Ljump_table) 415 411 la %r10,0x7f 416 - nr %r10,%r3 412 + n %r10,__PT_INT_CODE(%r11) 417 413 je sysc_return 418 414 sll %r10,2 419 415 l %r1,0(%r10,%r1) # load address of handler routine ··· 858 858 mvc __PT_R8(32,%r15),__LC_SAVE_AREA_SYNC 859 859 stm %r0,%r7,__PT_R0(%r15) 860 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 862 # setup saved register 15 863 863 ahi %r15,-STACK_FRAME_OVERHEAD 864 864 st %r15,28(%r11) # r15 stack pointer
+5 -5
arch/s390/kernel/entry.h
··· 6 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 10 extern void *restart_stack; 11 11 12 12 asmlinkage long do_syscall_trace_enter(struct pt_regs *regs); 13 13 asmlinkage void do_syscall_trace_exit(struct pt_regs *regs); 14 14 15 - void do_protection_exception(struct pt_regs *, long, unsigned long); 16 - void do_dat_exception(struct pt_regs *, long, unsigned long); 17 - void do_asce_exception(struct pt_regs *, long, unsigned long); 15 + void do_protection_exception(struct pt_regs *regs); 16 + void do_dat_exception(struct pt_regs *regs); 17 + void do_asce_exception(struct pt_regs *regs); 18 18 19 19 void do_per_trap(struct pt_regs *regs); 20 20 void syscall_trace(struct pt_regs *regs, int entryexit); ··· 28 28 void do_restart(void); 29 29 int __cpuinit start_secondary(void *cpuvoid); 30 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 33 void __init time_init(void); 34 34
+13 -14
arch/s390/kernel/entry64.S
··· 1 - 2 1 /* 3 2 * arch/s390/kernel/entry64.S 4 3 * S390 low-level entry points. ··· 199 200 stmg %r0,%r7,__PT_R0(%r11) 200 201 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC 201 202 mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW 202 - mvc __PT_SVC_CODE(4,%r11),__LC_SVC_ILC 203 + mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC 203 204 sysc_do_svc: 204 205 oi __TI_flags+7(%r12),_TIF_SYSCALL 205 - llgh %r8,__PT_SVC_CODE+2(%r11) 206 + llgh %r8,__PT_INT_CODE+2(%r11) 206 207 slag %r8,%r8,2 # shift and test for svc 0 207 208 jnz sysc_nr_ok 208 209 # svc 0: system call number in %r1 209 210 llgfr %r1,%r1 # clear high word in r1 210 211 cghi %r1,NR_syscalls 211 212 jnl sysc_nr_ok 212 - sth %r1,__PT_SVC_CODE+2(%r11) 213 + sth %r1,__PT_INT_CODE+2(%r11) 213 214 slag %r8,%r1,2 214 215 sysc_nr_ok: 215 216 larl %r10,sys_call_table # 64 bit system call table ··· 287 288 jno sysc_return 288 289 lmg %r2,%r7,__PT_R2(%r11) # load svc arguments 289 290 lghi %r8,0 # svc 0 returns -ENOSYS 290 - lh %r1,__PT_SVC_CODE+2(%r11) # load new svc number 291 + lh %r1,__PT_INT_CODE+2(%r11) # load new svc number 291 292 cghi %r1,NR_syscalls 292 293 jnl sysc_nr_ok # invalid svc number -> do svc 0 293 294 slag %r8,%r1,2 ··· 317 318 sysc_tracesys: 318 319 lgr %r2,%r11 # pass pointer to pt_regs 319 320 la %r3,0 320 - llgh %r0,__PT_SVC_CODE+2(%r11) 321 + llgh %r0,__PT_INT_CODE+2(%r11) 321 322 stg %r0,__PT_R2(%r11) 322 323 brasl %r14,do_syscall_trace_enter 323 324 lghi %r0,NR_syscalls ··· 410 411 stmg %r0,%r7,__PT_R0(%r11) 411 412 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC 412 413 stmg %r8,%r9,__PT_PSW(%r11) 414 + mvc __PT_INT_CODE(4,%r11),__LC_PGM_ILC 415 + mvc __PT_INT_PARM_LONG(8,%r11),__LC_TRANS_EXC_CODE 413 416 stg %r10,__PT_ARGS(%r11) 414 417 tm __LC_PGM_ILC+3,0x80 # check for per exception 415 418 jz 0f ··· 422 421 mvc __THREAD_per_address(8,%r1),__LC_PER_ADDRESS 423 422 mvc __THREAD_per_cause(2,%r1),__LC_PER_CAUSE 424 423 mvc __THREAD_per_paid(1,%r1),__LC_PER_PAID 425 - 0: lgf %r3,__LC_PGM_ILC # load program interruption code 426 - lg %r4,__LC_TRANS_EXC_CODE 427 - REENABLE_IRQS 424 + 0: REENABLE_IRQS 428 425 xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) 429 - lghi %r10,0x7f 430 - ngr %r10,%r3 431 - je sysc_return 432 - sll %r10,3 433 426 larl %r1,pgm_check_table 427 + llgh %r10,__PT_INT_CODE+2(%r11) 428 + nill %r10,0x007f 429 + sll %r10,3 430 + je sysc_return 434 431 lg %r1,0(%r10,%r1) # load address of handler routine 435 432 lgr %r2,%r11 # pass pointer to pt_regs 436 433 basr %r14,%r1 # branch to interrupt-handler ··· 876 877 mvc __PT_R8(64,%r15),__LC_SAVE_AREA_SYNC 877 878 stmg %r0,%r7,__PT_R0(%r15) 878 879 mvc __PT_PSW(16,%r15),__LC_SVC_OLD_PSW 879 - mvc __PT_SVC_CODE(4,%r15),__LC_SVC_ILC 880 + mvc __PT_INT_CODE(4,%r15),__LC_SVC_ILC 880 881 # setup saved register r15 881 882 aghi %r15,-STACK_FRAME_OVERHEAD 882 883 stg %r15,56(%r11) # r15 stack pointer
+12 -8
arch/s390/kernel/signal.c
··· 302 302 303 303 /* We forgot to include these in the sigcontext. 304 304 To avoid breaking binary compatibility, they are passed as args. */ 305 - regs->gprs[4] = current->thread.trap_no; 306 - regs->gprs[5] = current->thread.prot_addr; 307 - regs->gprs[6] = task_thread_info(current)->last_break; 305 + if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || 306 + sig == SIGTRAP || sig == SIGFPE) { 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 313 /* Place signal number on stack to allow backtrace from handler. */ 310 314 if (__put_user(regs->gprs[2], (int __user *) &frame->signo)) ··· 438 434 * call information. 439 435 */ 440 436 current_thread_info()->system_call = 441 - test_thread_flag(TIF_SYSCALL) ? regs->svc_code : 0; 437 + test_thread_flag(TIF_SYSCALL) ? regs->int_code : 0; 442 438 signr = get_signal_to_deliver(&info, &ka, regs, NULL); 443 439 444 440 if (signr > 0) { 445 441 /* Whee! Actually deliver the signal. */ 446 442 if (current_thread_info()->system_call) { 447 - regs->svc_code = current_thread_info()->system_call; 443 + regs->int_code = current_thread_info()->system_call; 448 444 /* Check for system call restarting. */ 449 445 switch (regs->gprs[2]) { 450 446 case -ERESTART_RESTARTBLOCK: ··· 461 457 regs->gprs[2] = regs->orig_gpr2; 462 458 regs->psw.addr = 463 459 __rewind_psw(regs->psw, 464 - regs->svc_code >> 16); 460 + regs->int_code >> 16); 465 461 break; 466 462 } 467 463 } ··· 492 488 /* No handlers present - check for system call restart */ 493 489 clear_thread_flag(TIF_SYSCALL); 494 490 if (current_thread_info()->system_call) { 495 - regs->svc_code = current_thread_info()->system_call; 491 + regs->int_code = current_thread_info()->system_call; 496 492 switch (regs->gprs[2]) { 497 493 case -ERESTART_RESTARTBLOCK: 498 494 /* Restart with sys_restart_syscall */ 499 - regs->svc_code = __NR_restart_syscall; 495 + regs->int_code = __NR_restart_syscall; 500 496 /* fallthrough */ 501 497 case -ERESTARTNOHAND: 502 498 case -ERESTARTSYS:
+59 -109
arch/s390/kernel/traps.c
··· 43 43 #include <asm/debug.h> 44 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 48 int show_unhandled_signals; 49 49 ··· 234 234 235 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 239 static int die_counter; 240 240 ··· 243 243 console_verbose(); 244 244 spin_lock_irq(&die_lock); 245 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 247 #ifdef CONFIG_PREEMPT 248 248 printk("PREEMPT "); 249 249 #endif ··· 254 254 printk("DEBUG_PAGEALLOC"); 255 255 #endif 256 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 258 show_regs(regs); 259 259 bust_spinlocks(0); 260 260 add_taint(TAINT_DIE); ··· 267 267 do_exit(SIGSEGV); 268 268 } 269 269 270 - static void inline report_user_fault(struct pt_regs *regs, long int_code, 271 - int signr) 270 + static inline void report_user_fault(struct pt_regs *regs, int signr) 272 271 { 273 272 if ((task_pid_nr(current) > 1) && !show_unhandled_signals) 274 273 return; ··· 275 276 return; 276 277 if (!printk_ratelimit()) 277 278 return; 278 - printk("User process fault: interruption code 0x%lX ", int_code); 279 + printk("User process fault: interruption code 0x%X ", regs->int_code); 279 280 print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN); 280 281 printk("\n"); 281 282 show_regs(regs); ··· 286 287 return 1; 287 288 } 288 289 289 - static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str, 290 - struct pt_regs *regs, siginfo_t *info) 290 + static inline void __user *get_psw_address(struct pt_regs *regs) 291 291 { 292 - if (notify_die(DIE_TRAP, str, regs, pgm_int_code, 293 - pgm_int_code, signr) == NOTIFY_STOP) 292 + return (void __user *) 293 + ((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN); 294 + } 295 + 296 + static void __kprobes do_trap(struct pt_regs *regs, 297 + int si_signo, int si_code, char *str) 298 + { 299 + siginfo_t info; 300 + 301 + if (notify_die(DIE_TRAP, str, regs, 0, 302 + regs->int_code, si_signo) == NOTIFY_STOP) 294 303 return; 295 304 296 305 if (regs->psw.mask & PSW_MASK_PSTATE) { 297 - struct task_struct *tsk = current; 298 - 299 - tsk->thread.trap_no = pgm_int_code & 0xffff; 300 - force_sig_info(signr, info, tsk); 301 - report_user_fault(regs, pgm_int_code, signr); 306 + info.si_signo = si_signo; 307 + info.si_errno = 0; 308 + info.si_code = si_code; 309 + info.si_addr = get_psw_address(regs); 310 + force_sig_info(si_signo, &info, current); 311 + report_user_fault(regs, si_signo); 302 312 } else { 303 313 const struct exception_table_entry *fixup; 304 314 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); ··· 319 311 btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs); 320 312 if (btt == BUG_TRAP_TYPE_WARN) 321 313 return; 322 - die(str, regs, pgm_int_code); 314 + die(regs, str); 323 315 } 324 316 } 325 - } 326 - 327 - static inline void __user *get_psw_address(struct pt_regs *regs, 328 - long pgm_int_code) 329 - { 330 - return (void __user *) 331 - ((regs->psw.addr - (pgm_int_code >> 16)) & PSW_ADDR_INSN); 332 317 } 333 318 334 319 void __kprobes do_per_trap(struct pt_regs *regs) ··· 340 339 force_sig_info(SIGTRAP, &info, current); 341 340 } 342 341 343 - static void default_trap_handler(struct pt_regs *regs, long pgm_int_code, 344 - unsigned long trans_exc_code) 342 + static void default_trap_handler(struct pt_regs *regs) 345 343 { 346 344 if (regs->psw.mask & PSW_MASK_PSTATE) { 347 - report_user_fault(regs, pgm_int_code, SIGSEGV); 345 + report_user_fault(regs, SIGSEGV); 348 346 do_exit(SIGSEGV); 349 347 } else 350 - die("Unknown program exception", regs, pgm_int_code); 348 + die(regs, "Unknown program exception"); 351 349 } 352 350 353 351 #define DO_ERROR_INFO(name, signr, sicode, str) \ 354 - static void name(struct pt_regs *regs, long pgm_int_code, \ 355 - unsigned long trans_exc_code) \ 352 + static void name(struct pt_regs *regs) \ 356 353 { \ 357 - siginfo_t info; \ 358 - info.si_signo = signr; \ 359 - info.si_errno = 0; \ 360 - info.si_code = sicode; \ 361 - info.si_addr = get_psw_address(regs, pgm_int_code); \ 362 - do_trap(pgm_int_code, signr, str, regs, &info); \ 354 + do_trap(regs, signr, sicode, str); \ 363 355 } 364 356 365 357 DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR, ··· 382 388 DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, 383 389 "translation exception") 384 390 385 - static inline void do_fp_trap(struct pt_regs *regs, void __user *location, 386 - int fpc, long pgm_int_code) 391 + static inline void do_fp_trap(struct pt_regs *regs, int fpc) 387 392 { 388 - siginfo_t si; 389 - 390 - si.si_signo = SIGFPE; 391 - si.si_errno = 0; 392 - si.si_addr = location; 393 - si.si_code = 0; 393 + int si_code = 0; 394 394 /* FPC[2] is Data Exception Code */ 395 395 if ((fpc & 0x00000300) == 0) { 396 396 /* bits 6 and 7 of DXC are 0 iff IEEE exception */ 397 397 if (fpc & 0x8000) /* invalid fp operation */ 398 - si.si_code = FPE_FLTINV; 398 + si_code = FPE_FLTINV; 399 399 else if (fpc & 0x4000) /* div by 0 */ 400 - si.si_code = FPE_FLTDIV; 400 + si_code = FPE_FLTDIV; 401 401 else if (fpc & 0x2000) /* overflow */ 402 - si.si_code = FPE_FLTOVF; 402 + si_code = FPE_FLTOVF; 403 403 else if (fpc & 0x1000) /* underflow */ 404 - si.si_code = FPE_FLTUND; 404 + si_code = FPE_FLTUND; 405 405 else if (fpc & 0x0800) /* inexact */ 406 - si.si_code = FPE_FLTRES; 406 + si_code = FPE_FLTRES; 407 407 } 408 - do_trap(pgm_int_code, SIGFPE, 409 - "floating point exception", regs, &si); 408 + do_trap(regs, SIGFPE, si_code, "floating point exception"); 410 409 } 411 410 412 - static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_code, 413 - unsigned long trans_exc_code) 411 + static void __kprobes illegal_op(struct pt_regs *regs) 414 412 { 415 413 siginfo_t info; 416 414 __u8 opcode[6]; 417 415 __u16 __user *location; 418 416 int signal = 0; 419 417 420 - location = get_psw_address(regs, pgm_int_code); 418 + location = get_psw_address(regs); 421 419 422 420 if (regs->psw.mask & PSW_MASK_PSTATE) { 423 421 if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) ··· 453 467 * If we get an illegal op in kernel mode, send it through the 454 468 * kprobes notifier. If kprobes doesn't pick it up, SIGILL 455 469 */ 456 - if (notify_die(DIE_BPT, "bpt", regs, pgm_int_code, 470 + if (notify_die(DIE_BPT, "bpt", regs, 0, 457 471 3, SIGTRAP) != NOTIFY_STOP) 458 472 signal = SIGILL; 459 473 } 460 474 461 475 #ifdef CONFIG_MATHEMU 462 476 if (signal == SIGFPE) 463 - do_fp_trap(regs, location, 464 - current->thread.fp_regs.fpc, pgm_int_code); 465 - else if (signal == SIGSEGV) { 466 - info.si_signo = signal; 467 - info.si_errno = 0; 468 - info.si_code = SEGV_MAPERR; 469 - info.si_addr = (void __user *) location; 470 - do_trap(pgm_int_code, signal, 471 - "user address fault", regs, &info); 472 - } else 477 + do_fp_trap(regs, current->thread.fp_regs.fpc); 478 + else if (signal == SIGSEGV) 479 + do_trap(regs, signal, SEGV_MAPERR, "user address fault"); 480 + else 473 481 #endif 474 - if (signal) { 475 - info.si_signo = signal; 476 - info.si_errno = 0; 477 - info.si_code = ILL_ILLOPC; 478 - info.si_addr = (void __user *) location; 479 - do_trap(pgm_int_code, signal, 480 - "illegal operation", regs, &info); 481 - } 482 + if (signal) 483 + do_trap(regs, signal, ILL_ILLOPC, "illegal operation"); 482 484 } 483 485 484 486 485 487 #ifdef CONFIG_MATHEMU 486 - void specification_exception(struct pt_regs *regs, long pgm_int_code, 487 - unsigned long trans_exc_code) 488 + void specification_exception(struct pt_regs *regs) 488 489 { 489 490 __u8 opcode[6]; 490 491 __u16 __user *location = NULL; 491 492 int signal = 0; 492 493 493 - location = (__u16 __user *) get_psw_address(regs, pgm_int_code); 494 + location = (__u16 __user *) get_psw_address(regs); 494 495 495 496 if (regs->psw.mask & PSW_MASK_PSTATE) { 496 497 get_user(*((__u16 *) opcode), location); ··· 512 539 signal = SIGILL; 513 540 514 541 if (signal == SIGFPE) 515 - do_fp_trap(regs, location, 516 - current->thread.fp_regs.fpc, pgm_int_code); 517 - else if (signal) { 518 - siginfo_t info; 519 - info.si_signo = signal; 520 - info.si_errno = 0; 521 - info.si_code = ILL_ILLOPN; 522 - info.si_addr = location; 523 - do_trap(pgm_int_code, signal, 524 - "specification exception", regs, &info); 525 - } 542 + do_fp_trap(regs, current->thread.fp_regs.fpc); 543 + else if (signal) 544 + do_trap(regs, signal, ILL_ILLOPN, "specification exception"); 526 545 } 527 546 #else 528 547 DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN, 529 548 "specification exception"); 530 549 #endif 531 550 532 - static void data_exception(struct pt_regs *regs, long pgm_int_code, 533 - unsigned long trans_exc_code) 551 + static void data_exception(struct pt_regs *regs) 534 552 { 535 553 __u16 __user *location; 536 554 int signal = 0; 537 555 538 - location = get_psw_address(regs, pgm_int_code); 556 + location = get_psw_address(regs); 539 557 540 558 if (MACHINE_HAS_IEEE) 541 559 asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); ··· 591 627 else 592 628 signal = SIGILL; 593 629 if (signal == SIGFPE) 594 - do_fp_trap(regs, location, 595 - current->thread.fp_regs.fpc, pgm_int_code); 596 - else if (signal) { 597 - siginfo_t info; 598 - info.si_signo = signal; 599 - info.si_errno = 0; 600 - info.si_code = ILL_ILLOPN; 601 - info.si_addr = location; 602 - do_trap(pgm_int_code, signal, "data exception", regs, &info); 603 - } 630 + do_fp_trap(regs, current->thread.fp_regs.fpc); 631 + else if (signal) 632 + do_trap(regs, signal, ILL_ILLOPN, "data exception"); 604 633 } 605 634 606 - static void space_switch_exception(struct pt_regs *regs, long pgm_int_code, 607 - unsigned long trans_exc_code) 635 + static void space_switch_exception(struct pt_regs *regs) 608 636 { 609 - siginfo_t info; 610 - 611 637 /* Set user psw back to home space mode. */ 612 638 if (regs->psw.mask & PSW_MASK_PSTATE) 613 639 regs->psw.mask |= PSW_ASC_HOME; 614 640 /* Send SIGILL. */ 615 - info.si_signo = SIGILL; 616 - info.si_errno = 0; 617 - info.si_code = ILL_PRVOPC; 618 - info.si_addr = get_psw_address(regs, pgm_int_code); 619 - do_trap(pgm_int_code, SIGILL, "space switch event", regs, &info); 641 + do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event"); 620 642 } 621 643 622 644 void __kprobes kernel_stack_overflow(struct pt_regs * regs)
+46 -55
arch/s390/mm/fault.c
··· 125 125 return trans_exc_code != 3; 126 126 } 127 127 128 - static inline void report_user_fault(struct pt_regs *regs, long int_code, 129 - int signr, unsigned long address) 128 + static inline void report_user_fault(struct pt_regs *regs, long signr) 130 129 { 131 130 if ((task_pid_nr(current) > 1) && !show_unhandled_signals) 132 131 return; ··· 133 134 return; 134 135 if (!printk_ratelimit()) 135 136 return; 136 - printk("User process fault: interruption code 0x%lX ", int_code); 137 + printk(KERN_ALERT "User process fault: interruption code 0x%X ", 138 + regs->int_code); 137 139 print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN); 138 - printk("\n"); 139 - printk("failing address: %lX\n", address); 140 + printk(KERN_CONT "\n"); 141 + printk(KERN_ALERT "failing address: %lX\n", 142 + regs->int_parm_long & __FAIL_ADDR_MASK); 140 143 show_regs(regs); 141 144 } 142 145 ··· 146 145 * Send SIGSEGV to task. This is an external routine 147 146 * to keep the stack usage of do_page_fault small. 148 147 */ 149 - static noinline void do_sigsegv(struct pt_regs *regs, long int_code, 150 - int si_code, unsigned long trans_exc_code) 148 + static noinline void do_sigsegv(struct pt_regs *regs, int si_code) 151 149 { 152 150 struct siginfo si; 153 - unsigned long address; 154 151 155 - address = trans_exc_code & __FAIL_ADDR_MASK; 156 - current->thread.prot_addr = address; 157 - current->thread.trap_no = int_code; 158 - report_user_fault(regs, int_code, SIGSEGV, address); 152 + report_user_fault(regs, SIGSEGV); 159 153 si.si_signo = SIGSEGV; 160 154 si.si_code = si_code; 161 - si.si_addr = (void __user *) address; 155 + si.si_addr = (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK); 162 156 force_sig_info(SIGSEGV, &si, current); 163 157 } 164 158 165 - static noinline void do_no_context(struct pt_regs *regs, long int_code, 166 - unsigned long trans_exc_code) 159 + static noinline void do_no_context(struct pt_regs *regs) 167 160 { 168 161 const struct exception_table_entry *fixup; 169 162 unsigned long address; ··· 173 178 * Oops. The kernel tried to access some bad page. We'll have to 174 179 * terminate things with extreme prejudice. 175 180 */ 176 - address = trans_exc_code & __FAIL_ADDR_MASK; 177 - if (!user_space_fault(trans_exc_code)) 181 + address = regs->int_parm_long & __FAIL_ADDR_MASK; 182 + if (!user_space_fault(regs->int_parm_long)) 178 183 printk(KERN_ALERT "Unable to handle kernel pointer dereference" 179 184 " at virtual kernel address %p\n", (void *)address); 180 185 else 181 186 printk(KERN_ALERT "Unable to handle kernel paging request" 182 187 " at virtual user address %p\n", (void *)address); 183 188 184 - die("Oops", regs, int_code); 189 + die(regs, "Oops"); 185 190 do_exit(SIGKILL); 186 191 } 187 192 188 - static noinline void do_low_address(struct pt_regs *regs, long int_code, 189 - unsigned long trans_exc_code) 193 + static noinline void do_low_address(struct pt_regs *regs) 190 194 { 191 195 /* Low-address protection hit in kernel mode means 192 196 NULL pointer write access in kernel mode. */ 193 197 if (regs->psw.mask & PSW_MASK_PSTATE) { 194 198 /* Low-address protection hit in user mode 'cannot happen'. */ 195 - die ("Low-address protection", regs, int_code); 199 + die (regs, "Low-address protection"); 196 200 do_exit(SIGKILL); 197 201 } 198 202 199 - do_no_context(regs, int_code, trans_exc_code); 203 + do_no_context(regs); 200 204 } 201 205 202 - static noinline void do_sigbus(struct pt_regs *regs, long int_code, 203 - unsigned long trans_exc_code) 206 + static noinline void do_sigbus(struct pt_regs *regs) 204 207 { 205 208 struct task_struct *tsk = current; 206 - unsigned long address; 207 209 struct siginfo si; 208 210 209 211 /* 210 212 * Send a sigbus, regardless of whether we were in kernel 211 213 * or user mode. 212 214 */ 213 - address = trans_exc_code & __FAIL_ADDR_MASK; 214 - tsk->thread.prot_addr = address; 215 - tsk->thread.trap_no = int_code; 216 215 si.si_signo = SIGBUS; 217 216 si.si_errno = 0; 218 217 si.si_code = BUS_ADRERR; 219 - si.si_addr = (void __user *) address; 218 + si.si_addr = (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK); 220 219 force_sig_info(SIGBUS, &si, tsk); 221 220 } 222 221 223 - static noinline void do_fault_error(struct pt_regs *regs, long int_code, 224 - unsigned long trans_exc_code, int fault) 222 + static noinline void do_fault_error(struct pt_regs *regs, int fault) 225 223 { 226 224 int si_code; 227 225 ··· 226 238 /* User mode accesses just cause a SIGSEGV */ 227 239 si_code = (fault == VM_FAULT_BADMAP) ? 228 240 SEGV_MAPERR : SEGV_ACCERR; 229 - do_sigsegv(regs, int_code, si_code, trans_exc_code); 241 + do_sigsegv(regs, si_code); 230 242 return; 231 243 } 232 244 case VM_FAULT_BADCONTEXT: 233 - do_no_context(regs, int_code, trans_exc_code); 245 + do_no_context(regs); 234 246 break; 235 247 default: /* fault & VM_FAULT_ERROR */ 236 248 if (fault & VM_FAULT_OOM) { 237 249 if (!(regs->psw.mask & PSW_MASK_PSTATE)) 238 - do_no_context(regs, int_code, trans_exc_code); 250 + do_no_context(regs); 239 251 else 240 252 pagefault_out_of_memory(); 241 253 } else if (fault & VM_FAULT_SIGBUS) { 242 254 /* Kernel mode? Handle exceptions or die */ 243 255 if (!(regs->psw.mask & PSW_MASK_PSTATE)) 244 - do_no_context(regs, int_code, trans_exc_code); 256 + do_no_context(regs); 245 257 else 246 - do_sigbus(regs, int_code, trans_exc_code); 258 + do_sigbus(regs); 247 259 } else 248 260 BUG(); 249 261 break; ··· 261 273 * 11 Page translation -> Not present (nullification) 262 274 * 3b Region third trans. -> Not present (nullification) 263 275 */ 264 - static inline int do_exception(struct pt_regs *regs, int access, 265 - unsigned long trans_exc_code) 276 + static inline int do_exception(struct pt_regs *regs, int access) 266 277 { 267 278 struct task_struct *tsk; 268 279 struct mm_struct *mm; 269 280 struct vm_area_struct *vma; 281 + unsigned long trans_exc_code; 270 282 unsigned long address; 271 283 unsigned int flags; 272 284 int fault; ··· 276 288 277 289 tsk = current; 278 290 mm = tsk->mm; 291 + trans_exc_code = regs->int_parm_long; 279 292 280 293 /* 281 294 * Verify that the fault happened in user space, that ··· 376 387 return fault; 377 388 } 378 389 379 - void __kprobes do_protection_exception(struct pt_regs *regs, long pgm_int_code, 380 - unsigned long trans_exc_code) 390 + void __kprobes do_protection_exception(struct pt_regs *regs) 381 391 { 392 + unsigned long trans_exc_code; 382 393 int fault; 383 394 395 + trans_exc_code = regs->int_parm_long; 384 396 /* Protection exception is suppressing, decrement psw address. */ 385 - regs->psw.addr = __rewind_psw(regs->psw, pgm_int_code >> 16); 397 + regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16); 386 398 /* 387 399 * Check for low-address protection. This needs to be treated 388 400 * as a special case because the translation exception code 389 401 * field is not guaranteed to contain valid data in this case. 390 402 */ 391 403 if (unlikely(!(trans_exc_code & 4))) { 392 - do_low_address(regs, pgm_int_code, trans_exc_code); 404 + do_low_address(regs); 393 405 return; 394 406 } 395 - fault = do_exception(regs, VM_WRITE, trans_exc_code); 407 + fault = do_exception(regs, VM_WRITE); 396 408 if (unlikely(fault)) 397 - do_fault_error(regs, 4, trans_exc_code, fault); 409 + do_fault_error(regs, fault); 398 410 } 399 411 400 - void __kprobes do_dat_exception(struct pt_regs *regs, long pgm_int_code, 401 - unsigned long trans_exc_code) 412 + void __kprobes do_dat_exception(struct pt_regs *regs) 402 413 { 403 414 int access, fault; 404 415 405 416 access = VM_READ | VM_EXEC | VM_WRITE; 406 - fault = do_exception(regs, access, trans_exc_code); 417 + fault = do_exception(regs, access); 407 418 if (unlikely(fault)) 408 - do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault); 419 + do_fault_error(regs, fault); 409 420 } 410 421 411 422 #ifdef CONFIG_64BIT 412 - void __kprobes do_asce_exception(struct pt_regs *regs, long pgm_int_code, 413 - unsigned long trans_exc_code) 423 + void __kprobes do_asce_exception(struct pt_regs *regs) 414 424 { 415 425 struct mm_struct *mm = current->mm; 416 426 struct vm_area_struct *vma; 427 + unsigned long trans_exc_code; 417 428 429 + trans_exc_code = regs->int_parm_long; 418 430 if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm)) 419 431 goto no_context; 420 432 ··· 430 440 431 441 /* User mode accesses just cause a SIGSEGV */ 432 442 if (regs->psw.mask & PSW_MASK_PSTATE) { 433 - do_sigsegv(regs, pgm_int_code, SEGV_MAPERR, trans_exc_code); 443 + do_sigsegv(regs, SEGV_MAPERR); 434 444 return; 435 445 } 436 446 437 447 no_context: 438 - do_no_context(regs, pgm_int_code, trans_exc_code); 448 + do_no_context(regs); 439 449 } 440 450 #endif 441 451 ··· 449 459 regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT; 450 460 regs.psw.addr = (unsigned long) __builtin_return_address(0); 451 461 regs.psw.addr |= PSW_ADDR_AMODE; 452 - uaddr &= PAGE_MASK; 462 + regs.int_code = pgm_int_code; 463 + regs.int_parm_long = (uaddr & PAGE_MASK) | 2; 453 464 access = write ? VM_WRITE : VM_READ; 454 - fault = do_exception(&regs, access, uaddr | 2); 465 + fault = do_exception(&regs, access); 455 466 if (unlikely(fault)) { 456 467 if (fault & VM_FAULT_OOM) 457 468 return -EFAULT; 458 469 else if (fault & VM_FAULT_SIGBUS) 459 - do_sigbus(&regs, pgm_int_code, uaddr); 470 + do_sigbus(&regs); 460 471 } 461 472 return fault ? -EFAULT : 0; 462 473 }