Commit e8012b584fac3a1bb70cd896612c12086d28e9ff

Authored by Jeff Dike
Committed by Linus Torvalds
1 parent a5f6096c80

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
... ... @@ -9,6 +9,7 @@
9 9  
10 10 struct page;
11 11  
  12 +#include <linux/types.h>
12 13 #include <asm/vm-flags.h>
13 14  
14 15 /* PAGE_SHIFT determines the page size */
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);