summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/ptrace.c')
-rw-r--r--arch/sparc64/kernel/ptrace.c95
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();
}