aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Zankel <chris@zankel.net>2008-01-28 18:55:01 -0500
committerChris Zankel <chris@zankel.net>2008-02-13 20:45:36 -0500
commit42086cec3263b8c015ca3faa01e8190f0e3ff445 (patch)
treec28564042c13ee09e652dc176b6f8cd87ce10359
parentbdd362ff4ff8dc0c697ce87dbb337f3b7341fc46 (diff)
[XTENSA] Allow debugger to modify the WINDOWBASE register.
For the 'return' command, GDB needs to adjust WINDOWBASE. In case WB is different from 0, we need to rotate the window register file and update WINDOWSTART and WMASK. This patch also removes some ret|= statements for __get_user/__put_user as the address range was alrady checked a couple of lines earlier. Signed-off-by: Chris Zankel <chris@zankel.net>
-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)
43{ 43{
44 struct pt_regs *regs = task_pt_regs(child); 44 struct pt_regs *regs = task_pt_regs(child);
45 xtensa_gregset_t __user *gregset = uregs; 45 xtensa_gregset_t __user *gregset = uregs;
46 unsigned long wb = regs->windowbase;
47 unsigned long ws = regs->windowstart;
48 unsigned long wm = regs->wmask; 46 unsigned long wm = regs->wmask;
49 int ret = 0; 47 unsigned long wb = regs->windowbase;
50 int live, last; 48 int live, i;
51 49
52 if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) 50 if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
53 return -EIO; 51 return -EIO;
54 52
55 /* Norm windowstart to a windowbase of 0. */ 53 __put_user(regs->pc, &gregset->pc);
56 54 __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps);
57 ws = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<<WSBITS)-1); 55 __put_user(regs->lbeg, &gregset->lbeg);
58 56 __put_user(regs->lend, &gregset->lend);
59 ret |= __put_user(regs->pc, &gregset->pc); 57 __put_user(regs->lcount, &gregset->lcount);
60 ret |= __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps); 58 __put_user(regs->windowstart, &gregset->windowstart);
61 ret |= __put_user(regs->lbeg, &gregset->lbeg); 59 __put_user(regs->windowbase, &gregset->windowbase);
62 ret |= __put_user(regs->lend, &gregset->lend);
63 ret |= __put_user(regs->lcount, &gregset->lcount);
64 ret |= __put_user(ws, &gregset->windowstart);
65 60
66 live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; 61 live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16;
67 last = XCHAL_NUM_AREGS - (wm >> 4) * 4;
68 ret |= __copy_to_user(gregset->a, regs->areg, live * 4);
69 ret |= __copy_to_user(gregset->a + last, regs->areg + last, (wm>>4)*16);
70 62
71 return ret ? -EFAULT : 0; 63 for (i = 0; i < live; i++)
64 __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS));
65 for (i = XCHAL_NUM_AREGS - (wm >> 4) * 4; i < XCHAL_NUM_AREGS; i++)
66 __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS));
67
68 return 0;
72} 69}
73 70
74int ptrace_setregs(struct task_struct *child, void __user *uregs) 71int ptrace_setregs(struct task_struct *child, void __user *uregs)
@@ -76,28 +73,35 @@ int ptrace_setregs(struct task_struct *child, void __user *uregs)
76 struct pt_regs *regs = task_pt_regs(child); 73 struct pt_regs *regs = task_pt_regs(child);
77 xtensa_gregset_t *gregset = uregs; 74 xtensa_gregset_t *gregset = uregs;
78 const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK; 75 const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK;
79 unsigned long wm = regs->wmask;
80 unsigned long ps; 76 unsigned long ps;
81 int ret = 0; 77 unsigned long wb;
82 int live, last;
83 78
84 if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) 79 if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
85 return -EIO; 80 return -EIO;
86 81
87 ret |= __get_user(regs->pc, &gregset->pc); 82 __get_user(regs->pc, &gregset->pc);
88 ret |= __get_user(ps, &gregset->ps); 83 __get_user(ps, &gregset->ps);
89 ret |= __get_user(regs->lbeg, &gregset->lbeg); 84 __get_user(regs->lbeg, &gregset->lbeg);
90 ret |= __get_user(regs->lend, &gregset->lend); 85 __get_user(regs->lend, &gregset->lend);
91 ret |= __get_user(regs->lcount, &gregset->lcount); 86 __get_user(regs->lcount, &gregset->lcount);
87 __get_user(regs->windowstart, &gregset->windowstart);
88 __get_user(wb, &gregset->windowbase);
92 89
93 regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT); 90 regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT);
94 91
95 live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; 92 if (wb >= XCHAL_NUM_AREGS / 4)
96 last = XCHAL_NUM_AREGS - (wm >> 4) * 4; 93 return -EFAULT;
97 ret |= __copy_from_user(regs->areg, gregset->a, live * 4);
98 ret |= __copy_from_user(regs->areg+last, gregset->a+last, (wm>>4)*16);
99 94
100 return ret ? -EFAULT : 0; 95 regs->windowbase = wb;
96
97 if (wb != 0 && __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4,
98 gregset->a, wb * 16))
99 return -EFAULT;
100
101 if (__copy_from_user(regs->areg, gregset->a + wb*4, (WSBITS-wb) * 16))
102 return -EFAULT;
103
104 return 0;
101} 105}
102 106
103 107
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 {
82 elf_greg_t lcount; 82 elf_greg_t lcount;
83 elf_greg_t sar; 83 elf_greg_t sar;
84 elf_greg_t windowstart; 84 elf_greg_t windowstart;
85 elf_greg_t reserved[9+48]; 85 elf_greg_t windowbase;
86 elf_greg_t reserved[8+48];
86 elf_greg_t a[64]; 87 elf_greg_t a[64];
87} xtensa_gregset_t; 88} xtensa_gregset_t;
88 89