Commit e8012b584fac3a1bb70cd896612c12086d28e9ff
Committed by
Linus Torvalds
1 parent
a5f6096c80
Exists in
master
and in
7 other branches
uml: ptrace floating point fixes
Handle floating point state better in ptrace. The code now correctly distinguishes between PTRACE_[GS]ETFPREGS and PTRACE_[GS]ETFPXREGS. The FPX requests get handed off to arch-specific code because that's not generic. get_fpregs, set_fpregs, set_fpregs, and set_fpxregs needed real implementations. Something here exposed a missing include in asm/page.h, which needed linux/types.h in order to get gfp_t, so that's fixed here. Signed-off-by: Jeff Dike <jdike@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 6 changed files with 107 additions and 55 deletions Side-by-side Diff
arch/um/kernel/ptrace.c
... | ... | @@ -143,24 +143,16 @@ |
143 | 143 | #endif |
144 | 144 | #ifdef PTRACE_GETFPREGS |
145 | 145 | case PTRACE_GETFPREGS: /* Get the child FPU state. */ |
146 | - ret = get_fpregs(data, child); | |
146 | + ret = get_fpregs((struct user_i387_struct __user *) data, | |
147 | + child); | |
147 | 148 | break; |
148 | 149 | #endif |
149 | 150 | #ifdef PTRACE_SETFPREGS |
150 | 151 | case PTRACE_SETFPREGS: /* Set the child FPU state. */ |
151 | - ret = set_fpregs(data, child); | |
152 | + ret = set_fpregs((struct user_i387_struct __user *) data, | |
153 | + child); | |
152 | 154 | break; |
153 | 155 | #endif |
154 | -#ifdef PTRACE_GETFPXREGS | |
155 | - case PTRACE_GETFPXREGS: /* Get the child FPU state. */ | |
156 | - ret = get_fpxregs(data, child); | |
157 | - break; | |
158 | -#endif | |
159 | -#ifdef PTRACE_SETFPXREGS | |
160 | - case PTRACE_SETFPXREGS: /* Set the child FPU state. */ | |
161 | - ret = set_fpxregs(data, child); | |
162 | - break; | |
163 | -#endif | |
164 | 156 | case PTRACE_GET_THREAD_AREA: |
165 | 157 | ret = ptrace_get_thread_area(child, addr, |
166 | 158 | (struct user_desc __user *) data); |
... | ... | @@ -227,6 +219,8 @@ |
227 | 219 | #endif |
228 | 220 | default: |
229 | 221 | ret = ptrace_request(child, request, addr, data); |
222 | + if (ret == -EIO) | |
223 | + ret = subarch_ptrace(child, request, addr, data); | |
230 | 224 | break; |
231 | 225 | } |
232 | 226 |
arch/um/sys-i386/ptrace.c
... | ... | @@ -6,6 +6,7 @@ |
6 | 6 | #include "linux/mm.h" |
7 | 7 | #include "linux/sched.h" |
8 | 8 | #include "asm/uaccess.h" |
9 | +#include "skas.h" | |
9 | 10 | |
10 | 11 | extern int arch_switch_tls(struct task_struct *from, struct task_struct *to); |
11 | 12 | |
12 | 13 | |
13 | 14 | |
14 | 15 | |
15 | 16 | |
16 | 17 | |
17 | 18 | |
18 | 19 | |
19 | 20 | |
20 | 21 | |
21 | 22 | |
22 | 23 | |
23 | 24 | |
24 | 25 | |
25 | 26 | |
... | ... | @@ -144,48 +145,64 @@ |
144 | 145 | return put_user(tmp, (unsigned long __user *) data); |
145 | 146 | } |
146 | 147 | |
147 | -static inline int convert_fxsr_to_user(struct _fpstate __user *buf, | |
148 | - struct pt_regs *regs) | |
148 | +int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) | |
149 | 149 | { |
150 | - return 0; | |
151 | -} | |
150 | + int err, n, cpu = ((struct thread_info *) child->stack)->cpu; | |
151 | + long fpregs[HOST_FP_SIZE]; | |
152 | 152 | |
153 | -static inline int convert_fxsr_from_user(struct pt_regs *regs, | |
154 | - struct _fpstate __user *buf) | |
155 | -{ | |
156 | - return 0; | |
153 | + BUG_ON(sizeof(*buf) != sizeof(fpregs)); | |
154 | + err = save_fp_registers(userspace_pid[cpu], fpregs); | |
155 | + if (err) | |
156 | + return err; | |
157 | + | |
158 | + n = copy_to_user((void *) buf, fpregs, sizeof(fpregs)); | |
159 | + if(n > 0) | |
160 | + return -EFAULT; | |
161 | + | |
162 | + return n; | |
157 | 163 | } |
158 | 164 | |
159 | -int get_fpregs(unsigned long buf, struct task_struct *child) | |
165 | +int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) | |
160 | 166 | { |
161 | - int err; | |
167 | + int n, cpu = ((struct thread_info *) child->stack)->cpu; | |
168 | + long fpregs[HOST_FP_SIZE]; | |
162 | 169 | |
163 | - err = convert_fxsr_to_user((struct _fpstate __user *) buf, | |
164 | - &child->thread.regs); | |
165 | - if (err) | |
170 | + BUG_ON(sizeof(*buf) != sizeof(fpregs)); | |
171 | + n = copy_from_user(fpregs, (void *) buf, sizeof(fpregs)); | |
172 | + if (n > 0) | |
166 | 173 | return -EFAULT; |
167 | - return 0; | |
174 | + | |
175 | + return restore_fp_registers(userspace_pid[cpu], fpregs); | |
168 | 176 | } |
169 | 177 | |
170 | -int set_fpregs(unsigned long buf, struct task_struct *child) | |
178 | +int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) | |
171 | 179 | { |
172 | - int err; | |
180 | + int err, n, cpu = ((struct thread_info *) child->stack)->cpu; | |
181 | + long fpregs[HOST_XFP_SIZE]; | |
173 | 182 | |
174 | - err = convert_fxsr_from_user(&child->thread.regs, | |
175 | - (struct _fpstate __user *) buf); | |
183 | + BUG_ON(sizeof(*buf) != sizeof(fpregs)); | |
184 | + err = save_fpx_registers(userspace_pid[cpu], fpregs); | |
176 | 185 | if (err) |
186 | + return err; | |
187 | + | |
188 | + n = copy_to_user((void *) buf, fpregs, sizeof(fpregs)); | |
189 | + if(n > 0) | |
177 | 190 | return -EFAULT; |
178 | - return 0; | |
179 | -} | |
180 | 191 | |
181 | -int get_fpxregs(unsigned long buf, struct task_struct *tsk) | |
182 | -{ | |
183 | - return 0; | |
192 | + return n; | |
184 | 193 | } |
185 | 194 | |
186 | -int set_fpxregs(unsigned long buf, struct task_struct *tsk) | |
195 | +int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) | |
187 | 196 | { |
188 | - return 0; | |
197 | + int n, cpu = ((struct thread_info *) child->stack)->cpu; | |
198 | + long fpregs[HOST_XFP_SIZE]; | |
199 | + | |
200 | + BUG_ON(sizeof(*buf) != sizeof(fpregs)); | |
201 | + n = copy_from_user(fpregs, (void *) buf, sizeof(fpregs)); | |
202 | + if (n > 0) | |
203 | + return -EFAULT; | |
204 | + | |
205 | + return restore_fpx_registers(userspace_pid[cpu], fpregs); | |
189 | 206 | } |
190 | 207 | |
191 | 208 | #ifdef notdef |
... | ... | @@ -208,5 +225,11 @@ |
208 | 225 | int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu ) |
209 | 226 | { |
210 | 227 | return 1; |
228 | +} | |
229 | + | |
230 | +long subarch_ptrace(struct task_struct *child, long request, long addr, | |
231 | + long data) | |
232 | +{ | |
233 | + return -EIO; | |
211 | 234 | } |
arch/um/sys-x86_64/ptrace.c
... | ... | @@ -156,28 +156,53 @@ |
156 | 156 | return(instr == 0x050f); |
157 | 157 | } |
158 | 158 | |
159 | -int get_fpregs(unsigned long buf, struct task_struct *child) | |
159 | +int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) | |
160 | 160 | { |
161 | - panic("get_fpregs"); | |
162 | - return(0); | |
163 | -} | |
161 | + int err, n, cpu = ((struct thread_info *) child->stack)->cpu; | |
162 | + long fpregs[HOST_FP_SIZE]; | |
164 | 163 | |
165 | -int set_fpregs(unsigned long buf, struct task_struct *child) | |
166 | -{ | |
167 | - panic("set_fpregs"); | |
168 | - return(0); | |
164 | + BUG_ON(sizeof(*buf) != sizeof(fpregs)); | |
165 | + err = save_fp_registers(userspace_pid[cpu], fpregs); | |
166 | + if (err) | |
167 | + return err; | |
168 | + | |
169 | + n = copy_to_user((void *) buf, fpregs, sizeof(fpregs)); | |
170 | + if(n > 0) | |
171 | + return -EFAULT; | |
172 | + | |
173 | + return n; | |
169 | 174 | } |
170 | 175 | |
171 | -int get_fpxregs(unsigned long buf, struct task_struct *tsk) | |
176 | +int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) | |
172 | 177 | { |
173 | - panic("get_fpxregs"); | |
174 | - return(0); | |
178 | + int n, cpu = ((struct thread_info *) child->stack)->cpu; | |
179 | + long fpregs[HOST_FP_SIZE]; | |
180 | + | |
181 | + BUG_ON(sizeof(*buf) != sizeof(fpregs)); | |
182 | + n = copy_from_user(fpregs, (void *) buf, sizeof(fpregs)); | |
183 | + if (n > 0) | |
184 | + return -EFAULT; | |
185 | + | |
186 | + return restore_fp_registers(userspace_pid[cpu], fpregs); | |
175 | 187 | } |
176 | 188 | |
177 | -int set_fpxregs(unsigned long buf, struct task_struct *tsk) | |
189 | +long subarch_ptrace(struct task_struct *child, long request, long addr, | |
190 | + long data) | |
178 | 191 | { |
179 | - panic("set_fxpregs"); | |
180 | - return(0); | |
192 | + int ret = -EIO; | |
193 | + | |
194 | + switch (request) { | |
195 | + case PTRACE_GETFPXREGS: /* Get the child FPU state. */ | |
196 | + ret = get_fpregs((struct user_i387_struct __user *) data, | |
197 | + child); | |
198 | + break; | |
199 | + case PTRACE_SETFPXREGS: /* Set the child FPU state. */ | |
200 | + ret = set_fpregs((struct user_i387_struct __user *) data, | |
201 | + child); | |
202 | + break; | |
203 | + } | |
204 | + | |
205 | + return ret; | |
181 | 206 | } |
182 | 207 | |
183 | 208 | /* |
include/asm-um/page.h
include/asm-um/ptrace-generic.h
... | ... | @@ -9,6 +9,7 @@ |
9 | 9 | #ifndef __ASSEMBLY__ |
10 | 10 | |
11 | 11 | #include "asm/arch/ptrace-abi.h" |
12 | +#include <asm/user.h> | |
12 | 13 | #include "sysdep/ptrace.h" |
13 | 14 | |
14 | 15 | struct pt_regs { |
15 | 16 | |
... | ... | @@ -35,12 +36,14 @@ |
35 | 36 | |
36 | 37 | struct task_struct; |
37 | 38 | |
39 | +extern long subarch_ptrace(struct task_struct *child, long request, long addr, | |
40 | + long data); | |
38 | 41 | extern unsigned long getreg(struct task_struct *child, int regno); |
39 | 42 | extern int putreg(struct task_struct *child, int regno, unsigned long value); |
40 | -extern int get_fpregs(unsigned long buf, struct task_struct *child); | |
41 | -extern int set_fpregs(unsigned long buf, struct task_struct *child); | |
42 | -extern int get_fpxregs(unsigned long buf, struct task_struct *child); | |
43 | -extern int set_fpxregs(unsigned long buf, struct task_struct *tsk); | |
43 | +extern int get_fpregs(struct user_i387_struct __user *buf, | |
44 | + struct task_struct *child); | |
45 | +extern int set_fpregs(struct user_i387_struct __user *buf, | |
46 | + struct task_struct *child); | |
44 | 47 | |
45 | 48 | extern void show_regs(struct pt_regs *regs); |
46 | 49 |
include/asm-um/ptrace-i386.h
... | ... | @@ -10,6 +10,7 @@ |
10 | 10 | |
11 | 11 | #include "linux/compiler.h" |
12 | 12 | #include "asm/ptrace-generic.h" |
13 | +#include <asm/user.h> | |
13 | 14 | #include "sysdep/ptrace.h" |
14 | 15 | |
15 | 16 | #define PT_REGS_EAX(r) UPT_EAX(&(r)->regs) |
... | ... | @@ -44,6 +45,11 @@ |
44 | 45 | * circular include, and compilation failures. |
45 | 46 | */ |
46 | 47 | struct user_desc; |
48 | + | |
49 | +extern int get_fpxregs(struct user_fxsr_struct __user *buf, | |
50 | + struct task_struct *child); | |
51 | +extern int set_fpxregs(struct user_fxsr_struct __user *buf, | |
52 | + struct task_struct *tsk); | |
47 | 53 | |
48 | 54 | extern int ptrace_get_thread_area(struct task_struct *child, int idx, |
49 | 55 | struct user_desc __user *user_desc); |