]> git.openfabrics.org - ~emulex/infiniband.git/commitdiff
xtensa: complete ptrace handling of register windows
authorMax Filippov <jcmvbkbc@gmail.com>
Mon, 14 Jan 2013 06:38:02 +0000 (10:38 +0400)
committerChris Zankel <chris@zankel.net>
Sun, 24 Feb 2013 03:23:00 +0000 (19:23 -0800)
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>
arch/xtensa/kernel/ptrace.c

index 61fb2e9e903561954878c9cffc6b3e5a09577e32..a8b0d57955718f5a3d1e8aceb00ca42d8c1e5f2b 100644 (file)
@@ -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;