um: take arch/um/sys-x86 to arch/x86/um
[pandora-kernel.git] / arch / x86 / um / ptrace_32.c
1 /*
2  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3  * Licensed under the GPL
4  */
5
6 #include "linux/mm.h"
7 #include "linux/sched.h"
8 #include "asm/uaccess.h"
9 #include "skas.h"
10
11 extern int arch_switch_tls(struct task_struct *to);
12
13 void arch_switch_to(struct task_struct *to)
14 {
15         int err = arch_switch_tls(to);
16         if (!err)
17                 return;
18
19         if (err != -EINVAL)
20                 printk(KERN_WARNING "arch_switch_tls failed, errno %d, "
21                        "not EINVAL\n", -err);
22         else
23                 printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n");
24 }
25
26 int is_syscall(unsigned long addr)
27 {
28         unsigned short instr;
29         int n;
30
31         n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
32         if (n) {
33                 /* access_process_vm() grants access to vsyscall and stub,
34                  * while copy_from_user doesn't. Maybe access_process_vm is
35                  * slow, but that doesn't matter, since it will be called only
36                  * in case of singlestepping, if copy_from_user failed.
37                  */
38                 n = access_process_vm(current, addr, &instr, sizeof(instr), 0);
39                 if (n != sizeof(instr)) {
40                         printk(KERN_ERR "is_syscall : failed to read "
41                                "instruction from 0x%lx\n", addr);
42                         return 1;
43                 }
44         }
45         /* int 0x80 or sysenter */
46         return (instr == 0x80cd) || (instr == 0x340f);
47 }
48
49 /* determines which flags the user has access to. */
50 /* 1 = access 0 = no access */
51 #define FLAG_MASK 0x00044dd5
52
53 static const int reg_offsets[] = {
54         [EBX] = HOST_EBX,
55         [ECX] = HOST_ECX,
56         [EDX] = HOST_EDX,
57         [ESI] = HOST_ESI,
58         [EDI] = HOST_EDI,
59         [EBP] = HOST_EBP,
60         [EAX] = HOST_EAX,
61         [DS] = HOST_DS,
62         [ES] = HOST_ES,
63         [FS] = HOST_FS,
64         [GS] = HOST_GS,
65         [EIP] = HOST_IP,
66         [CS] = HOST_CS,
67         [EFL] = HOST_EFLAGS,
68         [UESP] = HOST_SP,
69         [SS] = HOST_SS,
70 };
71
72 int putreg(struct task_struct *child, int regno, unsigned long value)
73 {
74         regno >>= 2;
75         switch (regno) {
76         case EBX:
77         case ECX:
78         case EDX:
79         case ESI:
80         case EDI:
81         case EBP:
82         case EAX:
83         case EIP:
84         case UESP:
85                 break;
86         case FS:
87                 if (value && (value & 3) != 3)
88                         return -EIO;
89                 break;
90         case GS:
91                 if (value && (value & 3) != 3)
92                         return -EIO;
93                 break;
94         case DS:
95         case ES:
96                 if (value && (value & 3) != 3)
97                         return -EIO;
98                 value &= 0xffff;
99                 break;
100         case SS:
101         case CS:
102                 if ((value & 3) != 3)
103                         return -EIO;
104                 value &= 0xffff;
105                 break;
106         case EFL:
107                 value &= FLAG_MASK;
108                 child->thread.regs.regs.gp[HOST_EFLAGS] |= value;
109                 return 0;
110         case ORIG_EAX:
111                 child->thread.regs.regs.syscall = value;
112                 return 0;
113         default :
114                 panic("Bad register in putreg() : %d\n", regno);
115         }
116         child->thread.regs.regs.gp[reg_offsets[regno]] = value;
117         return 0;
118 }
119
120 int poke_user(struct task_struct *child, long addr, long data)
121 {
122         if ((addr & 3) || addr < 0)
123                 return -EIO;
124
125         if (addr < MAX_REG_OFFSET)
126                 return putreg(child, addr, data);
127         else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
128                  (addr <= offsetof(struct user, u_debugreg[7]))) {
129                 addr -= offsetof(struct user, u_debugreg[0]);
130                 addr = addr >> 2;
131                 if ((addr == 4) || (addr == 5))
132                         return -EIO;
133                 child->thread.arch.debugregs[addr] = data;
134                 return 0;
135         }
136         return -EIO;
137 }
138
139 unsigned long getreg(struct task_struct *child, int regno)
140 {
141         unsigned long mask = ~0UL;
142
143         regno >>= 2;
144         switch (regno) {
145         case ORIG_EAX:
146                 return child->thread.regs.regs.syscall;
147         case FS:
148         case GS:
149         case DS:
150         case ES:
151         case SS:
152         case CS:
153                 mask = 0xffff;
154                 break;
155         case EIP:
156         case UESP:
157         case EAX:
158         case EBX:
159         case ECX:
160         case EDX:
161         case ESI:
162         case EDI:
163         case EBP:
164         case EFL:
165                 break;
166         default:
167                 panic("Bad register in getreg() : %d\n", regno);
168         }
169         return mask & child->thread.regs.regs.gp[reg_offsets[regno]];
170 }
171
172 /* read the word at location addr in the USER area. */
173 int peek_user(struct task_struct *child, long addr, long data)
174 {
175         unsigned long tmp;
176
177         if ((addr & 3) || addr < 0)
178                 return -EIO;
179
180         tmp = 0;  /* Default return condition */
181         if (addr < MAX_REG_OFFSET) {
182                 tmp = getreg(child, addr);
183         }
184         else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
185                  (addr <= offsetof(struct user, u_debugreg[7]))) {
186                 addr -= offsetof(struct user, u_debugreg[0]);
187                 addr = addr >> 2;
188                 tmp = child->thread.arch.debugregs[addr];
189         }
190         return put_user(tmp, (unsigned long __user *) data);
191 }
192
193 static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
194 {
195         int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
196         struct user_i387_struct fpregs;
197
198         err = save_fp_registers(userspace_pid[cpu], (unsigned long *) &fpregs);
199         if (err)
200                 return err;
201
202         n = copy_to_user(buf, &fpregs, sizeof(fpregs));
203         if(n > 0)
204                 return -EFAULT;
205
206         return n;
207 }
208
209 static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
210 {
211         int n, cpu = ((struct thread_info *) child->stack)->cpu;
212         struct user_i387_struct fpregs;
213
214         n = copy_from_user(&fpregs, buf, sizeof(fpregs));
215         if (n > 0)
216                 return -EFAULT;
217
218         return restore_fp_registers(userspace_pid[cpu],
219                                     (unsigned long *) &fpregs);
220 }
221
222 static int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
223 {
224         int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
225         struct user_fxsr_struct fpregs;
226
227         err = save_fpx_registers(userspace_pid[cpu], (unsigned long *) &fpregs);
228         if (err)
229                 return err;
230
231         n = copy_to_user(buf, &fpregs, sizeof(fpregs));
232         if(n > 0)
233                 return -EFAULT;
234
235         return n;
236 }
237
238 static int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
239 {
240         int n, cpu = ((struct thread_info *) child->stack)->cpu;
241         struct user_fxsr_struct fpregs;
242
243         n = copy_from_user(&fpregs, buf, sizeof(fpregs));
244         if (n > 0)
245                 return -EFAULT;
246
247         return restore_fpx_registers(userspace_pid[cpu],
248                                      (unsigned long *) &fpregs);
249 }
250
251 long subarch_ptrace(struct task_struct *child, long request,
252                     unsigned long addr, unsigned long data)
253 {
254         int ret = -EIO;
255         void __user *datap = (void __user *) data;
256         switch (request) {
257         case PTRACE_GETFPREGS: /* Get the child FPU state. */
258                 ret = get_fpregs(datap, child);
259                 break;
260         case PTRACE_SETFPREGS: /* Set the child FPU state. */
261                 ret = set_fpregs(datap, child);
262                 break;
263         case PTRACE_GETFPXREGS: /* Get the child FPU state. */
264                 ret = get_fpxregs(datap, child);
265                 break;
266         case PTRACE_SETFPXREGS: /* Set the child FPU state. */
267                 ret = set_fpxregs(datap, child);
268                 break;
269         default:
270                 ret = -EIO;
271         }
272         return ret;
273 }