diff options
Diffstat (limited to 'arch/sparc64/kernel/ptrace.c')
-rw-r--r-- | arch/sparc64/kernel/ptrace.c | 95 |
1 files changed, 71 insertions, 24 deletions
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 5d3c6f46a..07ee212a3 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -19,10 +19,12 @@ #include <linux/smp.h> #include <linux/smp_lock.h> +#include <asm/asi.h> #include <asm/pgtable.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/psrcompat.h> +#include <asm/visasm.h> #define MAGIC_CONSTANT 0x80000000 @@ -72,6 +74,41 @@ repeat: return pgtable; } +/* We must bypass the L1-cache to avoid alias issues. -DaveM */ +static __inline__ unsigned long read_user_long(unsigned long kvaddr) +{ + unsigned long ret; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (ret) + : "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC)); + return ret; +} + +static __inline__ unsigned int read_user_int(unsigned long kvaddr) +{ + unsigned int ret; + + __asm__ __volatile__("lduwa [%1] %2, %0" + : "=r" (ret) + : "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC)); + return ret; +} + +static __inline__ void write_user_long(unsigned long kvaddr, unsigned long val) +{ + __asm__ __volatile__("stxa %0, [%1] %2" + : /* no outputs */ + : "r" (val), "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC)); +} + +static __inline__ void write_user_int(unsigned long kvaddr, unsigned int val) +{ + __asm__ __volatile__("stwa %0, [%1] %2" + : /* no outputs */ + : "r" (val), "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC)); +} + static inline unsigned long get_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr) { @@ -84,7 +121,7 @@ static inline unsigned long get_long(struct task_struct * tsk, if (MAP_NR(page) >= max_mapnr) return 0; page += addr & ~PAGE_MASK; - retval = *(unsigned long *) page; + retval = read_user_long(page); flush_page_to_ram(page); return retval; } @@ -103,14 +140,12 @@ static inline void put_long(struct task_struct * tsk, struct vm_area_struct * vm unsigned long pgaddr; pgaddr = page + (addr & ~PAGE_MASK); - *(unsigned long *) (pgaddr) = data; + write_user_long(pgaddr, data); __asm__ __volatile__(" membar #StoreStore flush %0 " : : "r" (pgaddr & ~7) : "memory"); - - flush_page_to_ram(page); } /* we're bypassing pagetables, so we have to set the dirty bit ourselves */ /* this should also re-instate whatever read-only mode there was before */ @@ -131,7 +166,7 @@ static inline unsigned int get_int(struct task_struct * tsk, if (MAP_NR(page) >= max_mapnr) return 0; page += addr & ~PAGE_MASK; - retval = *(unsigned int *) page; + retval = read_user_int(page); flush_page_to_ram(page); return retval; } @@ -150,14 +185,12 @@ static inline void put_int(struct task_struct * tsk, struct vm_area_struct * vma unsigned long pgaddr; pgaddr = page + (addr & ~PAGE_MASK); - *(unsigned int *) (pgaddr) = data; + write_user_int(pgaddr, data); __asm__ __volatile__(" membar #StoreStore flush %0 " : : "r" (pgaddr & ~7) : "memory"); - - flush_page_to_ram(page); } /* we're bypassing pagetables, so we have to set the dirty bit ourselves */ /* this should also re-instate whatever read-only mode there was before */ @@ -323,9 +356,11 @@ static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset, case 0: v = t->ksp; break; +#if 0 case 4: v = t->kpc; break; +#endif case 8: v = t->kpsr; break; @@ -800,11 +835,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned int insn; } fpq[16]; } *fps = (struct fps *) addr; - unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1); + unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs); if (copy_to_user(&fps->regs[0], fpregs, (32 * sizeof(unsigned int))) || - __put_user(((unsigned int)fpregs[32]), (&fps->fsr)) || + __put_user(child->tss.xfsr[0], (&fps->fsr)) || __put_user(0, (&fps->fpqd)) || __put_user(0, (&fps->flags)) || __put_user(0, (&fps->extra)) || @@ -821,11 +856,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned int regs[64]; unsigned long fsr; } *fps = (struct fps *) addr; - unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1); + unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs); if (copy_to_user(&fps->regs[0], fpregs, (64 * sizeof(unsigned int))) || - __put_user(fpregs[32], (&fps->fsr))) { + __put_user(child->tss.xfsr[0], (&fps->fsr))) { pt_error_return(regs, EFAULT); goto out; } @@ -845,7 +880,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned int insn; } fpq[16]; } *fps = (struct fps *) addr; - unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1); + unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs); unsigned fsr; if (copy_from_user(fpregs, &fps->regs[0], @@ -854,8 +889,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, EFAULT); goto out; } - fpregs[32] &= 0xffffffff00000000UL; - fpregs[32] |= fsr; + child->tss.xfsr[0] &= 0xffffffff00000000UL; + child->tss.xfsr[0] |= fsr; + if (!(child->tss.fpsaved[0] & FPRS_FEF)) + child->tss.gsr[0] = 0; + child->tss.fpsaved[0] |= (FPRS_FEF | FPRS_DL); pt_succ_return(regs, 0); goto out; } @@ -865,14 +903,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned int regs[64]; unsigned long fsr; } *fps = (struct fps *) addr; - unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1); + unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs); if (copy_from_user(fpregs, &fps->regs[0], (64 * sizeof(unsigned int))) || - __get_user(fpregs[32], (&fps->fsr))) { + __get_user(child->tss.xfsr[0], (&fps->fsr))) { pt_error_return(regs, EFAULT); goto out; } + if (!(child->tss.fpsaved[0] & FPRS_FEF)) + child->tss.gsr[0] = 0; + child->tss.fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU); pt_succ_return(regs, 0); goto out; } @@ -890,7 +931,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) vma = find_extend_vma(child, src); if (!vma) { pt_error_return(regs, EIO); - goto out; + goto flush_and_out; } pgtable = get_page (child, vma, src, 0); if (src & ~PAGE_MASK) { @@ -904,13 +945,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs) if (copy_to_user (dest, ((char *)page) + (src & ~PAGE_MASK), curlen)) { flush_page_to_ram(page); pt_error_return(regs, EFAULT); - goto out; + goto flush_and_out; } flush_page_to_ram(page); } else { if (clear_user (dest, curlen)) { pt_error_return(regs, EFAULT); - goto out; + goto flush_and_out; } } src += curlen; @@ -918,7 +959,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) len -= curlen; } pt_succ_return(regs, 0); - goto out; + goto flush_and_out; } case PTRACE_WRITETEXT: @@ -934,7 +975,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) vma = find_extend_vma(child, dest); if (!vma) { pt_error_return(regs, EIO); - goto out; + goto flush_and_out; } pgtable = get_page (child, vma, dest, 1); if (dest & ~PAGE_MASK) { @@ -951,7 +992,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); flush_tlb_page(vma, dest); pt_error_return(regs, EFAULT); - goto out; + goto flush_and_out; } flush_page_to_ram(page); set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); @@ -962,7 +1003,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) len -= curlen; } pt_succ_return(regs, 0); - goto out; + goto flush_and_out; } case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */ @@ -1041,6 +1082,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, EIO); goto out; } +flush_and_out: + { + unsigned long va; + for(va = 0; va < (PAGE_SIZE << 1); va += 32) + spitfire_put_dcache_tag(va, 0x0); + } out: unlock_kernel(); } |