aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2007-10-16 04:27:16 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-16 12:43:07 -0400
commite8012b584fac3a1bb70cd896612c12086d28e9ff (patch)
tree0ec406be2ad1878b601c6e97ad6216764ddae942
parenta5f6096c805e6d2fa03ee932f8c70af34cee41a0 (diff)
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>
-rw-r--r--arch/um/kernel/ptrace.c18
-rw-r--r--arch/um/sys-i386/ptrace.c73
-rw-r--r--arch/um/sys-x86_64/ptrace.c53
-rw-r--r--include/asm-um/page.h1
-rw-r--r--include/asm-um/ptrace-generic.h11
-rw-r--r--include/asm-um/ptrace-i386.h6
6 files changed, 107 insertions, 55 deletions
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
index db55a017e9b9..2511f9199417 100644
--- a/arch/um/kernel/ptrace.c
+++ b/arch/um/kernel/ptrace.c
@@ -143,22 +143,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
143#endif 143#endif
144#ifdef PTRACE_GETFPREGS 144#ifdef PTRACE_GETFPREGS
145 case PTRACE_GETFPREGS: /* Get the child FPU state. */ 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 break; 148 break;
148#endif 149#endif
149#ifdef PTRACE_SETFPREGS 150#ifdef PTRACE_SETFPREGS
150 case PTRACE_SETFPREGS: /* Set the child FPU state. */ 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,
152 break; 153 child);
153#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; 154 break;
163#endif 155#endif
164 case PTRACE_GET_THREAD_AREA: 156 case PTRACE_GET_THREAD_AREA:
@@ -227,6 +219,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
227#endif 219#endif
228 default: 220 default:
229 ret = ptrace_request(child, request, addr, data); 221 ret = ptrace_request(child, request, addr, data);
222 if (ret == -EIO)
223 ret = subarch_ptrace(child, request, addr, data);
230 break; 224 break;
231 } 225 }
232 226
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c
index cb899dd1c6b5..659011df1e9a 100644
--- a/arch/um/sys-i386/ptrace.c
+++ b/arch/um/sys-i386/ptrace.c
@@ -6,6 +6,7 @@
6#include "linux/mm.h" 6#include "linux/mm.h"
7#include "linux/sched.h" 7#include "linux/sched.h"
8#include "asm/uaccess.h" 8#include "asm/uaccess.h"
9#include "skas.h"
9 10
10extern int arch_switch_tls(struct task_struct *from, struct task_struct *to); 11extern int arch_switch_tls(struct task_struct *from, struct task_struct *to);
11 12
@@ -144,48 +145,64 @@ int peek_user(struct task_struct *child, long addr, long data)
144 return put_user(tmp, (unsigned long __user *) data); 145 return put_user(tmp, (unsigned long __user *) data);
145} 146}
146 147
147static inline int convert_fxsr_to_user(struct _fpstate __user *buf, 148int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
148 struct pt_regs *regs)
149{ 149{
150 return 0; 150 int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
151} 151 long fpregs[HOST_FP_SIZE];
152 152
153static inline int convert_fxsr_from_user(struct pt_regs *regs, 153 BUG_ON(sizeof(*buf) != sizeof(fpregs));
154 struct _fpstate __user *buf) 154 err = save_fp_registers(userspace_pid[cpu], fpregs);
155{ 155 if (err)
156 return 0; 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
159int get_fpregs(unsigned long buf, struct task_struct *child) 165int 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, 170 BUG_ON(sizeof(*buf) != sizeof(fpregs));
164 &child->thread.regs); 171 n = copy_from_user(fpregs, (void *) buf, sizeof(fpregs));
165 if (err) 172 if (n > 0)
166 return -EFAULT; 173 return -EFAULT;
167 return 0; 174
175 return restore_fp_registers(userspace_pid[cpu], fpregs);
168} 176}
169 177
170int set_fpregs(unsigned long buf, struct task_struct *child) 178int 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, 183 BUG_ON(sizeof(*buf) != sizeof(fpregs));
175 (struct _fpstate __user *) buf); 184 err = save_fpx_registers(userspace_pid[cpu], fpregs);
176 if (err) 185 if (err)
186 return err;
187
188 n = copy_to_user((void *) buf, fpregs, sizeof(fpregs));
189 if(n > 0)
177 return -EFAULT; 190 return -EFAULT;
178 return 0;
179}
180 191
181int get_fpxregs(unsigned long buf, struct task_struct *tsk) 192 return n;
182{
183 return 0;
184} 193}
185 194
186int set_fpxregs(unsigned long buf, struct task_struct *tsk) 195int 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#ifdef notdef 208#ifdef notdef
@@ -209,3 +226,9 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu )
209{ 226{
210 return 1; 227 return 1;
211} 228}
229
230long subarch_ptrace(struct task_struct *child, long request, long addr,
231 long data)
232{
233 return -EIO;
234}
diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c
index 1970d78aa528..b9032992a997 100644
--- a/arch/um/sys-x86_64/ptrace.c
+++ b/arch/um/sys-x86_64/ptrace.c
@@ -156,28 +156,53 @@ int is_syscall(unsigned long addr)
156 return(instr == 0x050f); 156 return(instr == 0x050f);
157} 157}
158 158
159int get_fpregs(unsigned long buf, struct task_struct *child) 159int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
160{ 160{
161 panic("get_fpregs"); 161 int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
162 return(0); 162 long fpregs[HOST_FP_SIZE];
163}
164 163
165int set_fpregs(unsigned long buf, struct task_struct *child) 164 BUG_ON(sizeof(*buf) != sizeof(fpregs));
166{ 165 err = save_fp_registers(userspace_pid[cpu], fpregs);
167 panic("set_fpregs"); 166 if (err)
168 return(0); 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
171int get_fpxregs(unsigned long buf, struct task_struct *tsk) 176int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
172{ 177{
173 panic("get_fpxregs"); 178 int n, cpu = ((struct thread_info *) child->stack)->cpu;
174 return(0); 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
177int set_fpxregs(unsigned long buf, struct task_struct *tsk) 189long subarch_ptrace(struct task_struct *child, long request, long addr,
190 long data)
178{ 191{
179 panic("set_fxpregs"); 192 int ret = -EIO;
180 return(0); 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/*
diff --git a/include/asm-um/page.h b/include/asm-um/page.h
index 8e310d81e5b4..4b424c75fca5 100644
--- a/include/asm-um/page.h
+++ b/include/asm-um/page.h
@@ -9,6 +9,7 @@
9 9
10struct page; 10struct page;
11 11
12#include <linux/types.h>
12#include <asm/vm-flags.h> 13#include <asm/vm-flags.h>
13 14
14/* PAGE_SHIFT determines the page size */ 15/* PAGE_SHIFT determines the page size */
diff --git a/include/asm-um/ptrace-generic.h b/include/asm-um/ptrace-generic.h
index 919581d713bd..6aefcd32fc61 100644
--- a/include/asm-um/ptrace-generic.h
+++ b/include/asm-um/ptrace-generic.h
@@ -9,6 +9,7 @@
9#ifndef __ASSEMBLY__ 9#ifndef __ASSEMBLY__
10 10
11#include "asm/arch/ptrace-abi.h" 11#include "asm/arch/ptrace-abi.h"
12#include <asm/user.h>
12#include "sysdep/ptrace.h" 13#include "sysdep/ptrace.h"
13 14
14struct pt_regs { 15struct pt_regs {
@@ -35,12 +36,14 @@ struct pt_regs {
35 36
36struct task_struct; 37struct task_struct;
37 38
39extern long subarch_ptrace(struct task_struct *child, long request, long addr,
40 long data);
38extern unsigned long getreg(struct task_struct *child, int regno); 41extern unsigned long getreg(struct task_struct *child, int regno);
39extern int putreg(struct task_struct *child, int regno, unsigned long value); 42extern int putreg(struct task_struct *child, int regno, unsigned long value);
40extern int get_fpregs(unsigned long buf, struct task_struct *child); 43extern int get_fpregs(struct user_i387_struct __user *buf,
41extern int set_fpregs(unsigned long buf, struct task_struct *child); 44 struct task_struct *child);
42extern int get_fpxregs(unsigned long buf, struct task_struct *child); 45extern int set_fpregs(struct user_i387_struct __user *buf,
43extern int set_fpxregs(unsigned long buf, struct task_struct *tsk); 46 struct task_struct *child);
44 47
45extern void show_regs(struct pt_regs *regs); 48extern void show_regs(struct pt_regs *regs);
46 49
diff --git a/include/asm-um/ptrace-i386.h b/include/asm-um/ptrace-i386.h
index 65102c883440..b2d24c5ea2c3 100644
--- a/include/asm-um/ptrace-i386.h
+++ b/include/asm-um/ptrace-i386.h
@@ -10,6 +10,7 @@
10 10
11#include "linux/compiler.h" 11#include "linux/compiler.h"
12#include "asm/ptrace-generic.h" 12#include "asm/ptrace-generic.h"
13#include <asm/user.h>
13#include "sysdep/ptrace.h" 14#include "sysdep/ptrace.h"
14 15
15#define PT_REGS_EAX(r) UPT_EAX(&(r)->regs) 16#define PT_REGS_EAX(r) UPT_EAX(&(r)->regs)
@@ -45,6 +46,11 @@
45 */ 46 */
46struct user_desc; 47struct user_desc;
47 48
49extern int get_fpxregs(struct user_fxsr_struct __user *buf,
50 struct task_struct *child);
51extern int set_fpxregs(struct user_fxsr_struct __user *buf,
52 struct task_struct *tsk);
53
48extern int ptrace_get_thread_area(struct task_struct *child, int idx, 54extern int ptrace_get_thread_area(struct task_struct *child, int idx,
49 struct user_desc __user *user_desc); 55 struct user_desc __user *user_desc);
50 56