summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/xtensa/kernel/ptrace.c66
-rw-r--r--include/asm-xtensa/elf.h3
2 files changed, 37 insertions, 32 deletions
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
index f6669d605125..9486882ef0af 100644
--- a/arch/xtensa/kernel/ptrace.c
+++ b/arch/xtensa/kernel/ptrace.c
@@ -43,32 +43,29 @@ int ptrace_getregs(struct task_struct *child, void __user *uregs)
{
struct pt_regs *regs = task_pt_regs(child);
xtensa_gregset_t __user *gregset = uregs;
- unsigned long wb = regs->windowbase;
- unsigned long ws = regs->windowstart;
unsigned long wm = regs->wmask;
- int ret = 0;
- int live, last;
+ unsigned long wb = regs->windowbase;
+ int live, i;
if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
return -EIO;
- /* Norm windowstart to a windowbase of 0. */
-
- ws = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<<WSBITS)-1);
-
- ret |= __put_user(regs->pc, &gregset->pc);
- ret |= __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps);
- ret |= __put_user(regs->lbeg, &gregset->lbeg);
- ret |= __put_user(regs->lend, &gregset->lend);
- ret |= __put_user(regs->lcount, &gregset->lcount);
- ret |= __put_user(ws, &gregset->windowstart);
+ __put_user(regs->pc, &gregset->pc);
+ __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps);
+ __put_user(regs->lbeg, &gregset->lbeg);
+ __put_user(regs->lend, &gregset->lend);
+ __put_user(regs->lcount, &gregset->lcount);
+ __put_user(regs->windowstart, &gregset->windowstart);
+ __put_user(regs->windowbase, &gregset->windowbase);
live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16;
- last = XCHAL_NUM_AREGS - (wm >> 4) * 4;
- ret |= __copy_to_user(gregset->a, regs->areg, live * 4);
- ret |= __copy_to_user(gregset->a + last, regs->areg + last, (wm>>4)*16);
- return ret ? -EFAULT : 0;
+ for (i = 0; i < live; i++)
+ __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS));
+ for (i = XCHAL_NUM_AREGS - (wm >> 4) * 4; i < XCHAL_NUM_AREGS; i++)
+ __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS));
+
+ return 0;
}
int ptrace_setregs(struct task_struct *child, void __user *uregs)
@@ -76,28 +73,35 @@ int ptrace_setregs(struct task_struct *child, void __user *uregs)
struct pt_regs *regs = task_pt_regs(child);
xtensa_gregset_t *gregset = uregs;
const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK;
- unsigned long wm = regs->wmask;
unsigned long ps;
- int ret = 0;
- int live, last;
+ unsigned long wb;
if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
return -EIO;
- ret |= __get_user(regs->pc, &gregset->pc);
- ret |= __get_user(ps, &gregset->ps);
- ret |= __get_user(regs->lbeg, &gregset->lbeg);
- ret |= __get_user(regs->lend, &gregset->lend);
- ret |= __get_user(regs->lcount, &gregset->lcount);
+ __get_user(regs->pc, &gregset->pc);
+ __get_user(ps, &gregset->ps);
+ __get_user(regs->lbeg, &gregset->lbeg);
+ __get_user(regs->lend, &gregset->lend);
+ __get_user(regs->lcount, &gregset->lcount);
+ __get_user(regs->windowstart, &gregset->windowstart);
+ __get_user(wb, &gregset->windowbase);
regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT);
- live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16;
- last = XCHAL_NUM_AREGS - (wm >> 4) * 4;
- ret |= __copy_from_user(regs->areg, gregset->a, live * 4);
- ret |= __copy_from_user(regs->areg+last, gregset->a+last, (wm>>4)*16);
+ if (wb >= XCHAL_NUM_AREGS / 4)
+ return -EFAULT;
- return ret ? -EFAULT : 0;
+ regs->windowbase = wb;
+
+ if (wb != 0 && __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4,
+ gregset->a, wb * 16))
+ return -EFAULT;
+
+ if (__copy_from_user(regs->areg, gregset->a + wb*4, (WSBITS-wb) * 16))
+ return -EFAULT;
+
+ return 0;
}
diff --git a/include/asm-xtensa/elf.h b/include/asm-xtensa/elf.h
index 11103e07d028..ca6e5101a2cb 100644
--- a/include/asm-xtensa/elf.h
+++ b/include/asm-xtensa/elf.h
@@ -82,7 +82,8 @@ typedef struct {
elf_greg_t lcount;
elf_greg_t sar;
elf_greg_t windowstart;
- elf_greg_t reserved[9+48];
+ elf_greg_t windowbase;
+ elf_greg_t reserved[8+48];
elf_greg_t a[64];
} xtensa_gregset_t;