diff options
Diffstat (limited to 'arch/sparc64/kernel/process.c')
-rw-r--r-- | arch/sparc64/kernel/process.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 26548fc604b6..803eea4dc4ff 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c | |||
@@ -541,6 +541,18 @@ void synchronize_user_stack(void) | |||
541 | } | 541 | } |
542 | } | 542 | } |
543 | 543 | ||
544 | static void stack_unaligned(unsigned long sp) | ||
545 | { | ||
546 | siginfo_t info; | ||
547 | |||
548 | info.si_signo = SIGBUS; | ||
549 | info.si_errno = 0; | ||
550 | info.si_code = BUS_ADRALN; | ||
551 | info.si_addr = (void __user *) sp; | ||
552 | info.si_trapno = 0; | ||
553 | force_sig_info(SIGBUS, &info, current); | ||
554 | } | ||
555 | |||
544 | void fault_in_user_windows(void) | 556 | void fault_in_user_windows(void) |
545 | { | 557 | { |
546 | struct thread_info *t = current_thread_info(); | 558 | struct thread_info *t = current_thread_info(); |
@@ -556,13 +568,17 @@ void fault_in_user_windows(void) | |||
556 | flush_user_windows(); | 568 | flush_user_windows(); |
557 | window = get_thread_wsaved(); | 569 | window = get_thread_wsaved(); |
558 | 570 | ||
559 | if (window != 0) { | 571 | if (likely(window != 0)) { |
560 | window -= 1; | 572 | window -= 1; |
561 | do { | 573 | do { |
562 | unsigned long sp = (t->rwbuf_stkptrs[window] + bias); | 574 | unsigned long sp = (t->rwbuf_stkptrs[window] + bias); |
563 | struct reg_window *rwin = &t->reg_window[window]; | 575 | struct reg_window *rwin = &t->reg_window[window]; |
564 | 576 | ||
565 | if (copy_to_user((char __user *)sp, rwin, winsize)) | 577 | if (unlikely(sp & 0x7UL)) |
578 | stack_unaligned(sp); | ||
579 | |||
580 | if (unlikely(copy_to_user((char __user *)sp, | ||
581 | rwin, winsize))) | ||
566 | goto barf; | 582 | goto barf; |
567 | } while (window--); | 583 | } while (window--); |
568 | } | 584 | } |