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 <linux/uaccess.h>
9 #include <asm/ptrace-abi.h>
10 #include <registers.h>
11 #include <skas.h>
12
arch_switch_to(struct task_struct * to)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 /* determines which flags the user has access to. */
27 /* 1 = access 0 = no access */
28 #define FLAG_MASK 0x00044dd5
29
30 static const int reg_offsets[] = {
31 [EBX] = HOST_BX,
32 [ECX] = HOST_CX,
33 [EDX] = HOST_DX,
34 [ESI] = HOST_SI,
35 [EDI] = HOST_DI,
36 [EBP] = HOST_BP,
37 [EAX] = HOST_AX,
38 [DS] = HOST_DS,
39 [ES] = HOST_ES,
40 [FS] = HOST_FS,
41 [GS] = HOST_GS,
42 [EIP] = HOST_IP,
43 [CS] = HOST_CS,
44 [EFL] = HOST_EFLAGS,
45 [UESP] = HOST_SP,
46 [SS] = HOST_SS,
47 [ORIG_EAX] = HOST_ORIG_AX,
48 };
49
putreg(struct task_struct * child,int regno,unsigned long value)50 int putreg(struct task_struct *child, int regno, unsigned long value)
51 {
52 regno >>= 2;
53 switch (regno) {
54 case EBX:
55 case ECX:
56 case EDX:
57 case ESI:
58 case EDI:
59 case EBP:
60 case EAX:
61 case EIP:
62 case UESP:
63 break;
64 case ORIG_EAX:
65 /* Update the syscall number. */
66 UPT_SYSCALL_NR(&child->thread.regs.regs) = value;
67 break;
68 case FS:
69 if (value && (value & 3) != 3)
70 return -EIO;
71 break;
72 case GS:
73 if (value && (value & 3) != 3)
74 return -EIO;
75 break;
76 case DS:
77 case ES:
78 if (value && (value & 3) != 3)
79 return -EIO;
80 value &= 0xffff;
81 break;
82 case SS:
83 case CS:
84 if ((value & 3) != 3)
85 return -EIO;
86 value &= 0xffff;
87 break;
88 case EFL:
89 value &= FLAG_MASK;
90 child->thread.regs.regs.gp[HOST_EFLAGS] |= value;
91 return 0;
92 default :
93 panic("Bad register in putreg() : %d\n", regno);
94 }
95 child->thread.regs.regs.gp[reg_offsets[regno]] = value;
96 return 0;
97 }
98
poke_user(struct task_struct * child,long addr,long data)99 int poke_user(struct task_struct *child, long addr, long data)
100 {
101 if ((addr & 3) || addr < 0)
102 return -EIO;
103
104 if (addr < MAX_REG_OFFSET)
105 return putreg(child, addr, data);
106 else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
107 (addr <= offsetof(struct user, u_debugreg[7]))) {
108 addr -= offsetof(struct user, u_debugreg[0]);
109 addr = addr >> 2;
110 if ((addr == 4) || (addr == 5))
111 return -EIO;
112 child->thread.arch.debugregs[addr] = data;
113 return 0;
114 }
115 return -EIO;
116 }
117
getreg(struct task_struct * child,int regno)118 unsigned long getreg(struct task_struct *child, int regno)
119 {
120 unsigned long mask = ~0UL;
121
122 regno >>= 2;
123 switch (regno) {
124 case FS:
125 case GS:
126 case DS:
127 case ES:
128 case SS:
129 case CS:
130 mask = 0xffff;
131 break;
132 case EIP:
133 case UESP:
134 case EAX:
135 case EBX:
136 case ECX:
137 case EDX:
138 case ESI:
139 case EDI:
140 case EBP:
141 case EFL:
142 case ORIG_EAX:
143 break;
144 default:
145 panic("Bad register in getreg() : %d\n", regno);
146 }
147 return mask & child->thread.regs.regs.gp[reg_offsets[regno]];
148 }
149
150 /* read the word at location addr in the USER area. */
peek_user(struct task_struct * child,long addr,long data)151 int peek_user(struct task_struct *child, long addr, long data)
152 {
153 unsigned long tmp;
154
155 if ((addr & 3) || addr < 0)
156 return -EIO;
157
158 tmp = 0; /* Default return condition */
159 if (addr < MAX_REG_OFFSET) {
160 tmp = getreg(child, addr);
161 }
162 else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
163 (addr <= offsetof(struct user, u_debugreg[7]))) {
164 addr -= offsetof(struct user, u_debugreg[0]);
165 addr = addr >> 2;
166 tmp = child->thread.arch.debugregs[addr];
167 }
168 return put_user(tmp, (unsigned long __user *) data);
169 }
170
get_fpregs(struct user_i387_struct __user * buf,struct task_struct * child)171 static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
172 {
173 int err, n, cpu = task_cpu(child);
174 struct user_i387_struct fpregs;
175
176 err = save_i387_registers(userspace_pid[cpu],
177 (unsigned long *) &fpregs);
178 if (err)
179 return err;
180
181 n = copy_to_user(buf, &fpregs, sizeof(fpregs));
182 if(n > 0)
183 return -EFAULT;
184
185 return n;
186 }
187
set_fpregs(struct user_i387_struct __user * buf,struct task_struct * child)188 static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
189 {
190 int n, cpu = task_cpu(child);
191 struct user_i387_struct fpregs;
192
193 n = copy_from_user(&fpregs, buf, sizeof(fpregs));
194 if (n > 0)
195 return -EFAULT;
196
197 return restore_i387_registers(userspace_pid[cpu],
198 (unsigned long *) &fpregs);
199 }
200
get_fpxregs(struct user_fxsr_struct __user * buf,struct task_struct * child)201 static int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
202 {
203 int err, n, cpu = task_cpu(child);
204 struct user_fxsr_struct fpregs;
205
206 err = save_fpx_registers(userspace_pid[cpu], (unsigned long *) &fpregs);
207 if (err)
208 return err;
209
210 n = copy_to_user(buf, &fpregs, sizeof(fpregs));
211 if(n > 0)
212 return -EFAULT;
213
214 return n;
215 }
216
set_fpxregs(struct user_fxsr_struct __user * buf,struct task_struct * child)217 static int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
218 {
219 int n, cpu = task_cpu(child);
220 struct user_fxsr_struct fpregs;
221
222 n = copy_from_user(&fpregs, buf, sizeof(fpregs));
223 if (n > 0)
224 return -EFAULT;
225
226 return restore_fpx_registers(userspace_pid[cpu],
227 (unsigned long *) &fpregs);
228 }
229
subarch_ptrace(struct task_struct * child,long request,unsigned long addr,unsigned long data)230 long subarch_ptrace(struct task_struct *child, long request,
231 unsigned long addr, unsigned long data)
232 {
233 int ret = -EIO;
234 void __user *datap = (void __user *) data;
235 switch (request) {
236 case PTRACE_GETFPREGS: /* Get the child FPU state. */
237 ret = get_fpregs(datap, child);
238 break;
239 case PTRACE_SETFPREGS: /* Set the child FPU state. */
240 ret = set_fpregs(datap, child);
241 break;
242 case PTRACE_GETFPXREGS: /* Get the child FPU state. */
243 ret = get_fpxregs(datap, child);
244 break;
245 case PTRACE_SETFPXREGS: /* Set the child FPU state. */
246 ret = set_fpxregs(datap, child);
247 break;
248 default:
249 ret = -EIO;
250 }
251 return ret;
252 }
253