aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2013-01-14 01:38:02 -0500
committerChris Zankel <chris@zankel.net>2013-02-23 22:23:00 -0500
commit4b2bb03f108a6e68c28de2763268571ef569c6e8 (patch)
treea96f0755d533fc55af4e38a232e3f6f0359d835e
parente6ffe17ec45dd763ee8278246a112562f64a4ef2 (diff)
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.c33
1 files changed, 20 insertions, 13 deletions
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
index 61fb2e9e9035..a8b0d5795571 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)
53{ 53{
54 struct pt_regs *regs = task_pt_regs(child); 54 struct pt_regs *regs = task_pt_regs(child);
55 xtensa_gregset_t __user *gregset = uregs; 55 xtensa_gregset_t __user *gregset = uregs;
56 unsigned long wm = regs->wmask;
57 unsigned long wb = regs->windowbase; 56 unsigned long wb = regs->windowbase;
58 int live, i; 57 int i;
59 58
60 if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) 59 if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
61 return -EIO; 60 return -EIO;
@@ -68,12 +67,9 @@ int ptrace_getregs(struct task_struct *child, void __user *uregs)
68 __put_user(regs->windowstart, &gregset->windowstart); 67 __put_user(regs->windowstart, &gregset->windowstart);
69 __put_user(regs->windowbase, &gregset->windowbase); 68 __put_user(regs->windowbase, &gregset->windowbase);
70 69
71 live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; 70 for (i = 0; i < XCHAL_NUM_AREGS; i++)
72 71 __put_user(regs->areg[i],
73 for (i = 0; i < live; i++) 72 gregset->a + ((wb * 4 + i) % XCHAL_NUM_AREGS));
74 __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS));
75 for (i = XCHAL_NUM_AREGS - (wm >> 4) * 4; i < XCHAL_NUM_AREGS; i++)
76 __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS));
77 73
78 return 0; 74 return 0;
79} 75}
@@ -84,7 +80,7 @@ int ptrace_setregs(struct task_struct *child, void __user *uregs)
84 xtensa_gregset_t *gregset = uregs; 80 xtensa_gregset_t *gregset = uregs;
85 const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK; 81 const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK;
86 unsigned long ps; 82 unsigned long ps;
87 unsigned long wb; 83 unsigned long wb, ws;
88 84
89 if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) 85 if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
90 return -EIO; 86 return -EIO;
@@ -94,7 +90,7 @@ int ptrace_setregs(struct task_struct *child, void __user *uregs)
94 __get_user(regs->lbeg, &gregset->lbeg); 90 __get_user(regs->lbeg, &gregset->lbeg);
95 __get_user(regs->lend, &gregset->lend); 91 __get_user(regs->lend, &gregset->lend);
96 __get_user(regs->lcount, &gregset->lcount); 92 __get_user(regs->lcount, &gregset->lcount);
97 __get_user(regs->windowstart, &gregset->windowstart); 93 __get_user(ws, &gregset->windowstart);
98 __get_user(wb, &gregset->windowbase); 94 __get_user(wb, &gregset->windowbase);
99 95
100 regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT); 96 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)
102 if (wb >= XCHAL_NUM_AREGS / 4) 98 if (wb >= XCHAL_NUM_AREGS / 4)
103 return -EFAULT; 99 return -EFAULT;
104 100
105 regs->windowbase = wb; 101 if (wb != regs->windowbase || ws != regs->windowstart) {
102 unsigned long rotws, wmask;
103
104 rotws = (((ws | (ws << WSBITS)) >> wb) &
105 ((1 << WSBITS) - 1)) & ~1;
106 wmask = ((rotws ? WSBITS + 1 - ffs(rotws) : 0) << 4) |
107 (rotws & 0xF) | 1;
108 regs->windowbase = wb;
109 regs->windowstart = ws;
110 regs->wmask = wmask;
111 }
106 112
107 if (wb != 0 && __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4, 113 if (wb != 0 && __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4,
108 gregset->a, wb * 16)) 114 gregset->a, wb * 16))
109 return -EFAULT; 115 return -EFAULT;
110 116
111 if (__copy_from_user(regs->areg, gregset->a + wb*4, (WSBITS-wb) * 16)) 117 if (__copy_from_user(regs->areg, gregset->a + wb * 4,
118 (WSBITS - wb) * 16))
112 return -EFAULT; 119 return -EFAULT;
113 120
114 return 0; 121 return 0;