diff options
Diffstat (limited to 'arch/sparc64')
-rw-r--r-- | arch/sparc64/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/sparc64/kernel/ptrace.c | 148 | ||||
-rw-r--r-- | arch/sparc64/kernel/semaphore.c | 254 | ||||
-rw-r--r-- | arch/sparc64/kernel/sparc64_ksyms.c | 6 |
4 files changed, 98 insertions, 312 deletions
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 1bf5b187de4..459462e80a1 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -10,7 +10,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o setup.o cpu.o idprom.o \ traps.o auxio.o una_asm.o sysfs.o iommu.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ - unaligned.o central.o pci.o starfire.o semaphore.o \ + unaligned.o central.o pci.o starfire.o \ power.o sbus.o sparc64_ksyms.o chmc.o \ visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 7963595c77c..e9fc0aa2da3 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -114,6 +114,85 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, preempt_enable(); } +static int get_from_target(struct task_struct *target, unsigned long uaddr, + void *kbuf, int len) +{ + if (target == current) { + if (copy_from_user(kbuf, (void __user *) uaddr, len)) + return -EFAULT; + } else { + int len2 = access_process_vm(target, uaddr, kbuf, len, 0); + if (len2 != len) + return -EFAULT; + } + return 0; +} + +static int set_to_target(struct task_struct *target, unsigned long uaddr, + void *kbuf, int len) +{ + if (target == current) { + if (copy_to_user((void __user *) uaddr, kbuf, len)) + return -EFAULT; + } else { + int len2 = access_process_vm(target, uaddr, kbuf, len, 1); + if (len2 != len) + return -EFAULT; + } + return 0; +} + +static int regwindow64_get(struct task_struct *target, + const struct pt_regs *regs, + struct reg_window *wbuf) +{ + unsigned long rw_addr = regs->u_regs[UREG_I6]; + + if (test_tsk_thread_flag(current, TIF_32BIT)) { + struct reg_window32 win32; + int i; + + if (get_from_target(target, rw_addr, &win32, sizeof(win32))) + return -EFAULT; + for (i = 0; i < 8; i++) + wbuf->locals[i] = win32.locals[i]; + for (i = 0; i < 8; i++) + wbuf->ins[i] = win32.ins[i]; + } else { + rw_addr += STACK_BIAS; + if (get_from_target(target, rw_addr, wbuf, sizeof(*wbuf))) + return -EFAULT; + } + + return 0; +} + +static int regwindow64_set(struct task_struct *target, + const struct pt_regs *regs, + struct reg_window *wbuf) +{ + unsigned long rw_addr = regs->u_regs[UREG_I6]; + + if (test_tsk_thread_flag(current, TIF_32BIT)) { + struct reg_window32 win32; + int i; + + for (i = 0; i < 8; i++) + win32.locals[i] = wbuf->locals[i]; + for (i = 0; i < 8; i++) + win32.ins[i] = wbuf->ins[i]; + + if (set_to_target(target, rw_addr, &win32, sizeof(win32))) + return -EFAULT; + } else { + rw_addr += STACK_BIAS; + if (set_to_target(target, rw_addr, wbuf, sizeof(*wbuf))) + return -EFAULT; + } + + return 0; +} + enum sparc_regset { REGSET_GENERAL, REGSET_FP, @@ -133,25 +212,13 @@ static int genregs64_get(struct task_struct *target, ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs->u_regs, 0, 16 * sizeof(u64)); - if (!ret) { - unsigned long __user *reg_window = (unsigned long __user *) - (regs->u_regs[UREG_I6] + STACK_BIAS); - unsigned long window[16]; - - if (target == current) { - if (copy_from_user(window, reg_window, sizeof(window))) - return -EFAULT; - } else { - if (access_process_vm(target, - (unsigned long) reg_window, - window, - sizeof(window), 0) != - sizeof(window)) - return -EFAULT; - } + if (!ret && count && pos < (32 * sizeof(u64))) { + struct reg_window window; + if (regwindow64_get(target, regs, &window)) + return -EFAULT; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, - window, + &window, 16 * sizeof(u64), 32 * sizeof(u64)); } @@ -173,10 +240,11 @@ static int genregs64_get(struct task_struct *target, 36 * sizeof(u64)); } - if (!ret) + if (!ret) { ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 36 * sizeof(u64), -1); + } return ret; } @@ -194,42 +262,20 @@ static int genregs64_set(struct task_struct *target, ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs->u_regs, 0, 16 * sizeof(u64)); - if (!ret && count > 0) { - unsigned long __user *reg_window = (unsigned long __user *) - (regs->u_regs[UREG_I6] + STACK_BIAS); - unsigned long window[16]; + if (!ret && count && pos < (32 * sizeof(u64))) { + struct reg_window window; - if (target == current) { - if (copy_from_user(window, reg_window, sizeof(window))) - return -EFAULT; - } else { - if (access_process_vm(target, - (unsigned long) reg_window, - window, - sizeof(window), 0) != - sizeof(window)) - return -EFAULT; - } + if (regwindow64_get(target, regs, &window)) + return -EFAULT; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - window, + &window, 16 * sizeof(u64), 32 * sizeof(u64)); - if (!ret) { - if (target == current) { - if (copy_to_user(reg_window, window, - sizeof(window))) - return -EFAULT; - } else { - if (access_process_vm(target, - (unsigned long) - reg_window, - window, - sizeof(window), 1) != - sizeof(window)) - return -EFAULT; - } - } + + if (!ret && + regwindow64_set(target, regs, &window)) + return -EFAULT; } if (!ret && count > 0) { @@ -805,7 +851,7 @@ struct compat_fps { long compat_arch_ptrace(struct task_struct *child, compat_long_t request, compat_ulong_t caddr, compat_ulong_t cdata) { - const struct user_regset_view *view = task_user_regset_view(child); + const struct user_regset_view *view = task_user_regset_view(current); compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4]; struct pt_regs32 __user *pregs; struct compat_fps __user *fps; @@ -913,7 +959,7 @@ struct fps { long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - const struct user_regset_view *view = task_user_regset_view(child); + const struct user_regset_view *view = task_user_regset_view(current); unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4]; struct pt_regs __user *pregs; struct fps __user *fps; diff --git a/arch/sparc64/kernel/semaphore.c b/arch/sparc64/kernel/semaphore.c deleted file mode 100644 index 9974a689955..00000000000 --- a/arch/sparc64/kernel/semaphore.c +++ /dev/null @@ -1,254 +0,0 @@ -/* semaphore.c: Sparc64 semaphore implementation. - * - * This is basically the PPC semaphore scheme ported to use - * the sparc64 atomic instructions, so see the PPC code for - * credits. - */ - -#include <linux/sched.h> -#include <linux/errno.h> -#include <linux/init.h> - -/* - * Atomically update sem->count. - * This does the equivalent of the following: - * - * old_count = sem->count; - * tmp = MAX(old_count, 0) + incr; - * sem->count = tmp; - * return old_count; - */ -static inline int __sem_update_count(struct semaphore *sem, int incr) -{ - int old_count, tmp; - - __asm__ __volatile__("\n" -" ! __sem_update_count old_count(%0) tmp(%1) incr(%4) &sem->count(%3)\n" -"1: ldsw [%3], %0\n" -" mov %0, %1\n" -" cmp %0, 0\n" -" movl %%icc, 0, %1\n" -" add %1, %4, %1\n" -" cas [%3], %0, %1\n" -" cmp %0, %1\n" -" membar #StoreLoad | #StoreStore\n" -" bne,pn %%icc, 1b\n" -" nop\n" - : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) - : "r" (&sem->count), "r" (incr), "m" (sem->count) - : "cc"); - - return old_count; -} - -static void __up(struct semaphore *sem) -{ - __sem_update_count(sem, 1); - wake_up(&sem->wait); -} - -void up(struct semaphore *sem) -{ - /* This atomically does: - * old_val = sem->count; - * new_val = sem->count + 1; - * sem->count = new_val; - * if (old_val < 0) - * __up(sem); - * - * The (old_val < 0) test is equivalent to - * the more straightforward (new_val <= 0), - * but it is easier to test the former because - * of how the CAS instruction works. - */ - - __asm__ __volatile__("\n" -" ! up sem(%0)\n" -" membar #StoreLoad | #LoadLoad\n" -"1: lduw [%0], %%g1\n" -" add %%g1, 1, %%g7\n" -" cas [%0], %%g1, %%g7\n" -" cmp %%g1, %%g7\n" -" bne,pn %%icc, 1b\n" -" addcc %%g7, 1, %%g0\n" -" membar #StoreLoad | #StoreStore\n" -" ble,pn %%icc, 3f\n" -" nop\n" -"2:\n" -" .subsection 2\n" -"3: mov %0, %%g1\n" -" save %%sp, -160, %%sp\n" -" call %1\n" -" mov %%g1, %%o0\n" -" ba,pt %%xcc, 2b\n" -" restore\n" -" .previous\n" - : : "r" (sem), "i" (__up) - : "g1", "g2", "g3", "g7", "memory", "cc"); -} - -static void __sched __down(struct semaphore * sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - tsk->state = TASK_UNINTERRUPTIBLE; - add_wait_queue_exclusive(&sem->wait, &wait); - - while (__sem_update_count(sem, -1) <= 0) { - schedule(); - tsk->state = TASK_UNINTERRUPTIBLE; - } - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - wake_up(&sem->wait); -} - -void __sched down(struct semaphore *sem) -{ - might_sleep(); - /* This atomically does: - * old_val = sem->count; - * new_val = sem->count - 1; - * sem->count = new_val; - * if (old_val < 1) - * __down(sem); - * - * The (old_val < 1) test is equivalent to - * the more straightforward (new_val < 0), - * but it is easier to test the former because - * of how the CAS instruction works. - */ - - __asm__ __volatile__("\n" -" ! down sem(%0)\n" -"1: lduw [%0], %%g1\n" -" sub %%g1, 1, %%g7\n" -" cas [%0], %%g1, %%g7\n" -" cmp %%g1, %%g7\n" -" bne,pn %%icc, 1b\n" -" cmp %%g7, 1\n" -" membar #StoreLoad | #StoreStore\n" -" bl,pn %%icc, 3f\n" -" nop\n" -"2:\n" -" .subsection 2\n" -"3: mov %0, %%g1\n" -" save %%sp, -160, %%sp\n" -" call %1\n" -" mov %%g1, %%o0\n" -" ba,pt %%xcc, 2b\n" -" restore\n" -" .previous\n" - : : "r" (sem), "i" (__down) - : "g1", "g2", "g3", "g7", "memory", "cc"); -} - -int down_trylock(struct semaphore *sem) -{ - int ret; - - /* This atomically does: - * old_val = sem->count; - * new_val = sem->count - 1; - * if (old_val < 1) { - * ret = 1; - * } else { - * sem->count = new_val; - * ret = 0; - * } - * - * The (old_val < 1) test is equivalent to - * the more straightforward (new_val < 0), - * but it is easier to test the former because - * of how the CAS instruction works. - */ - - __asm__ __volatile__("\n" -" ! down_trylock sem(%1) ret(%0)\n" -"1: lduw [%1], %%g1\n" -" sub %%g1, 1, %%g7\n" -" cmp %%g1, 1\n" -" bl,pn %%icc, 2f\n" -" mov 1, %0\n" -" cas [%1], %%g1, %%g7\n" -" cmp %%g1, %%g7\n" -" bne,pn %%icc, 1b\n" -" mov 0, %0\n" -" membar #StoreLoad | #StoreStore\n" -"2:\n" - : "=&r" (ret) - : "r" (sem) - : "g1", "g7", "memory", "cc"); - - return ret; -} - -static int __sched __down_interruptible(struct semaphore * sem) -{ - int retval = 0; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - tsk->state = TASK_INTERRUPTIBLE; - add_wait_queue_exclusive(&sem->wait, &wait); - - while (__sem_update_count(sem, -1) <= 0) { - if (signal_pending(current)) { - __sem_update_count(sem, 0); - retval = -EINTR; - break; - } - schedule(); - tsk->state = TASK_INTERRUPTIBLE; - } - tsk->state = TASK_RUNNING; - remove_wait_queue(&sem->wait, &wait); - wake_up(&sem->wait); - return retval; -} - -int __sched down_interruptible(struct semaphore *sem) -{ - int ret = 0; - - might_sleep(); - /* This atomically does: - * old_val = sem->count; - * new_val = sem->count - 1; - * sem->count = new_val; - * if (old_val < 1) - * ret = __down_interruptible(sem); - * - * The (old_val < 1) test is equivalent to - * the more straightforward (new_val < 0), - * but it is easier to test the former because - * of how the CAS instruction works. - */ - - __asm__ __volatile__("\n" -" ! down_interruptible sem(%2) ret(%0)\n" -"1: lduw [%2], %%g1\n" -" sub %%g1, 1, %%g7\n" -" cas [%2], %%g1, %%g7\n" -" cmp %%g1, %%g7\n" -" bne,pn %%icc, 1b\n" -" cmp %%g7, 1\n" -" membar #StoreLoad | #StoreStore\n" -" bl,pn %%icc, 3f\n" -" nop\n" -"2:\n" -" .subsection 2\n" -"3: mov %2, %%g1\n" -" save %%sp, -160, %%sp\n" -" call %3\n" -" mov %%g1, %%o0\n" -" ba,pt %%xcc, 2b\n" -" restore\n" -" .previous\n" - : "=r" (ret) - : "0" (ret), "r" (sem), "i" (__down_interruptible) - : "g1", "g2", "g3", "g7", "memory", "cc"); - return ret; -} diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 51fa773f38c..051b8d9cb98 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -130,12 +130,6 @@ EXPORT_SYMBOL(_mcount); EXPORT_SYMBOL(sparc64_get_clock_tick); -/* semaphores */ -EXPORT_SYMBOL(down); -EXPORT_SYMBOL(down_trylock); -EXPORT_SYMBOL(down_interruptible); -EXPORT_SYMBOL(up); - /* RW semaphores */ EXPORT_SYMBOL(__down_read); EXPORT_SYMBOL(__down_read_trylock); |