diff options
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r-- | arch/sparc/kernel/entry.h | 7 | ||||
-rw-r--r-- | arch/sparc/kernel/leon_kernel.c | 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/setup_64.c | 21 | ||||
-rw-r--r-- | arch/sparc/kernel/signal_64.c | 4 | ||||
-rw-r--r-- | arch/sparc/kernel/sys_sparc_64.c | 5 | ||||
-rw-r--r-- | arch/sparc/kernel/systbls_32.S | 1 | ||||
-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/vmlinux.lds.S | 5 | ||||
-rw-r--r-- | arch/sparc/kernel/winfixup.S | 2 |
14 files changed, 126 insertions, 54 deletions
diff --git a/arch/sparc/kernel/entry.h b/arch/sparc/kernel/entry.h index 0c218e4c0881..cc3c5cb47cda 100644 --- a/arch/sparc/kernel/entry.h +++ b/arch/sparc/kernel/entry.h | |||
@@ -59,6 +59,13 @@ struct popc_6insn_patch_entry { | |||
59 | extern struct popc_6insn_patch_entry __popc_6insn_patch, | 59 | extern struct popc_6insn_patch_entry __popc_6insn_patch, |
60 | __popc_6insn_patch_end; | 60 | __popc_6insn_patch_end; |
61 | 61 | ||
62 | struct pause_patch_entry { | ||
63 | unsigned int addr; | ||
64 | unsigned int insns[3]; | ||
65 | }; | ||
66 | extern struct pause_patch_entry __pause_3insn_patch, | ||
67 | __pause_3insn_patch_end; | ||
68 | |||
62 | extern void __init per_cpu_patch(void); | 69 | extern void __init per_cpu_patch(void); |
63 | extern void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *, | 70 | extern void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *, |
64 | struct sun4v_1insn_patch_entry *); | 71 | struct sun4v_1insn_patch_entry *); |
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index f8b6eee40bde..87f60ee65433 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c | |||
@@ -56,11 +56,13 @@ static inline unsigned int leon_eirq_get(int cpu) | |||
56 | static void leon_handle_ext_irq(unsigned int irq, struct irq_desc *desc) | 56 | static void leon_handle_ext_irq(unsigned int irq, struct irq_desc *desc) |
57 | { | 57 | { |
58 | unsigned int eirq; | 58 | unsigned int eirq; |
59 | struct irq_bucket *p; | ||
59 | int cpu = sparc_leon3_cpuid(); | 60 | int cpu = sparc_leon3_cpuid(); |
60 | 61 | ||
61 | eirq = leon_eirq_get(cpu); | 62 | eirq = leon_eirq_get(cpu); |
62 | if ((eirq & 0x10) && irq_map[eirq]->irq) /* bit4 tells if IRQ happened */ | 63 | p = irq_map[eirq]; |
63 | generic_handle_irq(irq_map[eirq]->irq); | 64 | if ((eirq & 0x10) && p && p->irq) /* bit4 tells if IRQ happened */ |
65 | generic_handle_irq(p->irq); | ||
64 | } | 66 | } |
65 | 67 | ||
66 | /* The extended IRQ controller has been found, this function registers it */ | 68 | /* The extended IRQ controller has been found, this function registers it */ |
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/setup_64.c b/arch/sparc/kernel/setup_64.c index 0800e71d8a88..0eaf0059aaef 100644 --- a/arch/sparc/kernel/setup_64.c +++ b/arch/sparc/kernel/setup_64.c | |||
@@ -316,6 +316,25 @@ static void __init popc_patch(void) | |||
316 | } | 316 | } |
317 | } | 317 | } |
318 | 318 | ||
319 | static void __init pause_patch(void) | ||
320 | { | ||
321 | struct pause_patch_entry *p; | ||
322 | |||
323 | p = &__pause_3insn_patch; | ||
324 | while (p < &__pause_3insn_patch_end) { | ||
325 | unsigned long i, addr = p->addr; | ||
326 | |||
327 | for (i = 0; i < 3; i++) { | ||
328 | *(unsigned int *) (addr + (i * 4)) = p->insns[i]; | ||
329 | wmb(); | ||
330 | __asm__ __volatile__("flush %0" | ||
331 | : : "r" (addr + (i * 4))); | ||
332 | } | ||
333 | |||
334 | p++; | ||
335 | } | ||
336 | } | ||
337 | |||
319 | #ifdef CONFIG_SMP | 338 | #ifdef CONFIG_SMP |
320 | void __init boot_cpu_id_too_large(int cpu) | 339 | void __init boot_cpu_id_too_large(int cpu) |
321 | { | 340 | { |
@@ -528,6 +547,8 @@ static void __init init_sparc64_elf_hwcap(void) | |||
528 | 547 | ||
529 | if (sparc64_elf_hwcap & AV_SPARC_POPC) | 548 | if (sparc64_elf_hwcap & AV_SPARC_POPC) |
530 | popc_patch(); | 549 | popc_patch(); |
550 | if (sparc64_elf_hwcap & AV_SPARC_PAUSE) | ||
551 | pause_patch(); | ||
531 | } | 552 | } |
532 | 553 | ||
533 | void __init setup_arch(char **cmdline_p) | 554 | void __init setup_arch(char **cmdline_p) |
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index 867de2f8189c..689e1ba62809 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c | |||
@@ -295,9 +295,7 @@ void do_rt_sigreturn(struct pt_regs *regs) | |||
295 | err |= restore_fpu_state(regs, fpu_save); | 295 | err |= restore_fpu_state(regs, fpu_save); |
296 | 296 | ||
297 | err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); | 297 | err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); |
298 | err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf); | 298 | if (err || do_sigaltstack(&sf->stack, NULL, (unsigned long)sf) == -EFAULT) |
299 | |||
300 | if (err) | ||
301 | goto segv; | 299 | goto segv; |
302 | 300 | ||
303 | err |= __get_user(rwin_save, &sf->rwin_save); | 301 | err |= __get_user(rwin_save, &sf->rwin_save); |
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_32.S b/arch/sparc/kernel/systbls_32.S index 63402f9e9f51..5147f574f125 100644 --- a/arch/sparc/kernel/systbls_32.S +++ b/arch/sparc/kernel/systbls_32.S | |||
@@ -85,3 +85,4 @@ sys_call_table: | |||
85 | /*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init | 85 | /*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init |
86 | /*330*/ .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime | 86 | /*330*/ .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime |
87 | /*335*/ .long sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev | 87 | /*335*/ .long sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev |
88 | /*340*/ .long sys_ni_syscall, sys_kcmp | ||
diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 3a58e0d66f51..1c9af9fa38e9 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, sys_kcmp | ||
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, sys_kcmp | ||
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/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S index 89c2c29f154b..0bacceb19150 100644 --- a/arch/sparc/kernel/vmlinux.lds.S +++ b/arch/sparc/kernel/vmlinux.lds.S | |||
@@ -132,6 +132,11 @@ SECTIONS | |||
132 | *(.popc_6insn_patch) | 132 | *(.popc_6insn_patch) |
133 | __popc_6insn_patch_end = .; | 133 | __popc_6insn_patch_end = .; |
134 | } | 134 | } |
135 | .pause_3insn_patch : { | ||
136 | __pause_3insn_patch = .; | ||
137 | *(.pause_3insn_patch) | ||
138 | __pause_3insn_patch_end = .; | ||
139 | } | ||
135 | PERCPU_SECTION(SMP_CACHE_BYTES) | 140 | PERCPU_SECTION(SMP_CACHE_BYTES) |
136 | 141 | ||
137 | . = ALIGN(PAGE_SIZE); | 142 | . = ALIGN(PAGE_SIZE); |
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 |