diff options
author | Max Filippov <jcmvbkbc@gmail.com> | 2013-01-14 10:38:02 +0400 |
---|---|---|
committer | Chris Zankel <chris@zankel.net> | 2013-02-23 19:23:00 -0800 |
commit | 4b2bb03f108a6e68c28de2763268571ef569c6e8 (patch) | |
tree | a96f0755d533fc55af4e38a232e3f6f0359d835e | |
parent | e6ffe17ec45dd763ee8278246a112562f64a4ef2 (diff) | |
download | op-kernel-dev-4b2bb03f108a6e68c28de2763268571ef569c6e8.zip op-kernel-dev-4b2bb03f108a6e68c28de2763268571ef569c6e8.tar.gz |
xtensa: complete ptrace handling of register windows
Compute WindowBase and WindowMask registers correctly on ptrace calls.
Work done earlier by Maxim, Christian and Marc.
Signed-off-by: Marc Gauthier <marc@tensilica.com>
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Chris Zankel <chris@zankel.net>
-rw-r--r-- | arch/xtensa/kernel/ptrace.c | 33 |
1 files changed, 20 insertions, 13 deletions
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c index 61fb2e9..a8b0d57 100644 --- a/arch/xtensa/kernel/ptrace.c +++ b/arch/xtensa/kernel/ptrace.c @@ -53,9 +53,8 @@ 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 wm = regs->wmask; unsigned long wb = regs->windowbase; - int live, i; + int i; if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) return -EIO; @@ -68,12 +67,9 @@ int ptrace_getregs(struct task_struct *child, void __user *uregs) __put_user(regs->windowstart, &gregset->windowstart); __put_user(regs->windowbase, &gregset->windowbase); - live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; - - 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)); + for (i = 0; i < XCHAL_NUM_AREGS; i++) + __put_user(regs->areg[i], + gregset->a + ((wb * 4 + i) % XCHAL_NUM_AREGS)); return 0; } @@ -84,7 +80,7 @@ int ptrace_setregs(struct task_struct *child, void __user *uregs) xtensa_gregset_t *gregset = uregs; const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK; unsigned long ps; - unsigned long wb; + unsigned long wb, ws; if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) return -EIO; @@ -94,7 +90,7 @@ int ptrace_setregs(struct task_struct *child, void __user *uregs) __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(ws, &gregset->windowstart); __get_user(wb, &gregset->windowbase); regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT); @@ -102,13 +98,24 @@ int ptrace_setregs(struct task_struct *child, void __user *uregs) if (wb >= XCHAL_NUM_AREGS / 4) return -EFAULT; - regs->windowbase = wb; + if (wb != regs->windowbase || ws != regs->windowstart) { + unsigned long rotws, wmask; + + rotws = (((ws | (ws << WSBITS)) >> wb) & + ((1 << WSBITS) - 1)) & ~1; + wmask = ((rotws ? WSBITS + 1 - ffs(rotws) : 0) << 4) | + (rotws & 0xF) | 1; + regs->windowbase = wb; + regs->windowstart = ws; + regs->wmask = wmask; + } if (wb != 0 && __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4, - gregset->a, wb * 16)) + gregset->a, wb * 16)) return -EFAULT; - if (__copy_from_user(regs->areg, gregset->a + wb*4, (WSBITS-wb) * 16)) + if (__copy_from_user(regs->areg, gregset->a + wb * 4, + (WSBITS - wb) * 16)) return -EFAULT; return 0; |