diff options
-rw-r--r-- | arch/sparc/include/asm/compat.h | 5 | ||||
-rw-r--r-- | arch/sparc/include/asm/thread_info_64.h | 5 | ||||
-rw-r--r-- | arch/sparc/include/asm/ttable.h | 24 | ||||
-rw-r--r-- | arch/sparc/include/uapi/asm/unistd.h | 6 | ||||
-rw-r--r-- | arch/sparc/kernel/perf_event.c | 22 | ||||
-rw-r--r-- | arch/sparc/kernel/process_64.c | 42 | ||||
-rw-r--r-- | arch/sparc/kernel/ptrace_64.c | 4 | ||||
-rw-r--r-- | arch/sparc/kernel/sys_sparc_64.c | 5 | ||||
-rw-r--r-- | arch/sparc/kernel/systbls_64.S | 2 | ||||
-rw-r--r-- | arch/sparc/kernel/unaligned_64.c | 36 | ||||
-rw-r--r-- | arch/sparc/kernel/visemul.c | 23 | ||||
-rw-r--r-- | arch/sparc/kernel/winfixup.S | 2 | ||||
-rw-r--r-- | arch/sparc/math-emu/math_64.c | 2 |
13 files changed, 117 insertions, 61 deletions
diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h index cef99fbc0a21..830502fe62b4 100644 --- a/arch/sparc/include/asm/compat.h +++ b/arch/sparc/include/asm/compat.h | |||
@@ -232,9 +232,10 @@ static inline void __user *arch_compat_alloc_user_space(long len) | |||
232 | struct pt_regs *regs = current_thread_info()->kregs; | 232 | struct pt_regs *regs = current_thread_info()->kregs; |
233 | unsigned long usp = regs->u_regs[UREG_I6]; | 233 | unsigned long usp = regs->u_regs[UREG_I6]; |
234 | 234 | ||
235 | if (!(test_thread_flag(TIF_32BIT))) | 235 | if (test_thread_64bit_stack(usp)) |
236 | usp += STACK_BIAS; | 236 | usp += STACK_BIAS; |
237 | else | 237 | |
238 | if (test_thread_flag(TIF_32BIT)) | ||
238 | usp &= 0xffffffffUL; | 239 | usp &= 0xffffffffUL; |
239 | 240 | ||
240 | usp -= len; | 241 | usp -= len; |
diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h index 4e2276631081..a3fe4dcc0aa6 100644 --- a/arch/sparc/include/asm/thread_info_64.h +++ b/arch/sparc/include/asm/thread_info_64.h | |||
@@ -259,6 +259,11 @@ static inline bool test_and_clear_restore_sigmask(void) | |||
259 | 259 | ||
260 | #define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) | 260 | #define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) |
261 | 261 | ||
262 | #define thread32_stack_is_64bit(__SP) (((__SP) & 0x1) != 0) | ||
263 | #define test_thread_64bit_stack(__SP) \ | ||
264 | ((test_thread_flag(TIF_32BIT) && !thread32_stack_is_64bit(__SP)) ? \ | ||
265 | false : true) | ||
266 | |||
262 | #endif /* !__ASSEMBLY__ */ | 267 | #endif /* !__ASSEMBLY__ */ |
263 | 268 | ||
264 | #endif /* __KERNEL__ */ | 269 | #endif /* __KERNEL__ */ |
diff --git a/arch/sparc/include/asm/ttable.h b/arch/sparc/include/asm/ttable.h index 48f2807d3265..71b5a67522ab 100644 --- a/arch/sparc/include/asm/ttable.h +++ b/arch/sparc/include/asm/ttable.h | |||
@@ -372,7 +372,9 @@ etrap_spill_fixup_64bit: \ | |||
372 | 372 | ||
373 | /* Normal 32bit spill */ | 373 | /* Normal 32bit spill */ |
374 | #define SPILL_2_GENERIC(ASI) \ | 374 | #define SPILL_2_GENERIC(ASI) \ |
375 | srl %sp, 0, %sp; \ | 375 | and %sp, 1, %g3; \ |
376 | brnz,pn %g3, (. - (128 + 4)); \ | ||
377 | srl %sp, 0, %sp; \ | ||
376 | stwa %l0, [%sp + %g0] ASI; \ | 378 | stwa %l0, [%sp + %g0] ASI; \ |
377 | mov 0x04, %g3; \ | 379 | mov 0x04, %g3; \ |
378 | stwa %l1, [%sp + %g3] ASI; \ | 380 | stwa %l1, [%sp + %g3] ASI; \ |
@@ -398,14 +400,16 @@ etrap_spill_fixup_64bit: \ | |||
398 | stwa %i6, [%g1 + %g0] ASI; \ | 400 | stwa %i6, [%g1 + %g0] ASI; \ |
399 | stwa %i7, [%g1 + %g3] ASI; \ | 401 | stwa %i7, [%g1 + %g3] ASI; \ |
400 | saved; \ | 402 | saved; \ |
401 | retry; nop; nop; \ | 403 | retry; \ |
402 | b,a,pt %xcc, spill_fixup_dax; \ | 404 | b,a,pt %xcc, spill_fixup_dax; \ |
403 | b,a,pt %xcc, spill_fixup_mna; \ | 405 | b,a,pt %xcc, spill_fixup_mna; \ |
404 | b,a,pt %xcc, spill_fixup; | 406 | b,a,pt %xcc, spill_fixup; |
405 | 407 | ||
406 | #define SPILL_2_GENERIC_ETRAP \ | 408 | #define SPILL_2_GENERIC_ETRAP \ |
407 | etrap_user_spill_32bit: \ | 409 | etrap_user_spill_32bit: \ |
408 | srl %sp, 0, %sp; \ | 410 | and %sp, 1, %g3; \ |
411 | brnz,pn %g3, etrap_user_spill_64bit; \ | ||
412 | srl %sp, 0, %sp; \ | ||
409 | stwa %l0, [%sp + 0x00] %asi; \ | 413 | stwa %l0, [%sp + 0x00] %asi; \ |
410 | stwa %l1, [%sp + 0x04] %asi; \ | 414 | stwa %l1, [%sp + 0x04] %asi; \ |
411 | stwa %l2, [%sp + 0x08] %asi; \ | 415 | stwa %l2, [%sp + 0x08] %asi; \ |
@@ -427,7 +431,7 @@ etrap_user_spill_32bit: \ | |||
427 | ba,pt %xcc, etrap_save; \ | 431 | ba,pt %xcc, etrap_save; \ |
428 | wrpr %g1, %cwp; \ | 432 | wrpr %g1, %cwp; \ |
429 | nop; nop; nop; nop; \ | 433 | nop; nop; nop; nop; \ |
430 | nop; nop; nop; nop; \ | 434 | nop; nop; \ |
431 | ba,a,pt %xcc, etrap_spill_fixup_32bit; \ | 435 | ba,a,pt %xcc, etrap_spill_fixup_32bit; \ |
432 | ba,a,pt %xcc, etrap_spill_fixup_32bit; \ | 436 | ba,a,pt %xcc, etrap_spill_fixup_32bit; \ |
433 | ba,a,pt %xcc, etrap_spill_fixup_32bit; | 437 | ba,a,pt %xcc, etrap_spill_fixup_32bit; |
@@ -592,7 +596,9 @@ user_rtt_fill_64bit: \ | |||
592 | 596 | ||
593 | /* Normal 32bit fill */ | 597 | /* Normal 32bit fill */ |
594 | #define FILL_2_GENERIC(ASI) \ | 598 | #define FILL_2_GENERIC(ASI) \ |
595 | srl %sp, 0, %sp; \ | 599 | and %sp, 1, %g3; \ |
600 | brnz,pn %g3, (. - (128 + 4)); \ | ||
601 | srl %sp, 0, %sp; \ | ||
596 | lduwa [%sp + %g0] ASI, %l0; \ | 602 | lduwa [%sp + %g0] ASI, %l0; \ |
597 | mov 0x04, %g2; \ | 603 | mov 0x04, %g2; \ |
598 | mov 0x08, %g3; \ | 604 | mov 0x08, %g3; \ |
@@ -616,14 +622,16 @@ user_rtt_fill_64bit: \ | |||
616 | lduwa [%g1 + %g3] ASI, %i6; \ | 622 | lduwa [%g1 + %g3] ASI, %i6; \ |
617 | lduwa [%g1 + %g5] ASI, %i7; \ | 623 | lduwa [%g1 + %g5] ASI, %i7; \ |
618 | restored; \ | 624 | restored; \ |
619 | retry; nop; nop; nop; nop; \ | 625 | retry; nop; nop; \ |
620 | b,a,pt %xcc, fill_fixup_dax; \ | 626 | b,a,pt %xcc, fill_fixup_dax; \ |
621 | b,a,pt %xcc, fill_fixup_mna; \ | 627 | b,a,pt %xcc, fill_fixup_mna; \ |
622 | b,a,pt %xcc, fill_fixup; | 628 | b,a,pt %xcc, fill_fixup; |
623 | 629 | ||
624 | #define FILL_2_GENERIC_RTRAP \ | 630 | #define FILL_2_GENERIC_RTRAP \ |
625 | user_rtt_fill_32bit: \ | 631 | user_rtt_fill_32bit: \ |
626 | srl %sp, 0, %sp; \ | 632 | and %sp, 1, %g3; \ |
633 | brnz,pn %g3, user_rtt_fill_64bit; \ | ||
634 | srl %sp, 0, %sp; \ | ||
627 | lduwa [%sp + 0x00] %asi, %l0; \ | 635 | lduwa [%sp + 0x00] %asi, %l0; \ |
628 | lduwa [%sp + 0x04] %asi, %l1; \ | 636 | lduwa [%sp + 0x04] %asi, %l1; \ |
629 | lduwa [%sp + 0x08] %asi, %l2; \ | 637 | lduwa [%sp + 0x08] %asi, %l2; \ |
@@ -643,7 +651,7 @@ user_rtt_fill_32bit: \ | |||
643 | ba,pt %xcc, user_rtt_pre_restore; \ | 651 | ba,pt %xcc, user_rtt_pre_restore; \ |
644 | restored; \ | 652 | restored; \ |
645 | nop; nop; nop; nop; nop; \ | 653 | nop; nop; nop; nop; nop; \ |
646 | nop; nop; nop; nop; nop; \ | 654 | nop; nop; nop; \ |
647 | ba,a,pt %xcc, user_rtt_fill_fixup; \ | 655 | ba,a,pt %xcc, user_rtt_fill_fixup; \ |
648 | ba,a,pt %xcc, user_rtt_fill_fixup; \ | 656 | ba,a,pt %xcc, user_rtt_fill_fixup; \ |
649 | ba,a,pt %xcc, user_rtt_fill_fixup; | 657 | ba,a,pt %xcc, user_rtt_fill_fixup; |
diff --git a/arch/sparc/include/uapi/asm/unistd.h b/arch/sparc/include/uapi/asm/unistd.h index 8974ef7ae920..bed86a820d09 100644 --- a/arch/sparc/include/uapi/asm/unistd.h +++ b/arch/sparc/include/uapi/asm/unistd.h | |||
@@ -405,8 +405,12 @@ | |||
405 | #define __NR_setns 337 | 405 | #define __NR_setns 337 |
406 | #define __NR_process_vm_readv 338 | 406 | #define __NR_process_vm_readv 338 |
407 | #define __NR_process_vm_writev 339 | 407 | #define __NR_process_vm_writev 339 |
408 | #define __NR_kern_features 340 | ||
408 | 409 | ||
409 | #define NR_syscalls 340 | 410 | #define NR_syscalls 341 |
411 | |||
412 | /* Bitmask values returned from kern_features system call. */ | ||
413 | #define KERN_FEATURE_MIXED_MODE_STACK 0x00000001 | ||
410 | 414 | ||
411 | #ifdef __32bit_syscall_numbers__ | 415 | #ifdef __32bit_syscall_numbers__ |
412 | /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants, | 416 | /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants, |
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 885a8af74064..b5c38faa4ead 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c | |||
@@ -1762,15 +1762,25 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry, | |||
1762 | 1762 | ||
1763 | ufp = regs->u_regs[UREG_I6] & 0xffffffffUL; | 1763 | ufp = regs->u_regs[UREG_I6] & 0xffffffffUL; |
1764 | do { | 1764 | do { |
1765 | struct sparc_stackf32 *usf, sf; | ||
1766 | unsigned long pc; | 1765 | unsigned long pc; |
1767 | 1766 | ||
1768 | usf = (struct sparc_stackf32 *) ufp; | 1767 | if (thread32_stack_is_64bit(ufp)) { |
1769 | if (__copy_from_user_inatomic(&sf, usf, sizeof(sf))) | 1768 | struct sparc_stackf *usf, sf; |
1770 | break; | ||
1771 | 1769 | ||
1772 | pc = sf.callers_pc; | 1770 | ufp += STACK_BIAS; |
1773 | ufp = (unsigned long)sf.fp; | 1771 | usf = (struct sparc_stackf *) ufp; |
1772 | if (__copy_from_user_inatomic(&sf, usf, sizeof(sf))) | ||
1773 | break; | ||
1774 | pc = sf.callers_pc & 0xffffffff; | ||
1775 | ufp = ((unsigned long) sf.fp) & 0xffffffff; | ||
1776 | } else { | ||
1777 | struct sparc_stackf32 *usf, sf; | ||
1778 | usf = (struct sparc_stackf32 *) ufp; | ||
1779 | if (__copy_from_user_inatomic(&sf, usf, sizeof(sf))) | ||
1780 | break; | ||
1781 | pc = sf.callers_pc; | ||
1782 | ufp = (unsigned long)sf.fp; | ||
1783 | } | ||
1774 | perf_callchain_store(entry, pc); | 1784 | perf_callchain_store(entry, pc); |
1775 | } while (entry->nr < PERF_MAX_STACK_DEPTH); | 1785 | } while (entry->nr < PERF_MAX_STACK_DEPTH); |
1776 | } | 1786 | } |
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index d778248ef3f8..c6e0c2910043 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c | |||
@@ -452,13 +452,16 @@ void flush_thread(void) | |||
452 | /* It's a bit more tricky when 64-bit tasks are involved... */ | 452 | /* It's a bit more tricky when 64-bit tasks are involved... */ |
453 | static unsigned long clone_stackframe(unsigned long csp, unsigned long psp) | 453 | static unsigned long clone_stackframe(unsigned long csp, unsigned long psp) |
454 | { | 454 | { |
455 | bool stack_64bit = test_thread_64bit_stack(psp); | ||
455 | unsigned long fp, distance, rval; | 456 | unsigned long fp, distance, rval; |
456 | 457 | ||
457 | if (!(test_thread_flag(TIF_32BIT))) { | 458 | if (stack_64bit) { |
458 | csp += STACK_BIAS; | 459 | csp += STACK_BIAS; |
459 | psp += STACK_BIAS; | 460 | psp += STACK_BIAS; |
460 | __get_user(fp, &(((struct reg_window __user *)psp)->ins[6])); | 461 | __get_user(fp, &(((struct reg_window __user *)psp)->ins[6])); |
461 | fp += STACK_BIAS; | 462 | fp += STACK_BIAS; |
463 | if (test_thread_flag(TIF_32BIT)) | ||
464 | fp &= 0xffffffff; | ||
462 | } else | 465 | } else |
463 | __get_user(fp, &(((struct reg_window32 __user *)psp)->ins[6])); | 466 | __get_user(fp, &(((struct reg_window32 __user *)psp)->ins[6])); |
464 | 467 | ||
@@ -472,7 +475,7 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp) | |||
472 | rval = (csp - distance); | 475 | rval = (csp - distance); |
473 | if (copy_in_user((void __user *) rval, (void __user *) psp, distance)) | 476 | if (copy_in_user((void __user *) rval, (void __user *) psp, distance)) |
474 | rval = 0; | 477 | rval = 0; |
475 | else if (test_thread_flag(TIF_32BIT)) { | 478 | else if (!stack_64bit) { |
476 | if (put_user(((u32)csp), | 479 | if (put_user(((u32)csp), |
477 | &(((struct reg_window32 __user *)rval)->ins[6]))) | 480 | &(((struct reg_window32 __user *)rval)->ins[6]))) |
478 | rval = 0; | 481 | rval = 0; |
@@ -507,18 +510,18 @@ void synchronize_user_stack(void) | |||
507 | 510 | ||
508 | flush_user_windows(); | 511 | flush_user_windows(); |
509 | if ((window = get_thread_wsaved()) != 0) { | 512 | if ((window = get_thread_wsaved()) != 0) { |
510 | int winsize = sizeof(struct reg_window); | ||
511 | int bias = 0; | ||
512 | |||
513 | if (test_thread_flag(TIF_32BIT)) | ||
514 | winsize = sizeof(struct reg_window32); | ||
515 | else | ||
516 | bias = STACK_BIAS; | ||
517 | |||
518 | window -= 1; | 513 | window -= 1; |
519 | do { | 514 | do { |
520 | unsigned long sp = (t->rwbuf_stkptrs[window] + bias); | ||
521 | struct reg_window *rwin = &t->reg_window[window]; | 515 | struct reg_window *rwin = &t->reg_window[window]; |
516 | int winsize = sizeof(struct reg_window); | ||
517 | unsigned long sp; | ||
518 | |||
519 | sp = t->rwbuf_stkptrs[window]; | ||
520 | |||
521 | if (test_thread_64bit_stack(sp)) | ||
522 | sp += STACK_BIAS; | ||
523 | else | ||
524 | winsize = sizeof(struct reg_window32); | ||
522 | 525 | ||
523 | if (!copy_to_user((char __user *)sp, rwin, winsize)) { | 526 | if (!copy_to_user((char __user *)sp, rwin, winsize)) { |
524 | shift_window_buffer(window, get_thread_wsaved() - 1, t); | 527 | shift_window_buffer(window, get_thread_wsaved() - 1, t); |
@@ -544,13 +547,6 @@ void fault_in_user_windows(void) | |||
544 | { | 547 | { |
545 | struct thread_info *t = current_thread_info(); | 548 | struct thread_info *t = current_thread_info(); |
546 | unsigned long window; | 549 | unsigned long window; |
547 | int winsize = sizeof(struct reg_window); | ||
548 | int bias = 0; | ||
549 | |||
550 | if (test_thread_flag(TIF_32BIT)) | ||
551 | winsize = sizeof(struct reg_window32); | ||
552 | else | ||
553 | bias = STACK_BIAS; | ||
554 | 550 | ||
555 | flush_user_windows(); | 551 | flush_user_windows(); |
556 | window = get_thread_wsaved(); | 552 | window = get_thread_wsaved(); |
@@ -558,8 +554,16 @@ void fault_in_user_windows(void) | |||
558 | if (likely(window != 0)) { | 554 | if (likely(window != 0)) { |
559 | window -= 1; | 555 | window -= 1; |
560 | do { | 556 | do { |
561 | unsigned long sp = (t->rwbuf_stkptrs[window] + bias); | ||
562 | struct reg_window *rwin = &t->reg_window[window]; | 557 | struct reg_window *rwin = &t->reg_window[window]; |
558 | int winsize = sizeof(struct reg_window); | ||
559 | unsigned long sp; | ||
560 | |||
561 | sp = t->rwbuf_stkptrs[window]; | ||
562 | |||
563 | if (test_thread_64bit_stack(sp)) | ||
564 | sp += STACK_BIAS; | ||
565 | else | ||
566 | winsize = sizeof(struct reg_window32); | ||
563 | 567 | ||
564 | if (unlikely(sp & 0x7UL)) | 568 | if (unlikely(sp & 0x7UL)) |
565 | stack_unaligned(sp); | 569 | stack_unaligned(sp); |
diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c index 484dabac7045..7ff45e4ba681 100644 --- a/arch/sparc/kernel/ptrace_64.c +++ b/arch/sparc/kernel/ptrace_64.c | |||
@@ -151,7 +151,7 @@ static int regwindow64_get(struct task_struct *target, | |||
151 | { | 151 | { |
152 | unsigned long rw_addr = regs->u_regs[UREG_I6]; | 152 | unsigned long rw_addr = regs->u_regs[UREG_I6]; |
153 | 153 | ||
154 | if (test_tsk_thread_flag(current, TIF_32BIT)) { | 154 | if (!test_thread_64bit_stack(rw_addr)) { |
155 | struct reg_window32 win32; | 155 | struct reg_window32 win32; |
156 | int i; | 156 | int i; |
157 | 157 | ||
@@ -176,7 +176,7 @@ static int regwindow64_set(struct task_struct *target, | |||
176 | { | 176 | { |
177 | unsigned long rw_addr = regs->u_regs[UREG_I6]; | 177 | unsigned long rw_addr = regs->u_regs[UREG_I6]; |
178 | 178 | ||
179 | if (test_tsk_thread_flag(current, TIF_32BIT)) { | 179 | if (!test_thread_64bit_stack(rw_addr)) { |
180 | struct reg_window32 win32; | 180 | struct reg_window32 win32; |
181 | int i; | 181 | int i; |
182 | 182 | ||
diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 11c6c9603e71..878ef3d5fec5 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c | |||
@@ -751,3 +751,8 @@ int kernel_execve(const char *filename, | |||
751 | : "cc"); | 751 | : "cc"); |
752 | return __res; | 752 | return __res; |
753 | } | 753 | } |
754 | |||
755 | asmlinkage long sys_kern_features(void) | ||
756 | { | ||
757 | return KERN_FEATURE_MIXED_MODE_STACK; | ||
758 | } | ||
diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 3a58e0d66f51..45ce6be088e4 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S | |||
@@ -86,6 +86,7 @@ sys_call_table32: | |||
86 | .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init | 86 | .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init |
87 | /*330*/ .word sys32_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime | 87 | /*330*/ .word sys32_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime |
88 | .word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev | 88 | .word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev |
89 | /*340*/ .word sys_kern_features | ||
89 | 90 | ||
90 | #endif /* CONFIG_COMPAT */ | 91 | #endif /* CONFIG_COMPAT */ |
91 | 92 | ||
@@ -163,3 +164,4 @@ sys_call_table: | |||
163 | .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init | 164 | .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init |
164 | /*330*/ .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime | 165 | /*330*/ .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime |
165 | .word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev | 166 | .word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev |
167 | /*340*/ .word sys_kern_features | ||
diff --git a/arch/sparc/kernel/unaligned_64.c b/arch/sparc/kernel/unaligned_64.c index f81d038f7340..8201c25e7669 100644 --- a/arch/sparc/kernel/unaligned_64.c +++ b/arch/sparc/kernel/unaligned_64.c | |||
@@ -113,21 +113,24 @@ static inline long sign_extend_imm13(long imm) | |||
113 | 113 | ||
114 | static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs) | 114 | static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs) |
115 | { | 115 | { |
116 | unsigned long value; | 116 | unsigned long value, fp; |
117 | 117 | ||
118 | if (reg < 16) | 118 | if (reg < 16) |
119 | return (!reg ? 0 : regs->u_regs[reg]); | 119 | return (!reg ? 0 : regs->u_regs[reg]); |
120 | |||
121 | fp = regs->u_regs[UREG_FP]; | ||
122 | |||
120 | if (regs->tstate & TSTATE_PRIV) { | 123 | if (regs->tstate & TSTATE_PRIV) { |
121 | struct reg_window *win; | 124 | struct reg_window *win; |
122 | win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); | 125 | win = (struct reg_window *)(fp + STACK_BIAS); |
123 | value = win->locals[reg - 16]; | 126 | value = win->locals[reg - 16]; |
124 | } else if (test_thread_flag(TIF_32BIT)) { | 127 | } else if (!test_thread_64bit_stack(fp)) { |
125 | struct reg_window32 __user *win32; | 128 | struct reg_window32 __user *win32; |
126 | win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP])); | 129 | win32 = (struct reg_window32 __user *)((unsigned long)((u32)fp)); |
127 | get_user(value, &win32->locals[reg - 16]); | 130 | get_user(value, &win32->locals[reg - 16]); |
128 | } else { | 131 | } else { |
129 | struct reg_window __user *win; | 132 | struct reg_window __user *win; |
130 | win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS); | 133 | win = (struct reg_window __user *)(fp + STACK_BIAS); |
131 | get_user(value, &win->locals[reg - 16]); | 134 | get_user(value, &win->locals[reg - 16]); |
132 | } | 135 | } |
133 | return value; | 136 | return value; |
@@ -135,19 +138,24 @@ static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs) | |||
135 | 138 | ||
136 | static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs) | 139 | static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs) |
137 | { | 140 | { |
141 | unsigned long fp; | ||
142 | |||
138 | if (reg < 16) | 143 | if (reg < 16) |
139 | return ®s->u_regs[reg]; | 144 | return ®s->u_regs[reg]; |
145 | |||
146 | fp = regs->u_regs[UREG_FP]; | ||
147 | |||
140 | if (regs->tstate & TSTATE_PRIV) { | 148 | if (regs->tstate & TSTATE_PRIV) { |
141 | struct reg_window *win; | 149 | struct reg_window *win; |
142 | win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); | 150 | win = (struct reg_window *)(fp + STACK_BIAS); |
143 | return &win->locals[reg - 16]; | 151 | return &win->locals[reg - 16]; |
144 | } else if (test_thread_flag(TIF_32BIT)) { | 152 | } else if (!test_thread_64bit_stack(fp)) { |
145 | struct reg_window32 *win32; | 153 | struct reg_window32 *win32; |
146 | win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP])); | 154 | win32 = (struct reg_window32 *)((unsigned long)((u32)fp)); |
147 | return (unsigned long *)&win32->locals[reg - 16]; | 155 | return (unsigned long *)&win32->locals[reg - 16]; |
148 | } else { | 156 | } else { |
149 | struct reg_window *win; | 157 | struct reg_window *win; |
150 | win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); | 158 | win = (struct reg_window *)(fp + STACK_BIAS); |
151 | return &win->locals[reg - 16]; | 159 | return &win->locals[reg - 16]; |
152 | } | 160 | } |
153 | } | 161 | } |
@@ -392,13 +400,15 @@ int handle_popc(u32 insn, struct pt_regs *regs) | |||
392 | if (rd) | 400 | if (rd) |
393 | regs->u_regs[rd] = ret; | 401 | regs->u_regs[rd] = ret; |
394 | } else { | 402 | } else { |
395 | if (test_thread_flag(TIF_32BIT)) { | 403 | unsigned long fp = regs->u_regs[UREG_FP]; |
404 | |||
405 | if (!test_thread_64bit_stack(fp)) { | ||
396 | struct reg_window32 __user *win32; | 406 | struct reg_window32 __user *win32; |
397 | win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP])); | 407 | win32 = (struct reg_window32 __user *)((unsigned long)((u32)fp)); |
398 | put_user(ret, &win32->locals[rd - 16]); | 408 | put_user(ret, &win32->locals[rd - 16]); |
399 | } else { | 409 | } else { |
400 | struct reg_window __user *win; | 410 | struct reg_window __user *win; |
401 | win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS); | 411 | win = (struct reg_window __user *)(fp + STACK_BIAS); |
402 | put_user(ret, &win->locals[rd - 16]); | 412 | put_user(ret, &win->locals[rd - 16]); |
403 | } | 413 | } |
404 | } | 414 | } |
@@ -554,7 +564,7 @@ void handle_ld_nf(u32 insn, struct pt_regs *regs) | |||
554 | reg[0] = 0; | 564 | reg[0] = 0; |
555 | if ((insn & 0x780000) == 0x180000) | 565 | if ((insn & 0x780000) == 0x180000) |
556 | reg[1] = 0; | 566 | reg[1] = 0; |
557 | } else if (test_thread_flag(TIF_32BIT)) { | 567 | } else if (!test_thread_64bit_stack(regs->u_regs[UREG_FP])) { |
558 | put_user(0, (int __user *) reg); | 568 | put_user(0, (int __user *) reg); |
559 | if ((insn & 0x780000) == 0x180000) | 569 | if ((insn & 0x780000) == 0x180000) |
560 | put_user(0, ((int __user *) reg) + 1); | 570 | put_user(0, ((int __user *) reg) + 1); |
diff --git a/arch/sparc/kernel/visemul.c b/arch/sparc/kernel/visemul.c index 08e074b7eb6a..c096c624ac4d 100644 --- a/arch/sparc/kernel/visemul.c +++ b/arch/sparc/kernel/visemul.c | |||
@@ -149,21 +149,24 @@ static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2, | |||
149 | 149 | ||
150 | static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs) | 150 | static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs) |
151 | { | 151 | { |
152 | unsigned long value; | 152 | unsigned long value, fp; |
153 | 153 | ||
154 | if (reg < 16) | 154 | if (reg < 16) |
155 | return (!reg ? 0 : regs->u_regs[reg]); | 155 | return (!reg ? 0 : regs->u_regs[reg]); |
156 | |||
157 | fp = regs->u_regs[UREG_FP]; | ||
158 | |||
156 | if (regs->tstate & TSTATE_PRIV) { | 159 | if (regs->tstate & TSTATE_PRIV) { |
157 | struct reg_window *win; | 160 | struct reg_window *win; |
158 | win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); | 161 | win = (struct reg_window *)(fp + STACK_BIAS); |
159 | value = win->locals[reg - 16]; | 162 | value = win->locals[reg - 16]; |
160 | } else if (test_thread_flag(TIF_32BIT)) { | 163 | } else if (!test_thread_64bit_stack(fp)) { |
161 | struct reg_window32 __user *win32; | 164 | struct reg_window32 __user *win32; |
162 | win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP])); | 165 | win32 = (struct reg_window32 __user *)((unsigned long)((u32)fp)); |
163 | get_user(value, &win32->locals[reg - 16]); | 166 | get_user(value, &win32->locals[reg - 16]); |
164 | } else { | 167 | } else { |
165 | struct reg_window __user *win; | 168 | struct reg_window __user *win; |
166 | win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS); | 169 | win = (struct reg_window __user *)(fp + STACK_BIAS); |
167 | get_user(value, &win->locals[reg - 16]); | 170 | get_user(value, &win->locals[reg - 16]); |
168 | } | 171 | } |
169 | return value; | 172 | return value; |
@@ -172,16 +175,18 @@ static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs) | |||
172 | static inline unsigned long __user *__fetch_reg_addr_user(unsigned int reg, | 175 | static inline unsigned long __user *__fetch_reg_addr_user(unsigned int reg, |
173 | struct pt_regs *regs) | 176 | struct pt_regs *regs) |
174 | { | 177 | { |
178 | unsigned long fp = regs->u_regs[UREG_FP]; | ||
179 | |||
175 | BUG_ON(reg < 16); | 180 | BUG_ON(reg < 16); |
176 | BUG_ON(regs->tstate & TSTATE_PRIV); | 181 | BUG_ON(regs->tstate & TSTATE_PRIV); |
177 | 182 | ||
178 | if (test_thread_flag(TIF_32BIT)) { | 183 | if (!test_thread_64bit_stack(fp)) { |
179 | struct reg_window32 __user *win32; | 184 | struct reg_window32 __user *win32; |
180 | win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP])); | 185 | win32 = (struct reg_window32 __user *)((unsigned long)((u32)fp)); |
181 | return (unsigned long __user *)&win32->locals[reg - 16]; | 186 | return (unsigned long __user *)&win32->locals[reg - 16]; |
182 | } else { | 187 | } else { |
183 | struct reg_window __user *win; | 188 | struct reg_window __user *win; |
184 | win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS); | 189 | win = (struct reg_window __user *)(fp + STACK_BIAS); |
185 | return &win->locals[reg - 16]; | 190 | return &win->locals[reg - 16]; |
186 | } | 191 | } |
187 | } | 192 | } |
@@ -204,7 +209,7 @@ static void store_reg(struct pt_regs *regs, unsigned long val, unsigned long rd) | |||
204 | } else { | 209 | } else { |
205 | unsigned long __user *rd_user = __fetch_reg_addr_user(rd, regs); | 210 | unsigned long __user *rd_user = __fetch_reg_addr_user(rd, regs); |
206 | 211 | ||
207 | if (test_thread_flag(TIF_32BIT)) | 212 | if (!test_thread_64bit_stack(regs->u_regs[UREG_FP])) |
208 | __put_user((u32)val, (u32 __user *)rd_user); | 213 | __put_user((u32)val, (u32 __user *)rd_user); |
209 | else | 214 | else |
210 | __put_user(val, rd_user); | 215 | __put_user(val, rd_user); |
diff --git a/arch/sparc/kernel/winfixup.S b/arch/sparc/kernel/winfixup.S index a6b0863c27df..1e67ce958369 100644 --- a/arch/sparc/kernel/winfixup.S +++ b/arch/sparc/kernel/winfixup.S | |||
@@ -43,6 +43,8 @@ spill_fixup_mna: | |||
43 | spill_fixup_dax: | 43 | spill_fixup_dax: |
44 | TRAP_LOAD_THREAD_REG(%g6, %g1) | 44 | TRAP_LOAD_THREAD_REG(%g6, %g1) |
45 | ldx [%g6 + TI_FLAGS], %g1 | 45 | ldx [%g6 + TI_FLAGS], %g1 |
46 | andcc %sp, 0x1, %g0 | ||
47 | movne %icc, 0, %g1 | ||
46 | andcc %g1, _TIF_32BIT, %g0 | 48 | andcc %g1, _TIF_32BIT, %g0 |
47 | ldub [%g6 + TI_WSAVED], %g1 | 49 | ldub [%g6 + TI_WSAVED], %g1 |
48 | sll %g1, 3, %g3 | 50 | sll %g1, 3, %g3 |
diff --git a/arch/sparc/math-emu/math_64.c b/arch/sparc/math-emu/math_64.c index 1704068da928..034aadbff036 100644 --- a/arch/sparc/math-emu/math_64.c +++ b/arch/sparc/math-emu/math_64.c | |||
@@ -320,7 +320,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f, bool illegal_insn_trap) | |||
320 | XR = 0; | 320 | XR = 0; |
321 | else if (freg < 16) | 321 | else if (freg < 16) |
322 | XR = regs->u_regs[freg]; | 322 | XR = regs->u_regs[freg]; |
323 | else if (test_thread_flag(TIF_32BIT)) { | 323 | else if (!test_thread_64bit_stack(regs->u_regs[UREG_FP])) { |
324 | struct reg_window32 __user *win32; | 324 | struct reg_window32 __user *win32; |
325 | flushw_user (); | 325 | flushw_user (); |
326 | win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP])); | 326 | win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP])); |