diff options
author | Max Filippov <jcmvbkbc@gmail.com> | 2013-01-14 01:38:02 -0500 |
---|---|---|
committer | Chris Zankel <chris@zankel.net> | 2013-02-23 22:23:00 -0500 |
commit | 4b2bb03f108a6e68c28de2763268571ef569c6e8 (patch) | |
tree | a96f0755d533fc55af4e38a232e3f6f0359d835e | |
parent | e6ffe17ec45dd763ee8278246a112562f64a4ef2 (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.c | 33 |
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; |