diff options
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r-- | arch/sparc/kernel/entry.S | 2 | ||||
-rw-r--r-- | arch/sparc/kernel/process.c | 25 | ||||
-rw-r--r-- | arch/sparc/kernel/ptrace.c | 6 | ||||
-rw-r--r-- | arch/sparc/kernel/rtrap.S | 11 | ||||
-rw-r--r-- | arch/sparc/kernel/signal.c | 84 | ||||
-rw-r--r-- | arch/sparc/kernel/sys_sparc.c | 51 |
6 files changed, 81 insertions, 98 deletions
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 57d1bbdd0bd2..4bcfe54f878d 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S | |||
@@ -1306,6 +1306,8 @@ ret_from_fork: | |||
1306 | .align 4 | 1306 | .align 4 |
1307 | .globl linux_sparc_syscall | 1307 | .globl linux_sparc_syscall |
1308 | linux_sparc_syscall: | 1308 | linux_sparc_syscall: |
1309 | sethi %hi(PSR_SYSCALL), %l4 | ||
1310 | or %l0, %l4, %l0 | ||
1309 | /* Direct access to user regs, must faster. */ | 1311 | /* Direct access to user regs, must faster. */ |
1310 | cmp %g1, NR_SYSCALLS | 1312 | cmp %g1, NR_SYSCALLS |
1311 | bgeu linux_sparc_ni_syscall | 1313 | bgeu linux_sparc_ni_syscall |
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index e7f35198ae34..da48d248cc17 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c | |||
@@ -419,14 +419,26 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags, | |||
419 | unsigned long stack_size) | 419 | unsigned long stack_size) |
420 | { | 420 | { |
421 | unsigned long parent_tid_ptr, child_tid_ptr; | 421 | unsigned long parent_tid_ptr, child_tid_ptr; |
422 | unsigned long orig_i1 = regs->u_regs[UREG_I1]; | ||
423 | long ret; | ||
422 | 424 | ||
423 | parent_tid_ptr = regs->u_regs[UREG_I2]; | 425 | parent_tid_ptr = regs->u_regs[UREG_I2]; |
424 | child_tid_ptr = regs->u_regs[UREG_I4]; | 426 | child_tid_ptr = regs->u_regs[UREG_I4]; |
425 | 427 | ||
426 | return do_fork(clone_flags, stack_start, | 428 | ret = do_fork(clone_flags, stack_start, |
427 | regs, stack_size, | 429 | regs, stack_size, |
428 | (int __user *) parent_tid_ptr, | 430 | (int __user *) parent_tid_ptr, |
429 | (int __user *) child_tid_ptr); | 431 | (int __user *) child_tid_ptr); |
432 | |||
433 | /* If we get an error and potentially restart the system | ||
434 | * call, we're screwed because copy_thread() clobbered | ||
435 | * the parent's %o1. So detect that case and restore it | ||
436 | * here. | ||
437 | */ | ||
438 | if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK) | ||
439 | regs->u_regs[UREG_I1] = orig_i1; | ||
440 | |||
441 | return ret; | ||
430 | } | 442 | } |
431 | 443 | ||
432 | /* Copy a Sparc thread. The fork() return value conventions | 444 | /* Copy a Sparc thread. The fork() return value conventions |
@@ -626,11 +638,6 @@ asmlinkage int sparc_execve(struct pt_regs *regs) | |||
626 | (char __user * __user *)regs->u_regs[base + UREG_I2], | 638 | (char __user * __user *)regs->u_regs[base + UREG_I2], |
627 | regs); | 639 | regs); |
628 | putname(filename); | 640 | putname(filename); |
629 | if (error == 0) { | ||
630 | task_lock(current); | ||
631 | current->ptrace &= ~PT_DTRACE; | ||
632 | task_unlock(current); | ||
633 | } | ||
634 | out: | 641 | out: |
635 | return error; | 642 | return error; |
636 | } | 643 | } |
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index 7f44ae69b29e..81f3b929743f 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c | |||
@@ -170,8 +170,8 @@ static int genregs32_set(struct task_struct *target, | |||
170 | switch (pos) { | 170 | switch (pos) { |
171 | case 32: /* PSR */ | 171 | case 32: /* PSR */ |
172 | psr = regs->psr; | 172 | psr = regs->psr; |
173 | psr &= ~PSR_ICC; | 173 | psr &= ~(PSR_ICC | PSR_SYSCALL); |
174 | psr |= (reg & PSR_ICC); | 174 | psr |= (reg & (PSR_ICC | PSR_SYSCALL)); |
175 | regs->psr = psr; | 175 | regs->psr = psr; |
176 | break; | 176 | break; |
177 | case 33: /* PC */ | 177 | case 33: /* PC */ |
@@ -441,6 +441,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
441 | break; | 441 | break; |
442 | 442 | ||
443 | default: | 443 | default: |
444 | if (request == PTRACE_SPARC_DETACH) | ||
445 | request = PTRACE_DETACH; | ||
444 | ret = ptrace_request(child, request, addr, data); | 446 | ret = ptrace_request(child, request, addr, data); |
445 | break; | 447 | break; |
446 | } | 448 | } |
diff --git a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S index 77ca6fd81253..ab818cdc4cc0 100644 --- a/arch/sparc/kernel/rtrap.S +++ b/arch/sparc/kernel/rtrap.S | |||
@@ -50,8 +50,9 @@ rtrap_7win_patch5: and %g1, 0x7f, %g1 | |||
50 | ret_trap_entry: | 50 | ret_trap_entry: |
51 | ret_trap_lockless_ipi: | 51 | ret_trap_lockless_ipi: |
52 | andcc %t_psr, PSR_PS, %g0 | 52 | andcc %t_psr, PSR_PS, %g0 |
53 | sethi %hi(PSR_SYSCALL), %g1 | ||
53 | be 1f | 54 | be 1f |
54 | nop | 55 | andn %t_psr, %g1, %t_psr |
55 | 56 | ||
56 | wr %t_psr, 0x0, %psr | 57 | wr %t_psr, 0x0, %psr |
57 | b ret_trap_kernel | 58 | b ret_trap_kernel |
@@ -73,7 +74,6 @@ signal_p: | |||
73 | ld [%sp + STACKFRAME_SZ + PT_PSR], %t_psr | 74 | ld [%sp + STACKFRAME_SZ + PT_PSR], %t_psr |
74 | 75 | ||
75 | mov %l5, %o1 | 76 | mov %l5, %o1 |
76 | mov %l6, %o2 | ||
77 | call do_signal | 77 | call do_signal |
78 | add %sp, STACKFRAME_SZ, %o0 ! pt_regs ptr | 78 | add %sp, STACKFRAME_SZ, %o0 ! pt_regs ptr |
79 | 79 | ||
@@ -81,6 +81,8 @@ signal_p: | |||
81 | ld [%sp + STACKFRAME_SZ + PT_PSR], %t_psr | 81 | ld [%sp + STACKFRAME_SZ + PT_PSR], %t_psr |
82 | clr %l6 | 82 | clr %l6 |
83 | ret_trap_continue: | 83 | ret_trap_continue: |
84 | sethi %hi(PSR_SYSCALL), %g1 | ||
85 | andn %t_psr, %g1, %t_psr | ||
84 | wr %t_psr, 0x0, %psr | 86 | wr %t_psr, 0x0, %psr |
85 | WRITE_PAUSE | 87 | WRITE_PAUSE |
86 | 88 | ||
@@ -137,8 +139,9 @@ ret_trap_userwins_ok: | |||
137 | LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc) | 139 | LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc) |
138 | or %t_pc, %t_npc, %g2 | 140 | or %t_pc, %t_npc, %g2 |
139 | andcc %g2, 0x3, %g0 | 141 | andcc %g2, 0x3, %g0 |
142 | sethi %hi(PSR_SYSCALL), %g2 | ||
140 | be 1f | 143 | be 1f |
141 | nop | 144 | andn %t_psr, %g2, %t_psr |
142 | 145 | ||
143 | b ret_trap_unaligned_pc | 146 | b ret_trap_unaligned_pc |
144 | add %sp, STACKFRAME_SZ, %o0 | 147 | add %sp, STACKFRAME_SZ, %o0 |
@@ -201,6 +204,8 @@ rtrap_patch5: and %g1, 0xff, %g1 | |||
201 | 1: | 204 | 1: |
202 | LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1) | 205 | LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1) |
203 | 2: | 206 | 2: |
207 | sethi %hi(PSR_SYSCALL), %twin_tmp1 | ||
208 | andn %t_psr, %twin_tmp1, %t_psr | ||
204 | wr %t_psr, 0x0, %psr | 209 | wr %t_psr, 0x0, %psr |
205 | WRITE_PAUSE | 210 | WRITE_PAUSE |
206 | 211 | ||
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index 3c312290c3c2..3fd1df9f9ba7 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c | |||
@@ -145,6 +145,9 @@ asmlinkage void do_sigreturn(struct pt_regs *regs) | |||
145 | regs->psr = (up_psr & ~(PSR_ICC | PSR_EF)) | 145 | regs->psr = (up_psr & ~(PSR_ICC | PSR_EF)) |
146 | | (regs->psr & (PSR_ICC | PSR_EF)); | 146 | | (regs->psr & (PSR_ICC | PSR_EF)); |
147 | 147 | ||
148 | /* Prevent syscall restart. */ | ||
149 | pt_regs_clear_syscall(regs); | ||
150 | |||
148 | err |= __get_user(fpu_save, &sf->fpu_save); | 151 | err |= __get_user(fpu_save, &sf->fpu_save); |
149 | 152 | ||
150 | if (fpu_save) | 153 | if (fpu_save) |
@@ -199,6 +202,9 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs) | |||
199 | 202 | ||
200 | regs->psr = (regs->psr & ~PSR_ICC) | (psr & PSR_ICC); | 203 | regs->psr = (regs->psr & ~PSR_ICC) | (psr & PSR_ICC); |
201 | 204 | ||
205 | /* Prevent syscall restart. */ | ||
206 | pt_regs_clear_syscall(regs); | ||
207 | |||
202 | err |= __get_user(fpu_save, &sf->fpu_save); | 208 | err |= __get_user(fpu_save, &sf->fpu_save); |
203 | 209 | ||
204 | if (fpu_save) | 210 | if (fpu_save) |
@@ -245,15 +251,29 @@ static inline int invalid_frame_pointer(void __user *fp, int fplen) | |||
245 | 251 | ||
246 | static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize) | 252 | static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize) |
247 | { | 253 | { |
248 | unsigned long sp; | 254 | unsigned long sp = regs->u_regs[UREG_FP]; |
249 | 255 | ||
250 | sp = regs->u_regs[UREG_FP]; | 256 | /* |
257 | * If we are on the alternate signal stack and would overflow it, don't. | ||
258 | * Return an always-bogus address instead so we will die with SIGSEGV. | ||
259 | */ | ||
260 | if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) | ||
261 | return (void __user *) -1L; | ||
251 | 262 | ||
252 | /* This is the X/Open sanctioned signal stack switching. */ | 263 | /* This is the X/Open sanctioned signal stack switching. */ |
253 | if (sa->sa_flags & SA_ONSTACK) { | 264 | if (sa->sa_flags & SA_ONSTACK) { |
254 | if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7)) | 265 | if (sas_ss_flags(sp) == 0) |
255 | sp = current->sas_ss_sp + current->sas_ss_size; | 266 | sp = current->sas_ss_sp + current->sas_ss_size; |
256 | } | 267 | } |
268 | |||
269 | /* Always align the stack frame. This handles two cases. First, | ||
270 | * sigaltstack need not be mindful of platform specific stack | ||
271 | * alignment. Second, if we took this signal because the stack | ||
272 | * is not aligned properly, we'd like to take the signal cleanly | ||
273 | * and report that. | ||
274 | */ | ||
275 | sp &= ~7UL; | ||
276 | |||
257 | return (void __user *)(sp - framesize); | 277 | return (void __user *)(sp - framesize); |
258 | } | 278 | } |
259 | 279 | ||
@@ -493,26 +513,36 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, | |||
493 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 513 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
494 | * mistake. | 514 | * mistake. |
495 | */ | 515 | */ |
496 | asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int restart_syscall) | 516 | asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0) |
497 | { | 517 | { |
498 | siginfo_t info; | ||
499 | struct sparc_deliver_cookie cookie; | ||
500 | struct k_sigaction ka; | 518 | struct k_sigaction ka; |
501 | int signr; | 519 | int restart_syscall; |
502 | sigset_t *oldset; | 520 | sigset_t *oldset; |
521 | siginfo_t info; | ||
522 | int signr; | ||
503 | 523 | ||
504 | cookie.restart_syscall = restart_syscall; | 524 | if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) |
505 | cookie.orig_i0 = orig_i0; | 525 | restart_syscall = 1; |
526 | else | ||
527 | restart_syscall = 0; | ||
506 | 528 | ||
507 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 529 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
508 | oldset = ¤t->saved_sigmask; | 530 | oldset = ¤t->saved_sigmask; |
509 | else | 531 | else |
510 | oldset = ¤t->blocked; | 532 | oldset = ¤t->blocked; |
511 | 533 | ||
512 | signr = get_signal_to_deliver(&info, &ka, regs, &cookie); | 534 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
535 | |||
536 | /* If the debugger messes with the program counter, it clears | ||
537 | * the software "in syscall" bit, directing us to not perform | ||
538 | * a syscall restart. | ||
539 | */ | ||
540 | if (restart_syscall && !pt_regs_is_syscall(regs)) | ||
541 | restart_syscall = 0; | ||
542 | |||
513 | if (signr > 0) { | 543 | if (signr > 0) { |
514 | if (cookie.restart_syscall) | 544 | if (restart_syscall) |
515 | syscall_restart(cookie.orig_i0, regs, &ka.sa); | 545 | syscall_restart(orig_i0, regs, &ka.sa); |
516 | handle_signal(signr, &ka, &info, oldset, regs); | 546 | handle_signal(signr, &ka, &info, oldset, regs); |
517 | 547 | ||
518 | /* a signal was successfully delivered; the saved | 548 | /* a signal was successfully delivered; the saved |
@@ -524,16 +554,16 @@ asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int rest | |||
524 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 554 | clear_thread_flag(TIF_RESTORE_SIGMASK); |
525 | return; | 555 | return; |
526 | } | 556 | } |
527 | if (cookie.restart_syscall && | 557 | if (restart_syscall && |
528 | (regs->u_regs[UREG_I0] == ERESTARTNOHAND || | 558 | (regs->u_regs[UREG_I0] == ERESTARTNOHAND || |
529 | regs->u_regs[UREG_I0] == ERESTARTSYS || | 559 | regs->u_regs[UREG_I0] == ERESTARTSYS || |
530 | regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { | 560 | regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { |
531 | /* replay the system call when we are done */ | 561 | /* replay the system call when we are done */ |
532 | regs->u_regs[UREG_I0] = cookie.orig_i0; | 562 | regs->u_regs[UREG_I0] = orig_i0; |
533 | regs->pc -= 4; | 563 | regs->pc -= 4; |
534 | regs->npc -= 4; | 564 | regs->npc -= 4; |
535 | } | 565 | } |
536 | if (cookie.restart_syscall && | 566 | if (restart_syscall && |
537 | regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { | 567 | regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { |
538 | regs->u_regs[UREG_G1] = __NR_restart_syscall; | 568 | regs->u_regs[UREG_G1] = __NR_restart_syscall; |
539 | regs->pc -= 4; | 569 | regs->pc -= 4; |
@@ -585,27 +615,3 @@ do_sys_sigstack(struct sigstack __user *ssptr, struct sigstack __user *ossptr, | |||
585 | out: | 615 | out: |
586 | return ret; | 616 | return ret; |
587 | } | 617 | } |
588 | |||
589 | void ptrace_signal_deliver(struct pt_regs *regs, void *cookie) | ||
590 | { | ||
591 | struct sparc_deliver_cookie *cp = cookie; | ||
592 | |||
593 | if (cp->restart_syscall && | ||
594 | (regs->u_regs[UREG_I0] == ERESTARTNOHAND || | ||
595 | regs->u_regs[UREG_I0] == ERESTARTSYS || | ||
596 | regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { | ||
597 | /* replay the system call when we are done */ | ||
598 | regs->u_regs[UREG_I0] = cp->orig_i0; | ||
599 | regs->pc -= 4; | ||
600 | regs->npc -= 4; | ||
601 | cp->restart_syscall = 0; | ||
602 | } | ||
603 | |||
604 | if (cp->restart_syscall && | ||
605 | regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { | ||
606 | regs->u_regs[UREG_G1] = __NR_restart_syscall; | ||
607 | regs->pc -= 4; | ||
608 | regs->npc -= 4; | ||
609 | cp->restart_syscall = 0; | ||
610 | } | ||
611 | } | ||
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index f188b5dc9fd0..3c6b49a53ae8 100644 --- a/arch/sparc/kernel/sys_sparc.c +++ b/arch/sparc/kernel/sys_sparc.c | |||
@@ -219,12 +219,11 @@ out: | |||
219 | return err; | 219 | return err; |
220 | } | 220 | } |
221 | 221 | ||
222 | int sparc_mmap_check(unsigned long addr, unsigned long len, unsigned long flags) | 222 | int sparc_mmap_check(unsigned long addr, unsigned long len) |
223 | { | 223 | { |
224 | if (ARCH_SUN4C_SUN4 && | 224 | if (ARCH_SUN4C_SUN4 && |
225 | (len > 0x20000000 || | 225 | (len > 0x20000000 || |
226 | ((flags & MAP_FIXED) && | 226 | (addr < 0xe0000000 && addr + len > 0x20000000))) |
227 | addr < 0xe0000000 && addr + len > 0x20000000))) | ||
228 | return -EINVAL; | 227 | return -EINVAL; |
229 | 228 | ||
230 | /* See asm-sparc/uaccess.h */ | 229 | /* See asm-sparc/uaccess.h */ |
@@ -296,52 +295,14 @@ asmlinkage unsigned long sparc_mremap(unsigned long addr, | |||
296 | unsigned long old_len, unsigned long new_len, | 295 | unsigned long old_len, unsigned long new_len, |
297 | unsigned long flags, unsigned long new_addr) | 296 | unsigned long flags, unsigned long new_addr) |
298 | { | 297 | { |
299 | struct vm_area_struct *vma; | ||
300 | unsigned long ret = -EINVAL; | 298 | unsigned long ret = -EINVAL; |
301 | if (ARCH_SUN4C_SUN4) { | 299 | |
302 | if (old_len > 0x20000000 || new_len > 0x20000000) | 300 | if (unlikely(sparc_mmap_check(addr, old_len))) |
303 | goto out; | 301 | goto out; |
304 | if (addr < 0xe0000000 && addr + old_len > 0x20000000) | 302 | if (unlikely(sparc_mmap_check(new_addr, new_len))) |
305 | goto out; | ||
306 | } | ||
307 | if (old_len > TASK_SIZE - PAGE_SIZE || | ||
308 | new_len > TASK_SIZE - PAGE_SIZE) | ||
309 | goto out; | 303 | goto out; |
310 | down_write(¤t->mm->mmap_sem); | 304 | down_write(¤t->mm->mmap_sem); |
311 | if (flags & MREMAP_FIXED) { | ||
312 | if (ARCH_SUN4C_SUN4 && | ||
313 | new_addr < 0xe0000000 && | ||
314 | new_addr + new_len > 0x20000000) | ||
315 | goto out_sem; | ||
316 | if (new_addr + new_len > TASK_SIZE - PAGE_SIZE) | ||
317 | goto out_sem; | ||
318 | } else if ((ARCH_SUN4C_SUN4 && addr < 0xe0000000 && | ||
319 | addr + new_len > 0x20000000) || | ||
320 | addr + new_len > TASK_SIZE - PAGE_SIZE) { | ||
321 | unsigned long map_flags = 0; | ||
322 | struct file *file = NULL; | ||
323 | |||
324 | ret = -ENOMEM; | ||
325 | if (!(flags & MREMAP_MAYMOVE)) | ||
326 | goto out_sem; | ||
327 | |||
328 | vma = find_vma(current->mm, addr); | ||
329 | if (vma) { | ||
330 | if (vma->vm_flags & VM_SHARED) | ||
331 | map_flags |= MAP_SHARED; | ||
332 | file = vma->vm_file; | ||
333 | } | ||
334 | |||
335 | new_addr = get_unmapped_area(file, addr, new_len, | ||
336 | vma ? vma->vm_pgoff : 0, | ||
337 | map_flags); | ||
338 | ret = new_addr; | ||
339 | if (new_addr & ~PAGE_MASK) | ||
340 | goto out_sem; | ||
341 | flags |= MREMAP_FIXED; | ||
342 | } | ||
343 | ret = do_mremap(addr, old_len, new_len, flags, new_addr); | 305 | ret = do_mremap(addr, old_len, new_len, flags, new_addr); |
344 | out_sem: | ||
345 | up_write(¤t->mm->mmap_sem); | 306 | up_write(¤t->mm->mmap_sem); |
346 | out: | 307 | out: |
347 | return ret; | 308 | return ret; |