diff options
author | Mike Frysinger <vapier@gentoo.org> | 2010-02-14 17:58:02 -0500 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2010-03-09 00:30:51 -0500 |
commit | e50e2f25c5b90abd00a1e5871c45094cf5207afc (patch) | |
tree | 22c550f642bbc390c4713fa7d0dd8e1bab2ea4a0 /arch | |
parent | f2ce48024a9a6d3e92a023ded0f7b1e99da1cd16 (diff) |
Blackfin: initial regset support
We don't support core dumps (yet?), but this should make things easier.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/blackfin/include/asm/elf.h | 8 | ||||
-rw-r--r-- | arch/blackfin/kernel/process.c | 7 | ||||
-rw-r--r-- | arch/blackfin/kernel/ptrace.c | 113 |
3 files changed, 97 insertions, 31 deletions
diff --git a/arch/blackfin/include/asm/elf.h b/arch/blackfin/include/asm/elf.h index 5b50f0ecacf..117713adea7 100644 --- a/arch/blackfin/include/asm/elf.h +++ b/arch/blackfin/include/asm/elf.h | |||
@@ -22,12 +22,15 @@ | |||
22 | #define EF_BFIN_CODE_IN_L2 0x00000040 /* --code-in-l2 */ | 22 | #define EF_BFIN_CODE_IN_L2 0x00000040 /* --code-in-l2 */ |
23 | #define EF_BFIN_DATA_IN_L2 0x00000080 /* --data-in-l2 */ | 23 | #define EF_BFIN_DATA_IN_L2 0x00000080 /* --data-in-l2 */ |
24 | 24 | ||
25 | #if 1 /* core dumps not supported, but linux/elfcore.h needs these */ | ||
25 | typedef unsigned long elf_greg_t; | 26 | typedef unsigned long elf_greg_t; |
26 | 27 | ||
27 | #define ELF_NGREG 40 /* (sizeof(struct user_regs_struct) / sizeof(elf_greg_t)) */ | 28 | #define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t)) |
28 | typedef elf_greg_t elf_gregset_t[ELF_NGREG]; | 29 | typedef elf_greg_t elf_gregset_t[ELF_NGREG]; |
29 | 30 | ||
30 | typedef struct { } elf_fpregset_t; | 31 | typedef struct { } elf_fpregset_t; |
32 | #endif | ||
33 | |||
31 | /* | 34 | /* |
32 | * This is used to ensure we don't load something for the wrong architecture. | 35 | * This is used to ensure we don't load something for the wrong architecture. |
33 | */ | 36 | */ |
@@ -55,6 +58,9 @@ do { \ | |||
55 | _regs->p2 = _dynamic_addr; \ | 58 | _regs->p2 = _dynamic_addr; \ |
56 | } while(0) | 59 | } while(0) |
57 | 60 | ||
61 | #if 0 | ||
62 | #define CORE_DUMP_USE_REGSET | ||
63 | #endif | ||
58 | #define ELF_FDPIC_CORE_EFLAGS EF_BFIN_FDPIC | 64 | #define ELF_FDPIC_CORE_EFLAGS EF_BFIN_FDPIC |
59 | #define ELF_EXEC_PAGESIZE 4096 | 65 | #define ELF_EXEC_PAGESIZE 4096 |
60 | 66 | ||
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index b56b0e485e0..29705cec91d 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c | |||
@@ -98,13 +98,6 @@ void cpu_idle(void) | |||
98 | } | 98 | } |
99 | } | 99 | } |
100 | 100 | ||
101 | /* Fill in the fpu structure for a core dump. */ | ||
102 | |||
103 | int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs) | ||
104 | { | ||
105 | return 1; | ||
106 | } | ||
107 | |||
108 | /* | 101 | /* |
109 | * This gets run with P1 containing the | 102 | * This gets run with P1 containing the |
110 | * function to call, and R1 containing | 103 | * function to call, and R1 containing |
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index 9536c1e2d1c..92b4ca0b5af 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c | |||
@@ -9,9 +9,11 @@ | |||
9 | #include <linux/sched.h> | 9 | #include <linux/sched.h> |
10 | #include <linux/mm.h> | 10 | #include <linux/mm.h> |
11 | #include <linux/smp.h> | 11 | #include <linux/smp.h> |
12 | #include <linux/elf.h> | ||
12 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
13 | #include <linux/ptrace.h> | 14 | #include <linux/ptrace.h> |
14 | #include <linux/user.h> | 15 | #include <linux/user.h> |
16 | #include <linux/regset.h> | ||
15 | #include <linux/signal.h> | 17 | #include <linux/signal.h> |
16 | #include <linux/uaccess.h> | 18 | #include <linux/uaccess.h> |
17 | 19 | ||
@@ -50,22 +52,6 @@ static inline struct pt_regs *task_pt_regs(struct task_struct *task) | |||
50 | } | 52 | } |
51 | 53 | ||
52 | /* | 54 | /* |
53 | * Get all user integer registers. | ||
54 | */ | ||
55 | static inline int ptrace_getregs(struct task_struct *tsk, void __user *uregs) | ||
56 | { | ||
57 | struct pt_regs regs; | ||
58 | memcpy(®s, task_pt_regs(tsk), sizeof(regs)); | ||
59 | regs.usp = tsk->thread.usp; | ||
60 | return copy_to_user(uregs, ®s, sizeof(struct pt_regs)) ? -EFAULT : 0; | ||
61 | } | ||
62 | |||
63 | /* Mapping from PT_xxx to the stack offset at which the register is | ||
64 | * saved. Notice that usp has no stack-slot and needs to be treated | ||
65 | * specially (see get_reg/put_reg below). | ||
66 | */ | ||
67 | |||
68 | /* | ||
69 | * Get contents of register REGNO in task TASK. | 55 | * Get contents of register REGNO in task TASK. |
70 | */ | 56 | */ |
71 | static inline long | 57 | static inline long |
@@ -170,6 +156,84 @@ static inline int is_user_addr_valid(struct task_struct *child, | |||
170 | return -EIO; | 156 | return -EIO; |
171 | } | 157 | } |
172 | 158 | ||
159 | /* | ||
160 | * retrieve the contents of Blackfin userspace general registers | ||
161 | */ | ||
162 | static int genregs_get(struct task_struct *target, | ||
163 | const struct user_regset *regset, | ||
164 | unsigned int pos, unsigned int count, | ||
165 | void *kbuf, void __user *ubuf) | ||
166 | { | ||
167 | struct pt_regs *regs = task_pt_regs(target); | ||
168 | int ret; | ||
169 | |||
170 | /* This sucks ... */ | ||
171 | regs->usp = target->thread.usp; | ||
172 | |||
173 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
174 | regs, 0, sizeof(*regs)); | ||
175 | if (ret < 0) | ||
176 | return ret; | ||
177 | |||
178 | return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
179 | sizeof(*regs), -1); | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * update the contents of the Blackfin userspace general registers | ||
184 | */ | ||
185 | static int genregs_set(struct task_struct *target, | ||
186 | const struct user_regset *regset, | ||
187 | unsigned int pos, unsigned int count, | ||
188 | const void *kbuf, const void __user *ubuf) | ||
189 | { | ||
190 | struct pt_regs *regs = task_pt_regs(target); | ||
191 | int ret; | ||
192 | |||
193 | /* Don't let people set SYSCFG (it's at the end of pt_regs) */ | ||
194 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
195 | regs, 0, PT_SYSCFG); | ||
196 | if (ret < 0) | ||
197 | return ret; | ||
198 | |||
199 | /* This sucks ... */ | ||
200 | target->thread.usp = regs->usp; | ||
201 | /* regs->retx = regs->pc; */ | ||
202 | |||
203 | return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
204 | PT_SYSCFG, -1); | ||
205 | } | ||
206 | |||
207 | /* | ||
208 | * Define the register sets available on the Blackfin under Linux | ||
209 | */ | ||
210 | enum bfin_regset { | ||
211 | REGSET_GENERAL, | ||
212 | }; | ||
213 | |||
214 | static const struct user_regset bfin_regsets[] = { | ||
215 | [REGSET_GENERAL] = { | ||
216 | .core_note_type = NT_PRSTATUS, | ||
217 | .n = sizeof(struct pt_regs) / sizeof(long), | ||
218 | .size = sizeof(long), | ||
219 | .align = sizeof(long), | ||
220 | .get = genregs_get, | ||
221 | .set = genregs_set, | ||
222 | }, | ||
223 | }; | ||
224 | |||
225 | static const struct user_regset_view user_bfin_native_view = { | ||
226 | .name = "Blackfin", | ||
227 | .e_machine = EM_BLACKFIN, | ||
228 | .regsets = bfin_regsets, | ||
229 | .n = ARRAY_SIZE(bfin_regsets), | ||
230 | }; | ||
231 | |||
232 | const struct user_regset_view *task_user_regset_view(struct task_struct *task) | ||
233 | { | ||
234 | return &user_bfin_native_view; | ||
235 | } | ||
236 | |||
173 | void ptrace_enable(struct task_struct *child) | 237 | void ptrace_enable(struct task_struct *child) |
174 | { | 238 | { |
175 | struct pt_regs *regs = task_pt_regs(child); | 239 | struct pt_regs *regs = task_pt_regs(child); |
@@ -327,15 +391,18 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
327 | break; | 391 | break; |
328 | 392 | ||
329 | case PTRACE_GETREGS: | 393 | case PTRACE_GETREGS: |
330 | /* Get all gp regs from the child. */ | 394 | pr_debug("ptrace: PTRACE_GETREGS\n"); |
331 | ret = ptrace_getregs(child, datap); | 395 | return copy_regset_to_user(child, &user_bfin_native_view, |
332 | break; | 396 | REGSET_GENERAL, |
397 | 0, sizeof(struct pt_regs), | ||
398 | (void __user *)data); | ||
333 | 399 | ||
334 | case PTRACE_SETREGS: | 400 | case PTRACE_SETREGS: |
335 | printk(KERN_WARNING "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n"); | 401 | pr_debug("ptrace: PTRACE_SETREGS\n"); |
336 | /* Set all gp regs in the child. */ | 402 | return copy_regset_from_user(child, &user_bfin_native_view, |
337 | ret = 0; | 403 | REGSET_GENERAL, |
338 | break; | 404 | 0, sizeof(struct pt_regs), |
405 | (const void __user *)data); | ||
339 | 406 | ||
340 | default: | 407 | default: |
341 | ret = ptrace_request(child, request, addr, data); | 408 | ret = ptrace_request(child, request, addr, data); |