diff options
author | Paul Mundt <lethal@linux-sh.org> | 2008-09-21 06:04:55 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2008-09-21 06:04:55 -0400 |
commit | e7ab3cd251926d57ee11d7d320e8fb42c882ad22 (patch) | |
tree | 29dce1711413e010d30fb62c43cbe517a9de95bc /arch/sh | |
parent | 4b4cf7595a8bce9b4dd64c241a8cb7336ecb9489 (diff) |
sh: Add FPU registers to regset interface.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh')
-rw-r--r-- | arch/sh/Kconfig | 2 | ||||
-rw-r--r-- | arch/sh/include/asm/elf.h | 6 | ||||
-rw-r--r-- | arch/sh/include/asm/fpu.h | 19 | ||||
-rw-r--r-- | arch/sh/kernel/process_32.c | 14 | ||||
-rw-r--r-- | arch/sh/kernel/ptrace_32.c | 76 |
5 files changed, 108 insertions, 9 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 38a5a9edb677..71be7ff5c771 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig | |||
@@ -23,7 +23,7 @@ config SUPERH32 | |||
23 | def_bool !SUPERH64 | 23 | def_bool !SUPERH64 |
24 | select HAVE_KPROBES | 24 | select HAVE_KPROBES |
25 | select HAVE_KRETPROBES | 25 | select HAVE_KRETPROBES |
26 | select HAVE_ARCH_TRACEHOOK if !SH_FPU | 26 | select HAVE_ARCH_TRACEHOOK |
27 | select HAVE_FTRACE | 27 | select HAVE_FTRACE |
28 | 28 | ||
29 | config SUPERH64 | 29 | config SUPERH64 |
diff --git a/arch/sh/include/asm/elf.h b/arch/sh/include/asm/elf.h index 6b2cec80fd15..4da3a0b10911 100644 --- a/arch/sh/include/asm/elf.h +++ b/arch/sh/include/asm/elf.h | |||
@@ -108,10 +108,10 @@ typedef struct user_fpu_struct elf_fpregset_t; | |||
108 | #define elf_check_fdpic(x) ((x)->e_flags & EF_SH_FDPIC) | 108 | #define elf_check_fdpic(x) ((x)->e_flags & EF_SH_FDPIC) |
109 | #define elf_check_const_displacement(x) ((x)->e_flags & EF_SH_PIC) | 109 | #define elf_check_const_displacement(x) ((x)->e_flags & EF_SH_PIC) |
110 | 110 | ||
111 | #if defined(CONFIG_SUPERH32) && !defined(CONFIG_SH_FPU) | 111 | #ifdef CONFIG_SUPERH32 |
112 | /* | 112 | /* |
113 | * Enable dump using regset for general purpose registers, use this as | 113 | * Enable dump using regset. |
114 | * the default once the FPU registers are moved over also. | 114 | * This covers all of general/DSP/FPU regs. |
115 | */ | 115 | */ |
116 | #define CORE_DUMP_USE_REGSET | 116 | #define CORE_DUMP_USE_REGSET |
117 | #endif | 117 | #endif |
diff --git a/arch/sh/include/asm/fpu.h b/arch/sh/include/asm/fpu.h index 91462fea1507..1d3aee04b5cc 100644 --- a/arch/sh/include/asm/fpu.h +++ b/arch/sh/include/asm/fpu.h | |||
@@ -30,8 +30,15 @@ static inline void save_fpu(struct task_struct *tsk, struct pt_regs *regs) | |||
30 | } | 30 | } |
31 | #endif | 31 | #endif |
32 | 32 | ||
33 | struct user_regset; | ||
34 | |||
33 | extern int do_fpu_inst(unsigned short, struct pt_regs *); | 35 | extern int do_fpu_inst(unsigned short, struct pt_regs *); |
34 | 36 | ||
37 | extern int fpregs_get(struct task_struct *target, | ||
38 | const struct user_regset *regset, | ||
39 | unsigned int pos, unsigned int count, | ||
40 | void *kbuf, void __user *ubuf); | ||
41 | |||
35 | static inline void unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs) | 42 | static inline void unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs) |
36 | { | 43 | { |
37 | preempt_disable(); | 44 | preempt_disable(); |
@@ -50,6 +57,18 @@ static inline void clear_fpu(struct task_struct *tsk, struct pt_regs *regs) | |||
50 | preempt_enable(); | 57 | preempt_enable(); |
51 | } | 58 | } |
52 | 59 | ||
60 | static inline int init_fpu(struct task_struct *tsk) | ||
61 | { | ||
62 | if (tsk_used_math(tsk)) { | ||
63 | if ((boot_cpu_data.flags & CPU_HAS_FPU) && tsk == current) | ||
64 | unlazy_fpu(tsk, task_pt_regs(tsk)); | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | set_stopped_child_used_math(tsk); | ||
69 | return 0; | ||
70 | } | ||
71 | |||
53 | #endif /* __ASSEMBLY__ */ | 72 | #endif /* __ASSEMBLY__ */ |
54 | 73 | ||
55 | #endif /* __ASM_SH_FPU_H */ | 74 | #endif /* __ASM_SH_FPU_H */ |
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index 7b013aa8c43f..b965f0282c7d 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c | |||
@@ -7,7 +7,11 @@ | |||
7 | * | 7 | * |
8 | * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima | 8 | * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima |
9 | * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC | 9 | * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC |
10 | * Copyright (C) 2002 - 2007 Paul Mundt | 10 | * Copyright (C) 2002 - 2008 Paul Mundt |
11 | * | ||
12 | * This file is subject to the terms and conditions of the GNU General Public | ||
13 | * License. See the file "COPYING" in the main directory of this archive | ||
14 | * for more details. | ||
11 | */ | 15 | */ |
12 | #include <linux/module.h> | 16 | #include <linux/module.h> |
13 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
@@ -222,10 +226,10 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | |||
222 | struct task_struct *tsk = current; | 226 | struct task_struct *tsk = current; |
223 | 227 | ||
224 | fpvalid = !!tsk_used_math(tsk); | 228 | fpvalid = !!tsk_used_math(tsk); |
225 | if (fpvalid) { | 229 | if (fpvalid) |
226 | unlazy_fpu(tsk, regs); | 230 | fpvalid = !fpregs_get(tsk, NULL, 0, |
227 | memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu)); | 231 | sizeof(struct user_fpu_struct), |
228 | } | 232 | fpu, NULL); |
229 | #endif | 233 | #endif |
230 | 234 | ||
231 | return fpvalid; | 235 | return fpvalid; |
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 0f44f2b51a60..29ca09d24ef8 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <asm/processor.h> | 32 | #include <asm/processor.h> |
33 | #include <asm/mmu_context.h> | 33 | #include <asm/mmu_context.h> |
34 | #include <asm/syscalls.h> | 34 | #include <asm/syscalls.h> |
35 | #include <asm/fpu.h> | ||
35 | 36 | ||
36 | /* | 37 | /* |
37 | * This routine will get a word off of the process kernel stack. | 38 | * This routine will get a word off of the process kernel stack. |
@@ -145,6 +146,54 @@ static int genregs_set(struct task_struct *target, | |||
145 | return ret; | 146 | return ret; |
146 | } | 147 | } |
147 | 148 | ||
149 | #ifdef CONFIG_SH_FPU | ||
150 | int fpregs_get(struct task_struct *target, | ||
151 | const struct user_regset *regset, | ||
152 | unsigned int pos, unsigned int count, | ||
153 | void *kbuf, void __user *ubuf) | ||
154 | { | ||
155 | int ret; | ||
156 | |||
157 | ret = init_fpu(target); | ||
158 | if (ret) | ||
159 | return ret; | ||
160 | |||
161 | if ((boot_cpu_data.flags & CPU_HAS_FPU)) | ||
162 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
163 | &target->thread.fpu.hard, 0, -1); | ||
164 | |||
165 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
166 | &target->thread.fpu.soft, 0, -1); | ||
167 | } | ||
168 | |||
169 | static int fpregs_set(struct task_struct *target, | ||
170 | const struct user_regset *regset, | ||
171 | unsigned int pos, unsigned int count, | ||
172 | const void *kbuf, const void __user *ubuf) | ||
173 | { | ||
174 | int ret; | ||
175 | |||
176 | ret = init_fpu(target); | ||
177 | if (ret) | ||
178 | return ret; | ||
179 | |||
180 | set_stopped_child_used_math(target); | ||
181 | |||
182 | if ((boot_cpu_data.flags & CPU_HAS_FPU)) | ||
183 | return user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
184 | &target->thread.fpu.hard, 0, -1); | ||
185 | |||
186 | return user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
187 | &target->thread.fpu.soft, 0, -1); | ||
188 | } | ||
189 | |||
190 | static int fpregs_active(struct task_struct *target, | ||
191 | const struct user_regset *regset) | ||
192 | { | ||
193 | return tsk_used_math(target) ? regset->n : 0; | ||
194 | } | ||
195 | #endif | ||
196 | |||
148 | #ifdef CONFIG_SH_DSP | 197 | #ifdef CONFIG_SH_DSP |
149 | static int dspregs_get(struct task_struct *target, | 198 | static int dspregs_get(struct task_struct *target, |
150 | const struct user_regset *regset, | 199 | const struct user_regset *regset, |
@@ -194,6 +243,9 @@ static int dspregs_active(struct task_struct *target, | |||
194 | */ | 243 | */ |
195 | enum sh_regset { | 244 | enum sh_regset { |
196 | REGSET_GENERAL, | 245 | REGSET_GENERAL, |
246 | #ifdef CONFIG_SH_FPU | ||
247 | REGSET_FPU, | ||
248 | #endif | ||
197 | #ifdef CONFIG_SH_DSP | 249 | #ifdef CONFIG_SH_DSP |
198 | REGSET_DSP, | 250 | REGSET_DSP, |
199 | #endif | 251 | #endif |
@@ -214,6 +266,18 @@ static const struct user_regset sh_regsets[] = { | |||
214 | .set = genregs_set, | 266 | .set = genregs_set, |
215 | }, | 267 | }, |
216 | 268 | ||
269 | #ifdef CONFIG_SH_FPU | ||
270 | [REGSET_FPU] = { | ||
271 | .core_note_type = NT_PRFPREG, | ||
272 | .n = sizeof(struct user_fpu_struct) / sizeof(long), | ||
273 | .size = sizeof(long), | ||
274 | .align = sizeof(long), | ||
275 | .get = fpregs_get, | ||
276 | .set = fpregs_set, | ||
277 | .active = fpregs_active, | ||
278 | }, | ||
279 | #endif | ||
280 | |||
217 | #ifdef CONFIG_SH_DSP | 281 | #ifdef CONFIG_SH_DSP |
218 | [REGSET_DSP] = { | 282 | [REGSET_DSP] = { |
219 | .n = sizeof(struct pt_dspregs) / sizeof(long), | 283 | .n = sizeof(struct pt_dspregs) / sizeof(long), |
@@ -304,6 +368,18 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
304 | REGSET_GENERAL, | 368 | REGSET_GENERAL, |
305 | 0, sizeof(struct pt_regs), | 369 | 0, sizeof(struct pt_regs), |
306 | (const void __user *)data); | 370 | (const void __user *)data); |
371 | #ifdef CONFIG_SH_FPU | ||
372 | case PTRACE_GETFPREGS: | ||
373 | return copy_regset_to_user(child, &user_sh_native_view, | ||
374 | REGSET_FPU, | ||
375 | 0, sizeof(struct user_fpu_struct), | ||
376 | (void __user *)data); | ||
377 | case PTRACE_SETFPREGS: | ||
378 | return copy_regset_from_user(child, &user_sh_native_view, | ||
379 | REGSET_FPU, | ||
380 | 0, sizeof(struct user_fpu_struct), | ||
381 | (const void __user *)data); | ||
382 | #endif | ||
307 | #ifdef CONFIG_SH_DSP | 383 | #ifdef CONFIG_SH_DSP |
308 | case PTRACE_GETDSPREGS: | 384 | case PTRACE_GETDSPREGS: |
309 | return copy_regset_to_user(child, &user_sh_native_view, | 385 | return copy_regset_to_user(child, &user_sh_native_view, |