aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-07 13:21:26 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-07 13:21:26 -0500
commit0afc2edfada50980bec999f94dcea26ebad3dda6 (patch)
tree8963dd8fd78ee5c3481acad5903bc459bd3d055c /arch
parenta8e98d6d51a3eb7bb061b1625193a129c8bd094f (diff)
parentd256eb8db60e36fc5dd0a27ce8a64f65df31f7b5 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6: [SPARC32]: Use regsets in arch_ptrace(). [SPARC64]: Use regsets in arch_ptrace(). [SPARC32]: Use regsets for ELF core dumping. [SPARC64]: Use regsets for ELF core dumping. [SPARC64]: Remove unintentional ptrace debugging messages. [SPARC]: Move over to arch_ptrace(). [SPARC]: Remove PTRACE_SUN* handling. [SPARC]: Kill DEBUG_PTRACE code. [SPARC32]: Add user regset support. [SPARC64]: Add user regsets. [SPARC64]: Fix booting on non-zero cpu.
Diffstat (limited to 'arch')
-rw-r--r--arch/sparc/kernel/entry.S17
-rw-r--r--arch/sparc/kernel/ptrace.c813
-rw-r--r--arch/sparc64/kernel/binfmt_elf32.c31
-rw-r--r--arch/sparc64/kernel/entry.S4
-rw-r--r--arch/sparc64/kernel/head.S25
-rw-r--r--arch/sparc64/kernel/ptrace.c1095
-rw-r--r--arch/sparc64/prom/init.c3
7 files changed, 1066 insertions, 922 deletions
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index 88d2cefd01be..c2eed8f71516 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -1224,23 +1224,6 @@ sys_nis_syscall:
1224 call c_sys_nis_syscall 1224 call c_sys_nis_syscall
1225 mov %l5, %o7 1225 mov %l5, %o7
1226 1226
1227 .align 4
1228 .globl sys_ptrace
1229sys_ptrace:
1230 call do_ptrace
1231 add %sp, STACKFRAME_SZ, %o0
1232
1233 ld [%curptr + TI_FLAGS], %l5
1234 andcc %l5, _TIF_SYSCALL_TRACE, %g0
1235 be 1f
1236 nop
1237
1238 call syscall_trace
1239 nop
1240
12411:
1242 RESTORE_ALL
1243
1244 .align 4 1227 .align 4
1245 .globl sys_execve 1228 .globl sys_execve
1246sys_execve: 1229sys_execve:
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
index 7452269bba2a..5b54f11f4e59 100644
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -1,6 +1,6 @@
1/* ptrace.c: Sparc process tracing support. 1/* ptrace.c: Sparc process tracing support.
2 * 2 *
3 * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) 3 * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
4 * 4 *
5 * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, 5 * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
6 * and David Mosberger. 6 * and David Mosberger.
@@ -19,389 +19,343 @@
19#include <linux/smp_lock.h> 19#include <linux/smp_lock.h>
20#include <linux/security.h> 20#include <linux/security.h>
21#include <linux/signal.h> 21#include <linux/signal.h>
22#include <linux/regset.h>
23#include <linux/elf.h>
22 24
23#include <asm/pgtable.h> 25#include <asm/pgtable.h>
24#include <asm/system.h> 26#include <asm/system.h>
25#include <asm/uaccess.h> 27#include <asm/uaccess.h>
26 28
27#define MAGIC_CONSTANT 0x80000000 29/* #define ALLOW_INIT_TRACING */
28
29 30
30/* Returning from ptrace is a bit tricky because the syscall return 31/*
31 * low level code assumes any value returned which is negative and 32 * Called by kernel/ptrace.c when detaching..
32 * is a valid errno will mean setting the condition codes to indicate 33 *
33 * an error return. This doesn't work, so we have this hook. 34 * Make sure single step bits etc are not set.
34 */ 35 */
35static inline void pt_error_return(struct pt_regs *regs, unsigned long error) 36void ptrace_disable(struct task_struct *child)
36{ 37{
37 regs->u_regs[UREG_I0] = error; 38 /* nothing to do */
38 regs->psr |= PSR_C;
39 regs->pc = regs->npc;
40 regs->npc += 4;
41} 39}
42 40
43static inline void pt_succ_return(struct pt_regs *regs, unsigned long value) 41enum sparc_regset {
44{ 42 REGSET_GENERAL,
45 regs->u_regs[UREG_I0] = value; 43 REGSET_FP,
46 regs->psr &= ~PSR_C; 44};
47 regs->pc = regs->npc;
48 regs->npc += 4;
49}
50 45
51static void 46static int genregs32_get(struct task_struct *target,
52pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long __user *addr) 47 const struct user_regset *regset,
48 unsigned int pos, unsigned int count,
49 void *kbuf, void __user *ubuf)
53{ 50{
54 if (put_user(value, addr)) { 51 const struct pt_regs *regs = target->thread.kregs;
55 pt_error_return(regs, EFAULT); 52 unsigned long __user *reg_window;
56 return; 53 unsigned long *k = kbuf;
54 unsigned long __user *u = ubuf;
55 unsigned long reg;
56
57 if (target == current)
58 flush_user_windows();
59
60 pos /= sizeof(reg);
61 count /= sizeof(reg);
62
63 if (kbuf) {
64 for (; count > 0 && pos < 16; count--)
65 *k++ = regs->u_regs[pos++];
66
67 reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
68 for (; count > 0 && pos < 32; count--) {
69 if (get_user(*k++, &reg_window[pos++]))
70 return -EFAULT;
71 }
72 } else {
73 for (; count > 0 && pos < 16; count--) {
74 if (put_user(regs->u_regs[pos++], u++))
75 return -EFAULT;
76 }
77
78 reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
79 for (; count > 0 && pos < 32; count--) {
80 if (get_user(reg, &reg_window[pos++]) ||
81 put_user(reg, u++))
82 return -EFAULT;
83 }
57 } 84 }
58 regs->u_regs[UREG_I0] = 0; 85 while (count > 0) {
59 regs->psr &= ~PSR_C; 86 switch (pos) {
60 regs->pc = regs->npc; 87 case 32: /* PSR */
61 regs->npc += 4; 88 reg = regs->psr;
62} 89 break;
90 case 33: /* PC */
91 reg = regs->pc;
92 break;
93 case 34: /* NPC */
94 reg = regs->npc;
95 break;
96 case 35: /* Y */
97 reg = regs->y;
98 break;
99 case 36: /* WIM */
100 case 37: /* TBR */
101 reg = 0;
102 break;
103 default:
104 goto finish;
105 }
63 106
64static void 107 if (kbuf)
65pt_os_succ_return (struct pt_regs *regs, unsigned long val, long __user *addr) 108 *k++ = reg;
66{ 109 else if (put_user(reg, u++))
67 if (current->personality == PER_SUNOS) 110 return -EFAULT;
68 pt_succ_return (regs, val); 111 pos++;
69 else 112 count--;
70 pt_succ_return_linux (regs, val, addr); 113 }
114finish:
115 pos *= sizeof(reg);
116 count *= sizeof(reg);
117
118 return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
119 38 * sizeof(reg), -1);
71} 120}
72 121
73/* Fuck me gently with a chainsaw... */ 122static int genregs32_set(struct task_struct *target,
74static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset, 123 const struct user_regset *regset,
75 struct task_struct *tsk, long __user *addr) 124 unsigned int pos, unsigned int count,
125 const void *kbuf, const void __user *ubuf)
76{ 126{
77 struct pt_regs *cregs = tsk->thread.kregs; 127 struct pt_regs *regs = target->thread.kregs;
78 struct thread_info *t = task_thread_info(tsk); 128 unsigned long __user *reg_window;
79 int v; 129 const unsigned long *k = kbuf;
80 130 const unsigned long __user *u = ubuf;
81 if(offset >= 1024) 131 unsigned long reg;
82 offset -= 1024; /* whee... */ 132
83 if(offset & ((sizeof(unsigned long) - 1))) { 133 if (target == current)
84 pt_error_return(regs, EIO); 134 flush_user_windows();
85 return; 135
86 } 136 pos /= sizeof(reg);
87 if(offset >= 16 && offset < 784) { 137 count /= sizeof(reg);
88 offset -= 16; offset >>= 2; 138
89 pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr); 139 if (kbuf) {
90 return; 140 for (; count > 0 && pos < 16; count--)
91 } 141 regs->u_regs[pos++] = *k++;
92 if(offset >= 784 && offset < 832) { 142
93 offset -= 784; offset >>= 2; 143 reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
94 pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr); 144 for (; count > 0 && pos < 32; count--) {
95 return; 145 if (put_user(*k++, &reg_window[pos++]))
96 } 146 return -EFAULT;
97 switch(offset) { 147 }
98 case 0: 148 } else {
99 v = t->ksp; 149 for (; count > 0 && pos < 16; count--) {
100 break; 150 if (get_user(reg, u++))
101 case 4: 151 return -EFAULT;
102 v = t->kpc; 152 regs->u_regs[pos++] = reg;
103 break; 153 }
104 case 8:
105 v = t->kpsr;
106 break;
107 case 12:
108 v = t->uwinmask;
109 break;
110 case 832:
111 v = t->w_saved;
112 break;
113 case 896:
114 v = cregs->u_regs[UREG_I0];
115 break;
116 case 900:
117 v = cregs->u_regs[UREG_I1];
118 break;
119 case 904:
120 v = cregs->u_regs[UREG_I2];
121 break;
122 case 908:
123 v = cregs->u_regs[UREG_I3];
124 break;
125 case 912:
126 v = cregs->u_regs[UREG_I4];
127 break;
128 case 916:
129 v = cregs->u_regs[UREG_I5];
130 break;
131 case 920:
132 v = cregs->u_regs[UREG_I6];
133 break;
134 case 924:
135 if(tsk->thread.flags & MAGIC_CONSTANT)
136 v = cregs->u_regs[UREG_G1];
137 else
138 v = 0;
139 break;
140 case 940:
141 v = cregs->u_regs[UREG_I0];
142 break;
143 case 944:
144 v = cregs->u_regs[UREG_I1];
145 break;
146 154
147 case 948: 155 reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
148 /* Isn't binary compatibility _fun_??? */ 156 for (; count > 0 && pos < 32; count--) {
149 if(cregs->psr & PSR_C) 157 if (get_user(reg, u++) ||
150 v = cregs->u_regs[UREG_I0] << 24; 158 put_user(reg, &reg_window[pos++]))
151 else 159 return -EFAULT;
152 v = 0; 160 }
153 break; 161 }
162 while (count > 0) {
163 unsigned long psr;
164
165 if (kbuf)
166 reg = *k++;
167 else if (get_user(reg, u++))
168 return -EFAULT;
169
170 switch (pos) {
171 case 32: /* PSR */
172 psr = regs->psr;
173 psr &= ~PSR_ICC;
174 psr |= (reg & PSR_ICC);
175 regs->psr = psr;
176 break;
177 case 33: /* PC */
178 regs->pc = reg;
179 break;
180 case 34: /* NPC */
181 regs->npc = reg;
182 break;
183 case 35: /* Y */
184 regs->y = reg;
185 break;
186 case 36: /* WIM */
187 case 37: /* TBR */
188 break;
189 default:
190 goto finish;
191 }
154 192
155 /* Rest of them are completely unsupported. */ 193 pos++;
156 default: 194 count--;
157 printk("%s [%d]: Wants to read user offset %ld\n",
158 current->comm, task_pid_nr(current), offset);
159 pt_error_return(regs, EIO);
160 return;
161 } 195 }
162 if (current->personality == PER_SUNOS) 196finish:
163 pt_succ_return (regs, v); 197 pos *= sizeof(reg);
164 else 198 count *= sizeof(reg);
165 pt_succ_return_linux (regs, v, addr); 199
166 return; 200 return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
201 38 * sizeof(reg), -1);
167} 202}
168 203
169static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset, 204static int fpregs32_get(struct task_struct *target,
170 struct task_struct *tsk) 205 const struct user_regset *regset,
206 unsigned int pos, unsigned int count,
207 void *kbuf, void __user *ubuf)
171{ 208{
172 struct pt_regs *cregs = tsk->thread.kregs; 209 const unsigned long *fpregs = target->thread.float_regs;
173 struct thread_info *t = task_thread_info(tsk); 210 int ret = 0;
174 unsigned long value = regs->u_regs[UREG_I3];
175
176 if(offset >= 1024)
177 offset -= 1024; /* whee... */
178 if(offset & ((sizeof(unsigned long) - 1)))
179 goto failure;
180 if(offset >= 16 && offset < 784) {
181 offset -= 16; offset >>= 2;
182 *(((unsigned long *)(&t->reg_window[0]))+offset) = value;
183 goto success;
184 }
185 if(offset >= 784 && offset < 832) {
186 offset -= 784; offset >>= 2;
187 *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
188 goto success;
189 }
190 switch(offset) {
191 case 896:
192 cregs->u_regs[UREG_I0] = value;
193 break;
194 case 900:
195 cregs->u_regs[UREG_I1] = value;
196 break;
197 case 904:
198 cregs->u_regs[UREG_I2] = value;
199 break;
200 case 908:
201 cregs->u_regs[UREG_I3] = value;
202 break;
203 case 912:
204 cregs->u_regs[UREG_I4] = value;
205 break;
206 case 916:
207 cregs->u_regs[UREG_I5] = value;
208 break;
209 case 920:
210 cregs->u_regs[UREG_I6] = value;
211 break;
212 case 924:
213 cregs->u_regs[UREG_I7] = value;
214 break;
215 case 940:
216 cregs->u_regs[UREG_I0] = value;
217 break;
218 case 944:
219 cregs->u_regs[UREG_I1] = value;
220 break;
221 211
222 /* Rest of them are completely unsupported or "no-touch". */ 212#if 0
223 default: 213 if (target == current)
224 printk("%s [%d]: Wants to write user offset %ld\n", 214 save_and_clear_fpu();
225 current->comm, task_pid_nr(current), offset); 215#endif
226 goto failure; 216
217 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
218 fpregs,
219 0, 32 * sizeof(u32));
220
221 if (!ret)
222 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
223 32 * sizeof(u32),
224 33 * sizeof(u32));
225 if (!ret)
226 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
227 &target->thread.fsr,
228 33 * sizeof(u32),
229 34 * sizeof(u32));
230
231 if (!ret) {
232 unsigned long val;
233
234 val = (1 << 8) | (8 << 16);
235 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
236 &val,
237 34 * sizeof(u32),
238 35 * sizeof(u32));
227 } 239 }
228success:
229 pt_succ_return(regs, 0);
230 return;
231failure:
232 pt_error_return(regs, EIO);
233 return;
234}
235 240
236/* #define ALLOW_INIT_TRACING */ 241 if (!ret)
237/* #define DEBUG_PTRACE */ 242 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
238 243 35 * sizeof(u32), -1);
239#ifdef DEBUG_PTRACE
240char *pt_rq [] = {
241 /* 0 */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR",
242 /* 4 */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT",
243 /* 8 */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH",
244 /* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS",
245 /* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT",
246 /* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown",
247 /* 24 */ "SYSCALL", ""
248};
249#endif
250 244
251/* 245 return ret;
252 * Called by kernel/ptrace.c when detaching..
253 *
254 * Make sure single step bits etc are not set.
255 */
256void ptrace_disable(struct task_struct *child)
257{
258 /* nothing to do */
259} 246}
260 247
261asmlinkage void do_ptrace(struct pt_regs *regs) 248static int fpregs32_set(struct task_struct *target,
249 const struct user_regset *regset,
250 unsigned int pos, unsigned int count,
251 const void *kbuf, const void __user *ubuf)
262{ 252{
263 unsigned long request = regs->u_regs[UREG_I0]; 253 unsigned long *fpregs = target->thread.float_regs;
264 unsigned long pid = regs->u_regs[UREG_I1];
265 unsigned long addr = regs->u_regs[UREG_I2];
266 unsigned long data = regs->u_regs[UREG_I3];
267 unsigned long addr2 = regs->u_regs[UREG_I4];
268 struct task_struct *child;
269 int ret; 254 int ret;
270 255
271 lock_kernel(); 256#if 0
272#ifdef DEBUG_PTRACE 257 if (target == current)
273 { 258 save_and_clear_fpu();
274 char *s;
275
276 if ((request >= 0) && (request <= 24))
277 s = pt_rq [request];
278 else
279 s = "unknown";
280
281 if (request == PTRACE_POKEDATA && data == 0x91d02001){
282 printk ("do_ptrace: breakpoint pid=%d, addr=%08lx addr2=%08lx\n",
283 pid, addr, addr2);
284 } else
285 printk("do_ptrace: rq=%s(%d) pid=%d addr=%08lx data=%08lx addr2=%08lx\n",
286 s, (int) request, (int) pid, addr, data, addr2);
287 }
288#endif 259#endif
289 260 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
290 if (request == PTRACE_TRACEME) { 261 fpregs,
291 ret = ptrace_traceme(); 262 0, 32 * sizeof(u32));
292 if (ret < 0) 263 if (!ret)
293 pt_error_return(regs, -ret); 264 user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
294 else 265 32 * sizeof(u32),
295 pt_succ_return(regs, 0); 266 33 * sizeof(u32));
296 goto out; 267 if (!ret && count > 0) {
268 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
269 &target->thread.fsr,
270 33 * sizeof(u32),
271 34 * sizeof(u32));
297 } 272 }
298 273
299 child = ptrace_get_task_struct(pid); 274 if (!ret)
300 if (IS_ERR(child)) { 275 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
301 ret = PTR_ERR(child); 276 34 * sizeof(u32), -1);
302 pt_error_return(regs, -ret); 277 return ret;
303 goto out; 278}
304 }
305 279
306 if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) 280static const struct user_regset sparc32_regsets[] = {
307 || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { 281 /* Format is:
308 if (ptrace_attach(child)) { 282 * G0 --> G7
309 pt_error_return(regs, EPERM); 283 * O0 --> O7
310 goto out_tsk; 284 * L0 --> L7
311 } 285 * I0 --> I7
312 pt_succ_return(regs, 0); 286 * PSR, PC, nPC, Y, WIM, TBR
313 goto out_tsk; 287 */
314 } 288 [REGSET_GENERAL] = {
289 .core_note_type = NT_PRSTATUS,
290 .n = 38 * sizeof(u32),
291 .size = sizeof(u32), .align = sizeof(u32),
292 .get = genregs32_get, .set = genregs32_set
293 },
294 /* Format is:
295 * F0 --> F31
296 * empty 32-bit word
297 * FSR (32--bit word)
298 * FPU QUEUE COUNT (8-bit char)
299 * FPU QUEUE ENTRYSIZE (8-bit char)
300 * FPU ENABLED (8-bit char)
301 * empty 8-bit char
302 * FPU QUEUE (64 32-bit ints)
303 */
304 [REGSET_FP] = {
305 .core_note_type = NT_PRFPREG,
306 .n = 99 * sizeof(u32),
307 .size = sizeof(u32), .align = sizeof(u32),
308 .get = fpregs32_get, .set = fpregs32_set
309 },
310};
315 311
316 ret = ptrace_check_attach(child, request == PTRACE_KILL); 312static const struct user_regset_view user_sparc32_view = {
317 if (ret < 0) { 313 .name = "sparc", .e_machine = EM_SPARC,
318 pt_error_return(regs, -ret); 314 .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
319 goto out_tsk; 315};
320 }
321 316
322 switch(request) { 317const struct user_regset_view *task_user_regset_view(struct task_struct *task)
323 case PTRACE_PEEKTEXT: /* read word at location addr. */ 318{
324 case PTRACE_PEEKDATA: { 319 return &user_sparc32_view;
325 unsigned long tmp; 320}
326
327 if (access_process_vm(child, addr,
328 &tmp, sizeof(tmp), 0) == sizeof(tmp))
329 pt_os_succ_return(regs, tmp, (long __user *)data);
330 else
331 pt_error_return(regs, EIO);
332 goto out_tsk;
333 }
334 321
335 case PTRACE_PEEKUSR: 322long arch_ptrace(struct task_struct *child, long request, long addr, long data)
336 read_sunos_user(regs, addr, child, (long __user *) data); 323{
337 goto out_tsk; 324 unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
338 325 const struct user_regset_view *view;
339 case PTRACE_POKEUSR: 326 int ret;
340 write_sunos_user(regs, addr, child); 327
341 goto out_tsk; 328 view = task_user_regset_view(child);
342
343 case PTRACE_POKETEXT: /* write the word at location addr. */
344 case PTRACE_POKEDATA: {
345 if (access_process_vm(child, addr,
346 &data, sizeof(data), 1) == sizeof(data))
347 pt_succ_return(regs, 0);
348 else
349 pt_error_return(regs, EIO);
350 goto out_tsk;
351 }
352 329
330 switch(request) {
353 case PTRACE_GETREGS: { 331 case PTRACE_GETREGS: {
354 struct pt_regs __user *pregs = (struct pt_regs __user *) addr; 332 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
355 struct pt_regs *cregs = child->thread.kregs;
356 int rval;
357 333
358 if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) { 334 ret = copy_regset_to_user(child, view, REGSET_GENERAL,
359 rval = -EFAULT; 335 32 * sizeof(u32),
360 pt_error_return(regs, -rval); 336 4 * sizeof(u32),
361 goto out_tsk; 337 &pregs->psr);
362 } 338 if (!ret)
363 __put_user(cregs->psr, (&pregs->psr)); 339 copy_regset_to_user(child, view, REGSET_GENERAL,
364 __put_user(cregs->pc, (&pregs->pc)); 340 1 * sizeof(u32),
365 __put_user(cregs->npc, (&pregs->npc)); 341 15 * sizeof(u32),
366 __put_user(cregs->y, (&pregs->y)); 342 &pregs->u_regs[0]);
367 for(rval = 1; rval < 16; rval++) 343 break;
368 __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]));
369 pt_succ_return(regs, 0);
370#ifdef DEBUG_PTRACE
371 printk ("PC=%x nPC=%x o7=%x\n", cregs->pc, cregs->npc, cregs->u_regs [15]);
372#endif
373 goto out_tsk;
374 } 344 }
375 345
376 case PTRACE_SETREGS: { 346 case PTRACE_SETREGS: {
377 struct pt_regs __user *pregs = (struct pt_regs __user *) addr; 347 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
378 struct pt_regs *cregs = child->thread.kregs; 348
379 unsigned long psr, pc, npc, y; 349 ret = copy_regset_from_user(child, view, REGSET_GENERAL,
380 int i; 350 32 * sizeof(u32),
381 351 4 * sizeof(u32),
382 /* Must be careful, tracing process can only set certain 352 &pregs->psr);
383 * bits in the psr. 353 if (!ret)
384 */ 354 copy_regset_from_user(child, view, REGSET_GENERAL,
385 if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) { 355 1 * sizeof(u32),
386 pt_error_return(regs, EFAULT); 356 15 * sizeof(u32),
387 goto out_tsk; 357 &pregs->u_regs[0]);
388 } 358 break;
389 __get_user(psr, (&pregs->psr));
390 __get_user(pc, (&pregs->pc));
391 __get_user(npc, (&pregs->npc));
392 __get_user(y, (&pregs->y));
393 psr &= PSR_ICC;
394 cregs->psr &= ~PSR_ICC;
395 cregs->psr |= psr;
396 if (!((pc | npc) & 3)) {
397 cregs->pc = pc;
398 cregs->npc =npc;
399 }
400 cregs->y = y;
401 for(i = 1; i < 16; i++)
402 __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]));
403 pt_succ_return(regs, 0);
404 goto out_tsk;
405 } 359 }
406 360
407 case PTRACE_GETFPREGS: { 361 case PTRACE_GETFPREGS: {
@@ -417,26 +371,25 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
417 } fpq[16]; 371 } fpq[16];
418 }; 372 };
419 struct fps __user *fps = (struct fps __user *) addr; 373 struct fps __user *fps = (struct fps __user *) addr;
420 int i;
421 374
422 if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) { 375 ret = copy_regset_to_user(child, view, REGSET_FP,
423 i = -EFAULT; 376 0 * sizeof(u32),
424 pt_error_return(regs, -i); 377 32 * sizeof(u32),
425 goto out_tsk; 378 &fps->regs[0]);
426 } 379 if (!ret)
427 for(i = 0; i < 32; i++) 380 ret = copy_regset_to_user(child, view, REGSET_FP,
428 __put_user(child->thread.float_regs[i], (&fps->regs[i])); 381 33 * sizeof(u32),
429 __put_user(child->thread.fsr, (&fps->fsr)); 382 1 * sizeof(u32),
430 __put_user(child->thread.fpqdepth, (&fps->fpqd)); 383 &fps->fsr);
431 __put_user(0, (&fps->flags)); 384
432 __put_user(0, (&fps->extra)); 385 if (!ret) {
433 for(i = 0; i < 16; i++) { 386 if (__put_user(0, &fps->fpqd) ||
434 __put_user(child->thread.fpqueue[i].insn_addr, 387 __put_user(0, &fps->flags) ||
435 (&fps->fpq[i].insnaddr)); 388 __put_user(0, &fps->extra) ||
436 __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn)); 389 clear_user(fps->fpq, sizeof(fps->fpq)))
390 ret = -EFAULT;
437 } 391 }
438 pt_succ_return(regs, 0); 392 break;
439 goto out_tsk;
440 } 393 }
441 394
442 case PTRACE_SETFPREGS: { 395 case PTRACE_SETFPREGS: {
@@ -452,137 +405,55 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
452 } fpq[16]; 405 } fpq[16];
453 }; 406 };
454 struct fps __user *fps = (struct fps __user *) addr; 407 struct fps __user *fps = (struct fps __user *) addr;
455 int i;
456 408
457 if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) { 409 ret = copy_regset_from_user(child, view, REGSET_FP,
458 i = -EFAULT; 410 0 * sizeof(u32),
459 pt_error_return(regs, -i); 411 32 * sizeof(u32),
460 goto out_tsk; 412 &fps->regs[0]);
461 } 413 if (!ret)
462 copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long))); 414 ret = copy_regset_from_user(child, view, REGSET_FP,
463 __get_user(child->thread.fsr, (&fps->fsr)); 415 33 * sizeof(u32),
464 __get_user(child->thread.fpqdepth, (&fps->fpqd)); 416 1 * sizeof(u32),
465 for(i = 0; i < 16; i++) { 417 &fps->fsr);
466 __get_user(child->thread.fpqueue[i].insn_addr, 418 break;
467 (&fps->fpq[i].insnaddr));
468 __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
469 }
470 pt_succ_return(regs, 0);
471 goto out_tsk;
472 } 419 }
473 420
474 case PTRACE_READTEXT: 421 case PTRACE_READTEXT:
475 case PTRACE_READDATA: { 422 case PTRACE_READDATA:
476 int res = ptrace_readdata(child, addr, 423 ret = ptrace_readdata(child, addr,
477 (void __user *) addr2, data); 424 (void __user *) addr2, data);
478 425
479 if (res == data) { 426 if (ret == data)
480 pt_succ_return(regs, 0); 427 ret = 0;
481 goto out_tsk; 428 else if (ret >= 0)
482 } 429 ret = -EIO;
483 /* Partial read is an IO failure */ 430 break;
484 if (res >= 0)
485 res = -EIO;
486 pt_error_return(regs, -res);
487 goto out_tsk;
488 }
489 431
490 case PTRACE_WRITETEXT: 432 case PTRACE_WRITETEXT:
491 case PTRACE_WRITEDATA: { 433 case PTRACE_WRITEDATA:
492 int res = ptrace_writedata(child, (void __user *) addr2, 434 ret = ptrace_writedata(child, (void __user *) addr2,
493 addr, data); 435 addr, data);
494 436
495 if (res == data) { 437 if (ret == data)
496 pt_succ_return(regs, 0); 438 ret = 0;
497 goto out_tsk; 439 else if (ret >= 0)
498 } 440 ret = -EIO;
499 /* Partial write is an IO failure */ 441 break;
500 if (res >= 0)
501 res = -EIO;
502 pt_error_return(regs, -res);
503 goto out_tsk;
504 }
505
506 case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
507 addr = 1;
508
509 case PTRACE_CONT: { /* restart after signal. */
510 if (!valid_signal(data)) {
511 pt_error_return(regs, EIO);
512 goto out_tsk;
513 }
514
515 if (request == PTRACE_SYSCALL)
516 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
517 else
518 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
519
520 child->exit_code = data;
521#ifdef DEBUG_PTRACE
522 printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n",
523 child->comm, child->pid, child->exit_code,
524 child->thread.kregs->pc,
525 child->thread.kregs->npc);
526#endif
527 wake_up_process(child);
528 pt_succ_return(regs, 0);
529 goto out_tsk;
530 }
531
532/*
533 * make the child exit. Best I can do is send it a sigkill.
534 * perhaps it should be put in the status that it wants to
535 * exit.
536 */
537 case PTRACE_KILL: {
538 if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
539 pt_succ_return(regs, 0);
540 goto out_tsk;
541 }
542 wake_up_process(child);
543 child->exit_code = SIGKILL;
544 pt_succ_return(regs, 0);
545 goto out_tsk;
546 }
547 442
548 case PTRACE_SUNDETACH: { /* detach a process that was attached. */ 443 default:
549 int err = ptrace_detach(child, data); 444 ret = ptrace_request(child, request, addr, data);
550 if (err) { 445 break;
551 pt_error_return(regs, EIO);
552 goto out_tsk;
553 }
554 pt_succ_return(regs, 0);
555 goto out_tsk;
556 } 446 }
557 447
558 /* PTRACE_DUMPCORE unsupported... */ 448 return ret;
559
560 default: {
561 int err = ptrace_request(child, request, addr, data);
562 if (err)
563 pt_error_return(regs, -err);
564 else
565 pt_succ_return(regs, 0);
566 goto out_tsk;
567 }
568 }
569out_tsk:
570 if (child)
571 put_task_struct(child);
572out:
573 unlock_kernel();
574} 449}
575 450
576asmlinkage void syscall_trace(void) 451asmlinkage void syscall_trace(void)
577{ 452{
578#ifdef DEBUG_PTRACE
579 printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
580#endif
581 if (!test_thread_flag(TIF_SYSCALL_TRACE)) 453 if (!test_thread_flag(TIF_SYSCALL_TRACE))
582 return; 454 return;
583 if (!(current->ptrace & PT_PTRACED)) 455 if (!(current->ptrace & PT_PTRACED))
584 return; 456 return;
585 current->thread.flags ^= MAGIC_CONSTANT;
586 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) 457 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
587 ? 0x80 : 0)); 458 ? 0x80 : 0));
588 /* 459 /*
@@ -590,10 +461,6 @@ asmlinkage void syscall_trace(void)
590 * for normal use. strace only continues with a signal if the 461 * for normal use. strace only continues with a signal if the
591 * stopping signal is not SIGTRAP. -brl 462 * stopping signal is not SIGTRAP. -brl
592 */ 463 */
593#ifdef DEBUG_PTRACE
594 printk("%s [%d]: syscall_trace exit= %x\n", current->comm,
595 current->pid, current->exit_code);
596#endif
597 if (current->exit_code) { 464 if (current->exit_code) {
598 send_sig (current->exit_code, current, 1); 465 send_sig (current->exit_code, current, 1);
599 current->exit_code = 0; 466 current->exit_code = 0;
diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c
index 1587a29a4b0e..d141300e76b7 100644
--- a/arch/sparc64/kernel/binfmt_elf32.c
+++ b/arch/sparc64/kernel/binfmt_elf32.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra. 2 * binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra.
3 * 3 *
4 * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@davemloft.net) 4 * Copyright (C) 1995, 1996, 1997, 1998, 2008 David S. Miller (davem@davemloft.net)
5 * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) 5 * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz)
6 */ 6 */
7 7
@@ -9,13 +9,6 @@
9#define ELF_CLASS ELFCLASS32 9#define ELF_CLASS ELFCLASS32
10#define ELF_DATA ELFDATA2MSB; 10#define ELF_DATA ELFDATA2MSB;
11 11
12/* For the most part we present code dumps in the format
13 * Solaris does.
14 */
15typedef unsigned int elf_greg_t;
16#define ELF_NGREG 38
17typedef elf_greg_t elf_gregset_t[ELF_NGREG];
18
19/* Format is: 12/* Format is:
20 * G0 --> G7 13 * G0 --> G7
21 * O0 --> O7 14 * O0 --> O7
@@ -23,25 +16,9 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
23 * I0 --> I7 16 * I0 --> I7
24 * PSR, PC, nPC, Y, WIM, TBR 17 * PSR, PC, nPC, Y, WIM, TBR
25 */ 18 */
26#include <asm/psrcompat.h> 19typedef unsigned int elf_greg_t;
27#define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs) \ 20#define ELF_NGREG 38
28do { unsigned int *dest = &(__elf_regs[0]); \ 21typedef elf_greg_t elf_gregset_t[ELF_NGREG];
29 struct pt_regs *src = (__pt_regs); \
30 unsigned int __user *sp; \
31 int i; \
32 for(i = 0; i < 16; i++) \
33 dest[i] = (unsigned int) src->u_regs[i];\
34 /* Don't try this at home kids... */ \
35 sp = (unsigned int __user *) (src->u_regs[14] & \
36 0x00000000fffffffc); \
37 for(i = 0; i < 16; i++) \
38 __get_user(dest[i+16], &sp[i]); \
39 dest[32] = tstate_to_psr(src->tstate); \
40 dest[33] = (unsigned int) src->tpc; \
41 dest[34] = (unsigned int) src->tnpc; \
42 dest[35] = src->y; \
43 dest[36] = dest[37] = 0; /* XXX */ \
44} while(0);
45 22
46typedef struct { 23typedef struct {
47 union { 24 union {
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index ea257e828364..6be4d2d2904e 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1477,10 +1477,6 @@ sys32_rt_sigreturn:
1477 add %o7, 1f-.-4, %o7 1477 add %o7, 1f-.-4, %o7
1478 nop 1478 nop
1479#endif 1479#endif
1480sys_ptrace: add %sp, PTREGS_OFF, %o0
1481 call do_ptrace
1482 add %o7, 1f-.-4, %o7
1483 nop
1484 .align 32 1480 .align 32
14851: ldx [%curptr + TI_FLAGS], %l5 14811: ldx [%curptr + TI_FLAGS], %l5
1486 andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 1482 andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index c4147ad8677b..44b105c04dd3 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -632,11 +632,36 @@ tlb_fixup_done:
632 /* Not reached... */ 632 /* Not reached... */
633 633
6341: 6341:
635 /* If we boot on a non-zero cpu, all of the per-cpu
636 * variable references we make before setting up the
637 * per-cpu areas will use a bogus offset. Put a
638 * compensating factor into __per_cpu_base to handle
639 * this cleanly.
640 *
641 * What the per-cpu code calculates is:
642 *
643 * __per_cpu_base + (cpu << __per_cpu_shift)
644 *
645 * These two variables are zero initially, so to
646 * make it all cancel out to zero we need to put
647 * "0 - (cpu << 0)" into __per_cpu_base so that the
648 * above formula evaluates to zero.
649 *
650 * We cannot even perform a printk() until this stuff
651 * is setup as that calls cpu_clock() which uses
652 * per-cpu variables.
653 */
654 sub %g0, %o0, %o1
655 sethi %hi(__per_cpu_base), %o2
656 stx %o1, [%o2 + %lo(__per_cpu_base)]
635#else 657#else
636 mov 0, %o0 658 mov 0, %o0
637#endif 659#endif
638 sth %o0, [%g6 + TI_CPU] 660 sth %o0, [%g6 + TI_CPU]
639 661
662 call prom_init_report
663 nop
664
640 /* Off we go.... */ 665 /* Off we go.... */
641 call start_kernel 666 call start_kernel
642 nop 667 nop
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 81111a12f0a8..51f012410f9d 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -1,6 +1,6 @@
1/* ptrace.c: Sparc process tracing support. 1/* ptrace.c: Sparc process tracing support.
2 * 2 *
3 * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) 3 * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
4 * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 4 * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5 * 5 *
6 * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, 6 * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
@@ -22,6 +22,9 @@
22#include <linux/seccomp.h> 22#include <linux/seccomp.h>
23#include <linux/audit.h> 23#include <linux/audit.h>
24#include <linux/signal.h> 24#include <linux/signal.h>
25#include <linux/regset.h>
26#include <linux/compat.h>
27#include <linux/elf.h>
25 28
26#include <asm/asi.h> 29#include <asm/asi.h>
27#include <asm/pgtable.h> 30#include <asm/pgtable.h>
@@ -33,70 +36,7 @@
33#include <asm/page.h> 36#include <asm/page.h>
34#include <asm/cpudata.h> 37#include <asm/cpudata.h>
35 38
36/* Returning from ptrace is a bit tricky because the syscall return
37 * low level code assumes any value returned which is negative and
38 * is a valid errno will mean setting the condition codes to indicate
39 * an error return. This doesn't work, so we have this hook.
40 */
41static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
42{
43 regs->u_regs[UREG_I0] = error;
44 regs->tstate |= (TSTATE_ICARRY | TSTATE_XCARRY);
45 regs->tpc = regs->tnpc;
46 regs->tnpc += 4;
47}
48
49static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
50{
51 regs->u_regs[UREG_I0] = value;
52 regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY);
53 regs->tpc = regs->tnpc;
54 regs->tnpc += 4;
55}
56
57static inline void
58pt_succ_return_linux(struct pt_regs *regs, unsigned long value, void __user *addr)
59{
60 if (test_thread_flag(TIF_32BIT)) {
61 if (put_user(value, (unsigned int __user *) addr)) {
62 pt_error_return(regs, EFAULT);
63 return;
64 }
65 } else {
66 if (put_user(value, (long __user *) addr)) {
67 pt_error_return(regs, EFAULT);
68 return;
69 }
70 }
71 regs->u_regs[UREG_I0] = 0;
72 regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY);
73 regs->tpc = regs->tnpc;
74 regs->tnpc += 4;
75}
76
77static void
78pt_os_succ_return (struct pt_regs *regs, unsigned long val, void __user *addr)
79{
80 if (current->personality == PER_SUNOS)
81 pt_succ_return (regs, val);
82 else
83 pt_succ_return_linux (regs, val, addr);
84}
85
86/* #define ALLOW_INIT_TRACING */ 39/* #define ALLOW_INIT_TRACING */
87/* #define DEBUG_PTRACE */
88
89#ifdef DEBUG_PTRACE
90char *pt_rq [] = {
91 /* 0 */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR",
92 /* 4 */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT",
93 /* 8 */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH",
94 /* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS",
95 /* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT",
96 /* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown",
97 /* 24 */ "SYSCALL", ""
98};
99#endif
100 40
101/* 41/*
102 * Called by kernel/ptrace.c when detaching.. 42 * Called by kernel/ptrace.c when detaching..
@@ -167,267 +107,709 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
167 } 107 }
168} 108}
169 109
170asmlinkage void do_ptrace(struct pt_regs *regs) 110enum sparc_regset {
111 REGSET_GENERAL,
112 REGSET_FP,
113};
114
115static int genregs64_get(struct task_struct *target,
116 const struct user_regset *regset,
117 unsigned int pos, unsigned int count,
118 void *kbuf, void __user *ubuf)
171{ 119{
172 int request = regs->u_regs[UREG_I0]; 120 const struct pt_regs *regs = task_pt_regs(target);
173 pid_t pid = regs->u_regs[UREG_I1];
174 unsigned long addr = regs->u_regs[UREG_I2];
175 unsigned long data = regs->u_regs[UREG_I3];
176 unsigned long addr2 = regs->u_regs[UREG_I4];
177 struct task_struct *child;
178 int ret; 121 int ret;
179 122
180 if (test_thread_flag(TIF_32BIT)) { 123 if (target == current)
181 addr &= 0xffffffffUL; 124 flushw_user();
182 data &= 0xffffffffUL; 125
183 addr2 &= 0xffffffffUL; 126 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
127 regs->u_regs,
128 0, 16 * sizeof(u64));
129 if (!ret) {
130 unsigned long __user *reg_window = (unsigned long __user *)
131 (regs->u_regs[UREG_I6] + STACK_BIAS);
132 unsigned long window[16];
133
134 if (copy_from_user(window, reg_window, sizeof(window)))
135 return -EFAULT;
136
137 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
138 window,
139 16 * sizeof(u64),
140 32 * sizeof(u64));
184 } 141 }
185 lock_kernel();
186#ifdef DEBUG_PTRACE
187 {
188 char *s;
189 142
190 if ((request >= 0) && (request <= 24)) 143 if (!ret) {
191 s = pt_rq [request]; 144 /* TSTATE, TPC, TNPC */
192 else 145 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
193 s = "unknown"; 146 &regs->tstate,
147 32 * sizeof(u64),
148 35 * sizeof(u64));
149 }
150
151 if (!ret) {
152 unsigned long y = regs->y;
194 153
195 if (request == PTRACE_POKEDATA && data == 0x91d02001){ 154 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
196 printk ("do_ptrace: breakpoint pid=%d, addr=%016lx addr2=%016lx\n", 155 &y,
197 pid, addr, addr2); 156 35 * sizeof(u64),
198 } else 157 36 * sizeof(u64));
199 printk("do_ptrace: rq=%s(%d) pid=%d addr=%016lx data=%016lx addr2=%016lx\n",
200 s, request, pid, addr, data, addr2);
201 } 158 }
202#endif 159
203 if (request == PTRACE_TRACEME) { 160 if (!ret)
204 ret = ptrace_traceme(); 161 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
205 if (ret < 0) 162 36 * sizeof(u64), -1);
206 pt_error_return(regs, -ret); 163
164 return ret;
165}
166
167static int genregs64_set(struct task_struct *target,
168 const struct user_regset *regset,
169 unsigned int pos, unsigned int count,
170 const void *kbuf, const void __user *ubuf)
171{
172 struct pt_regs *regs = task_pt_regs(target);
173 int ret;
174
175 if (target == current)
176 flushw_user();
177
178 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
179 regs->u_regs,
180 0, 16 * sizeof(u64));
181 if (!ret && count > 0) {
182 unsigned long __user *reg_window = (unsigned long __user *)
183 (regs->u_regs[UREG_I6] + STACK_BIAS);
184 unsigned long window[16];
185
186 if (copy_from_user(window, reg_window, sizeof(window)))
187 return -EFAULT;
188
189 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
190 window,
191 16 * sizeof(u64),
192 32 * sizeof(u64));
193 if (!ret &&
194 copy_to_user(reg_window, window, sizeof(window)))
195 return -EFAULT;
196 }
197
198 if (!ret && count > 0) {
199 unsigned long tstate;
200
201 /* TSTATE */
202 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
203 &tstate,
204 32 * sizeof(u64),
205 33 * sizeof(u64));
206 if (!ret) {
207 /* Only the condition codes can be modified
208 * in the %tstate register.
209 */
210 tstate &= (TSTATE_ICC | TSTATE_XCC);
211 regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
212 regs->tstate |= tstate;
213 }
214 }
215
216 if (!ret) {
217 /* TPC, TNPC */
218 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
219 &regs->tpc,
220 33 * sizeof(u64),
221 35 * sizeof(u64));
222 }
223
224 if (!ret) {
225 unsigned long y;
226
227 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
228 &y,
229 35 * sizeof(u64),
230 36 * sizeof(u64));
231 if (!ret)
232 regs->y = y;
233 }
234
235 if (!ret)
236 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
237 36 * sizeof(u64), -1);
238
239 return ret;
240}
241
242static int fpregs64_get(struct task_struct *target,
243 const struct user_regset *regset,
244 unsigned int pos, unsigned int count,
245 void *kbuf, void __user *ubuf)
246{
247 const unsigned long *fpregs = task_thread_info(target)->fpregs;
248 unsigned long fprs, fsr, gsr;
249 int ret;
250
251 if (target == current)
252 save_and_clear_fpu();
253
254 fprs = task_thread_info(target)->fpsaved[0];
255
256 if (fprs & FPRS_DL)
257 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
258 fpregs,
259 0, 16 * sizeof(u64));
260 else
261 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
262 0,
263 16 * sizeof(u64));
264
265 if (!ret) {
266 if (fprs & FPRS_DU)
267 ret = user_regset_copyout(&pos, &count,
268 &kbuf, &ubuf,
269 fpregs + 16,
270 16 * sizeof(u64),
271 32 * sizeof(u64));
207 else 272 else
208 pt_succ_return(regs, 0); 273 ret = user_regset_copyout_zero(&pos, &count,
209 goto out; 274 &kbuf, &ubuf,
275 16 * sizeof(u64),
276 32 * sizeof(u64));
210 } 277 }
211 278
212 child = ptrace_get_task_struct(pid); 279 if (fprs & FPRS_FEF) {
213 if (IS_ERR(child)) { 280 fsr = task_thread_info(target)->xfsr[0];
214 ret = PTR_ERR(child); 281 gsr = task_thread_info(target)->gsr[0];
215 pt_error_return(regs, -ret); 282 } else {
216 goto out; 283 fsr = gsr = 0;
217 } 284 }
218 285
219 if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) 286 if (!ret)
220 || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { 287 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
221 if (ptrace_attach(child)) { 288 &fsr,
222 pt_error_return(regs, EPERM); 289 32 * sizeof(u64),
223 goto out_tsk; 290 33 * sizeof(u64));
291 if (!ret)
292 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
293 &gsr,
294 33 * sizeof(u64),
295 34 * sizeof(u64));
296 if (!ret)
297 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
298 &fprs,
299 34 * sizeof(u64),
300 35 * sizeof(u64));
301
302 if (!ret)
303 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
304 35 * sizeof(u64), -1);
305
306 return ret;
307}
308
309static int fpregs64_set(struct task_struct *target,
310 const struct user_regset *regset,
311 unsigned int pos, unsigned int count,
312 const void *kbuf, const void __user *ubuf)
313{
314 unsigned long *fpregs = task_thread_info(target)->fpregs;
315 unsigned long fprs;
316 int ret;
317
318 if (target == current)
319 save_and_clear_fpu();
320
321 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
322 fpregs,
323 0, 32 * sizeof(u64));
324 if (!ret)
325 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
326 task_thread_info(target)->xfsr,
327 32 * sizeof(u64),
328 33 * sizeof(u64));
329 if (!ret)
330 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
331 task_thread_info(target)->gsr,
332 33 * sizeof(u64),
333 34 * sizeof(u64));
334
335 fprs = task_thread_info(target)->fpsaved[0];
336 if (!ret && count > 0) {
337 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
338 &fprs,
339 34 * sizeof(u64),
340 35 * sizeof(u64));
341 }
342
343 fprs |= (FPRS_FEF | FPRS_DL | FPRS_DU);
344 task_thread_info(target)->fpsaved[0] = fprs;
345
346 if (!ret)
347 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
348 35 * sizeof(u64), -1);
349 return ret;
350}
351
352static const struct user_regset sparc64_regsets[] = {
353 /* Format is:
354 * G0 --> G7
355 * O0 --> O7
356 * L0 --> L7
357 * I0 --> I7
358 * TSTATE, TPC, TNPC, Y
359 */
360 [REGSET_GENERAL] = {
361 .core_note_type = NT_PRSTATUS,
362 .n = 36 * sizeof(u64),
363 .size = sizeof(u64), .align = sizeof(u64),
364 .get = genregs64_get, .set = genregs64_set
365 },
366 /* Format is:
367 * F0 --> F63
368 * FSR
369 * GSR
370 * FPRS
371 */
372 [REGSET_FP] = {
373 .core_note_type = NT_PRFPREG,
374 .n = 35 * sizeof(u64),
375 .size = sizeof(u64), .align = sizeof(u64),
376 .get = fpregs64_get, .set = fpregs64_set
377 },
378};
379
380static const struct user_regset_view user_sparc64_view = {
381 .name = "sparc64", .e_machine = EM_SPARCV9,
382 .regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets)
383};
384
385static int genregs32_get(struct task_struct *target,
386 const struct user_regset *regset,
387 unsigned int pos, unsigned int count,
388 void *kbuf, void __user *ubuf)
389{
390 const struct pt_regs *regs = task_pt_regs(target);
391 compat_ulong_t __user *reg_window;
392 compat_ulong_t *k = kbuf;
393 compat_ulong_t __user *u = ubuf;
394 compat_ulong_t reg;
395
396 if (target == current)
397 flushw_user();
398
399 pos /= sizeof(reg);
400 count /= sizeof(reg);
401
402 if (kbuf) {
403 for (; count > 0 && pos < 16; count--)
404 *k++ = regs->u_regs[pos++];
405
406 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
407 for (; count > 0 && pos < 32; count--) {
408 if (get_user(*k++, &reg_window[pos++]))
409 return -EFAULT;
410 }
411 } else {
412 for (; count > 0 && pos < 16; count--) {
413 if (put_user((compat_ulong_t) regs->u_regs[pos++], u++))
414 return -EFAULT;
415 }
416
417 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
418 for (; count > 0 && pos < 32; count--) {
419 if (get_user(reg, &reg_window[pos++]) ||
420 put_user(reg, u++))
421 return -EFAULT;
224 } 422 }
225 pt_succ_return(regs, 0);
226 goto out_tsk;
227 } 423 }
424 while (count > 0) {
425 switch (pos) {
426 case 32: /* PSR */
427 reg = tstate_to_psr(regs->tstate);
428 break;
429 case 33: /* PC */
430 reg = regs->tpc;
431 break;
432 case 34: /* NPC */
433 reg = regs->tnpc;
434 break;
435 case 35: /* Y */
436 reg = regs->y;
437 break;
438 case 36: /* WIM */
439 case 37: /* TBR */
440 reg = 0;
441 break;
442 default:
443 goto finish;
444 }
228 445
229 ret = ptrace_check_attach(child, request == PTRACE_KILL); 446 if (kbuf)
230 if (ret < 0) { 447 *k++ = reg;
231 pt_error_return(regs, -ret); 448 else if (put_user(reg, u++))
232 goto out_tsk; 449 return -EFAULT;
450 pos++;
451 count--;
233 } 452 }
453finish:
454 pos *= sizeof(reg);
455 count *= sizeof(reg);
456
457 return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
458 38 * sizeof(reg), -1);
459}
234 460
235 if (!(test_thread_flag(TIF_32BIT)) && 461static int genregs32_set(struct task_struct *target,
236 ((request == PTRACE_READDATA64) || 462 const struct user_regset *regset,
237 (request == PTRACE_WRITEDATA64) || 463 unsigned int pos, unsigned int count,
238 (request == PTRACE_READTEXT64) || 464 const void *kbuf, const void __user *ubuf)
239 (request == PTRACE_WRITETEXT64) || 465{
240 (request == PTRACE_PEEKTEXT64) || 466 struct pt_regs *regs = task_pt_regs(target);
241 (request == PTRACE_POKETEXT64) || 467 compat_ulong_t __user *reg_window;
242 (request == PTRACE_PEEKDATA64) || 468 const compat_ulong_t *k = kbuf;
243 (request == PTRACE_POKEDATA64))) { 469 const compat_ulong_t __user *u = ubuf;
244 addr = regs->u_regs[UREG_G2]; 470 compat_ulong_t reg;
245 addr2 = regs->u_regs[UREG_G3]; 471
246 request -= 30; /* wheee... */ 472 if (target == current)
473 flushw_user();
474
475 pos /= sizeof(reg);
476 count /= sizeof(reg);
477
478 if (kbuf) {
479 for (; count > 0 && pos < 16; count--)
480 regs->u_regs[pos++] = *k++;
481
482 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
483 for (; count > 0 && pos < 32; count--) {
484 if (put_user(*k++, &reg_window[pos++]))
485 return -EFAULT;
486 }
487 } else {
488 for (; count > 0 && pos < 16; count--) {
489 if (get_user(reg, u++))
490 return -EFAULT;
491 regs->u_regs[pos++] = reg;
492 }
493
494 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
495 for (; count > 0 && pos < 32; count--) {
496 if (get_user(reg, u++) ||
497 put_user(reg, &reg_window[pos++]))
498 return -EFAULT;
499 }
247 } 500 }
501 while (count > 0) {
502 unsigned long tstate;
503
504 if (kbuf)
505 reg = *k++;
506 else if (get_user(reg, u++))
507 return -EFAULT;
508
509 switch (pos) {
510 case 32: /* PSR */
511 tstate = regs->tstate;
512 tstate &= ~(TSTATE_ICC | TSTATE_XCC);
513 tstate |= psr_to_tstate_icc(reg);
514 regs->tstate = tstate;
515 break;
516 case 33: /* PC */
517 regs->tpc = reg;
518 break;
519 case 34: /* NPC */
520 regs->tnpc = reg;
521 break;
522 case 35: /* Y */
523 regs->y = reg;
524 break;
525 case 36: /* WIM */
526 case 37: /* TBR */
527 break;
528 default:
529 goto finish;
530 }
531
532 pos++;
533 count--;
534 }
535finish:
536 pos *= sizeof(reg);
537 count *= sizeof(reg);
538
539 return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
540 38 * sizeof(reg), -1);
541}
542
543static int fpregs32_get(struct task_struct *target,
544 const struct user_regset *regset,
545 unsigned int pos, unsigned int count,
546 void *kbuf, void __user *ubuf)
547{
548 const unsigned long *fpregs = task_thread_info(target)->fpregs;
549 compat_ulong_t enabled;
550 unsigned long fprs;
551 compat_ulong_t fsr;
552 int ret = 0;
553
554 if (target == current)
555 save_and_clear_fpu();
556
557 fprs = task_thread_info(target)->fpsaved[0];
558 if (fprs & FPRS_FEF) {
559 fsr = task_thread_info(target)->xfsr[0];
560 enabled = 1;
561 } else {
562 fsr = 0;
563 enabled = 0;
564 }
565
566 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
567 fpregs,
568 0, 32 * sizeof(u32));
569
570 if (!ret)
571 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
572 32 * sizeof(u32),
573 33 * sizeof(u32));
574 if (!ret)
575 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
576 &fsr,
577 33 * sizeof(u32),
578 34 * sizeof(u32));
579
580 if (!ret) {
581 compat_ulong_t val;
582
583 val = (enabled << 8) | (8 << 16);
584 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
585 &val,
586 34 * sizeof(u32),
587 35 * sizeof(u32));
588 }
589
590 if (!ret)
591 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
592 35 * sizeof(u32), -1);
593
594 return ret;
595}
596
597static int fpregs32_set(struct task_struct *target,
598 const struct user_regset *regset,
599 unsigned int pos, unsigned int count,
600 const void *kbuf, const void __user *ubuf)
601{
602 unsigned long *fpregs = task_thread_info(target)->fpregs;
603 unsigned long fprs;
604 int ret;
605
606 if (target == current)
607 save_and_clear_fpu();
608
609 fprs = task_thread_info(target)->fpsaved[0];
610
611 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
612 fpregs,
613 0, 32 * sizeof(u32));
614 if (!ret)
615 user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
616 32 * sizeof(u32),
617 33 * sizeof(u32));
618 if (!ret && count > 0) {
619 compat_ulong_t fsr;
620 unsigned long val;
621
622 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
623 &fsr,
624 33 * sizeof(u32),
625 34 * sizeof(u32));
626 if (!ret) {
627 val = task_thread_info(target)->xfsr[0];
628 val &= 0xffffffff00000000UL;
629 val |= fsr;
630 task_thread_info(target)->xfsr[0] = val;
631 }
632 }
633
634 fprs |= (FPRS_FEF | FPRS_DL);
635 task_thread_info(target)->fpsaved[0] = fprs;
636
637 if (!ret)
638 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
639 34 * sizeof(u32), -1);
640 return ret;
641}
642
643static const struct user_regset sparc32_regsets[] = {
644 /* Format is:
645 * G0 --> G7
646 * O0 --> O7
647 * L0 --> L7
648 * I0 --> I7
649 * PSR, PC, nPC, Y, WIM, TBR
650 */
651 [REGSET_GENERAL] = {
652 .core_note_type = NT_PRSTATUS,
653 .n = 38 * sizeof(u32),
654 .size = sizeof(u32), .align = sizeof(u32),
655 .get = genregs32_get, .set = genregs32_set
656 },
657 /* Format is:
658 * F0 --> F31
659 * empty 32-bit word
660 * FSR (32--bit word)
661 * FPU QUEUE COUNT (8-bit char)
662 * FPU QUEUE ENTRYSIZE (8-bit char)
663 * FPU ENABLED (8-bit char)
664 * empty 8-bit char
665 * FPU QUEUE (64 32-bit ints)
666 */
667 [REGSET_FP] = {
668 .core_note_type = NT_PRFPREG,
669 .n = 99 * sizeof(u32),
670 .size = sizeof(u32), .align = sizeof(u32),
671 .get = fpregs32_get, .set = fpregs32_set
672 },
673};
674
675static const struct user_regset_view user_sparc32_view = {
676 .name = "sparc", .e_machine = EM_SPARC,
677 .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
678};
679
680const struct user_regset_view *task_user_regset_view(struct task_struct *task)
681{
682 if (test_tsk_thread_flag(task, TIF_32BIT))
683 return &user_sparc32_view;
684 return &user_sparc64_view;
685}
686
687long arch_ptrace(struct task_struct *child, long request, long addr, long data)
688{
689 long addr2 = task_pt_regs(current)->u_regs[UREG_I4];
690 const struct user_regset_view *view;
691 int ret;
692
693 if (test_thread_flag(TIF_32BIT))
694 addr2 &= 0xffffffffUL;
695
696 view = task_user_regset_view(child);
248 697
249 switch(request) { 698 switch(request) {
250 case PTRACE_PEEKUSR: 699 case PTRACE_PEEKUSR:
251 if (addr != 0) 700 ret = (addr != 0) ? -EIO : 0;
252 pt_error_return(regs, EIO); 701 break;
253 else
254 pt_succ_return(regs, 0);
255 goto out_tsk;
256 702
257 case PTRACE_PEEKTEXT: /* read word at location addr. */ 703 case PTRACE_PEEKTEXT: /* read word at location addr. */
258 case PTRACE_PEEKDATA: { 704 case PTRACE_PEEKDATA: {
259 unsigned long tmp64; 705 unsigned long tmp64;
260 unsigned int tmp32; 706 unsigned int tmp32;
261 int res, copied; 707 int copied;
262 708
263 res = -EIO; 709 ret = -EIO;
264 if (test_thread_flag(TIF_32BIT)) { 710 if (test_thread_flag(TIF_32BIT)) {
265 copied = access_process_vm(child, addr, 711 copied = access_process_vm(child, addr,
266 &tmp32, sizeof(tmp32), 0); 712 &tmp32, sizeof(tmp32), 0);
267 tmp64 = (unsigned long) tmp32;
268 if (copied == sizeof(tmp32)) 713 if (copied == sizeof(tmp32))
269 res = 0; 714 ret = put_user(tmp32,
715 (unsigned int __user *) data);
270 } else { 716 } else {
271 copied = access_process_vm(child, addr, 717 copied = access_process_vm(child, addr,
272 &tmp64, sizeof(tmp64), 0); 718 &tmp64, sizeof(tmp64), 0);
273 if (copied == sizeof(tmp64)) 719 if (copied == sizeof(tmp64))
274 res = 0; 720 ret = put_user(tmp64,
721 (unsigned long __user *) data);
275 } 722 }
276 if (res < 0) 723 break;
277 pt_error_return(regs, -res);
278 else
279 pt_os_succ_return(regs, tmp64, (void __user *) data);
280 goto out_tsk;
281 } 724 }
282 725
283 case PTRACE_POKETEXT: /* write the word at location addr. */ 726 case PTRACE_POKETEXT: /* write the word at location addr. */
284 case PTRACE_POKEDATA: { 727 case PTRACE_POKEDATA: {
285 unsigned long tmp64; 728 unsigned long tmp64;
286 unsigned int tmp32; 729 unsigned int tmp32;
287 int copied, res = -EIO; 730 int copied;
288 731
732 ret = -EIO;
289 if (test_thread_flag(TIF_32BIT)) { 733 if (test_thread_flag(TIF_32BIT)) {
290 tmp32 = data; 734 tmp32 = data;
291 copied = access_process_vm(child, addr, 735 copied = access_process_vm(child, addr,
292 &tmp32, sizeof(tmp32), 1); 736 &tmp32, sizeof(tmp32), 1);
293 if (copied == sizeof(tmp32)) 737 if (copied == sizeof(tmp32))
294 res = 0; 738 ret = 0;
295 } else { 739 } else {
296 tmp64 = data; 740 tmp64 = data;
297 copied = access_process_vm(child, addr, 741 copied = access_process_vm(child, addr,
298 &tmp64, sizeof(tmp64), 1); 742 &tmp64, sizeof(tmp64), 1);
299 if (copied == sizeof(tmp64)) 743 if (copied == sizeof(tmp64))
300 res = 0; 744 ret = 0;
301 } 745 }
302 if (res < 0) 746 break;
303 pt_error_return(regs, -res);
304 else
305 pt_succ_return(regs, res);
306 goto out_tsk;
307 } 747 }
308 748
309 case PTRACE_GETREGS: { 749 case PTRACE_GETREGS: {
310 struct pt_regs32 __user *pregs = 750 struct pt_regs32 __user *pregs =
311 (struct pt_regs32 __user *) addr; 751 (struct pt_regs32 __user *) addr;
312 struct pt_regs *cregs = task_pt_regs(child); 752
313 int rval; 753 ret = copy_regset_to_user(child, view, REGSET_GENERAL,
314 754 32 * sizeof(u32),
315 if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) || 755 4 * sizeof(u32),
316 __put_user(cregs->tpc, (&pregs->pc)) || 756 &pregs->psr);
317 __put_user(cregs->tnpc, (&pregs->npc)) || 757 if (!ret)
318 __put_user(cregs->y, (&pregs->y))) { 758 ret = copy_regset_to_user(child, view, REGSET_GENERAL,
319 pt_error_return(regs, EFAULT); 759 1 * sizeof(u32),
320 goto out_tsk; 760 15 * sizeof(u32),
321 } 761 &pregs->u_regs[0]);
322 for (rval = 1; rval < 16; rval++) 762 break;
323 if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
324 pt_error_return(regs, EFAULT);
325 goto out_tsk;
326 }
327 pt_succ_return(regs, 0);
328#ifdef DEBUG_PTRACE
329 printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
330#endif
331 goto out_tsk;
332 } 763 }
333 764
334 case PTRACE_GETREGS64: { 765 case PTRACE_GETREGS64: {
335 struct pt_regs __user *pregs = (struct pt_regs __user *) addr; 766 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
336 struct pt_regs *cregs = task_pt_regs(child); 767
337 unsigned long tpc = cregs->tpc; 768 ret = copy_regset_to_user(child, view, REGSET_GENERAL,
338 int rval; 769 1 * sizeof(u64),
339 770 15 * sizeof(u64),
340 if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) 771 &pregs->u_regs[0]);
341 tpc &= 0xffffffff; 772 if (!ret) {
342 if (__put_user(cregs->tstate, (&pregs->tstate)) || 773 /* XXX doesn't handle 'y' register correctly XXX */
343 __put_user(tpc, (&pregs->tpc)) || 774 ret = copy_regset_to_user(child, view, REGSET_GENERAL,
344 __put_user(cregs->tnpc, (&pregs->tnpc)) || 775 32 * sizeof(u64),
345 __put_user(cregs->y, (&pregs->y))) { 776 4 * sizeof(u64),
346 pt_error_return(regs, EFAULT); 777 &pregs->tstate);
347 goto out_tsk;
348 } 778 }
349 for (rval = 1; rval < 16; rval++) 779 break;
350 if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
351 pt_error_return(regs, EFAULT);
352 goto out_tsk;
353 }
354 pt_succ_return(regs, 0);
355#ifdef DEBUG_PTRACE
356 printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
357#endif
358 goto out_tsk;
359 } 780 }
360 781
361 case PTRACE_SETREGS: { 782 case PTRACE_SETREGS: {
362 struct pt_regs32 __user *pregs = 783 struct pt_regs32 __user *pregs =
363 (struct pt_regs32 __user *) addr; 784 (struct pt_regs32 __user *) addr;
364 struct pt_regs *cregs = task_pt_regs(child); 785
365 unsigned int psr, pc, npc, y; 786 ret = copy_regset_from_user(child, view, REGSET_GENERAL,
366 int i; 787 32 * sizeof(u32),
367 788 4 * sizeof(u32),
368 /* Must be careful, tracing process can only set certain 789 &pregs->psr);
369 * bits in the psr. 790 if (!ret)
370 */ 791 ret = copy_regset_from_user(child, view, REGSET_GENERAL,
371 if (__get_user(psr, (&pregs->psr)) || 792 1 * sizeof(u32),
372 __get_user(pc, (&pregs->pc)) || 793 15 * sizeof(u32),
373 __get_user(npc, (&pregs->npc)) || 794 &pregs->u_regs[0]);
374 __get_user(y, (&pregs->y))) { 795 break;
375 pt_error_return(regs, EFAULT);
376 goto out_tsk;
377 }
378 cregs->tstate &= ~(TSTATE_ICC);
379 cregs->tstate |= psr_to_tstate_icc(psr);
380 if (!((pc | npc) & 3)) {
381 cregs->tpc = pc;
382 cregs->tnpc = npc;
383 }
384 cregs->y = y;
385 for (i = 1; i < 16; i++) {
386 if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
387 pt_error_return(regs, EFAULT);
388 goto out_tsk;
389 }
390 }
391 pt_succ_return(regs, 0);
392 goto out_tsk;
393 } 796 }
394 797
395 case PTRACE_SETREGS64: { 798 case PTRACE_SETREGS64: {
396 struct pt_regs __user *pregs = (struct pt_regs __user *) addr; 799 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
397 struct pt_regs *cregs = task_pt_regs(child); 800
398 unsigned long tstate, tpc, tnpc, y; 801 ret = copy_regset_from_user(child, view, REGSET_GENERAL,
399 int i; 802 1 * sizeof(u64),
400 803 15 * sizeof(u64),
401 /* Must be careful, tracing process can only set certain 804 &pregs->u_regs[0]);
402 * bits in the psr. 805 if (!ret) {
403 */ 806 /* XXX doesn't handle 'y' register correctly XXX */
404 if (__get_user(tstate, (&pregs->tstate)) || 807 ret = copy_regset_from_user(child, view, REGSET_GENERAL,
405 __get_user(tpc, (&pregs->tpc)) || 808 32 * sizeof(u64),
406 __get_user(tnpc, (&pregs->tnpc)) || 809 4 * sizeof(u64),
407 __get_user(y, (&pregs->y))) { 810 &pregs->tstate);
408 pt_error_return(regs, EFAULT);
409 goto out_tsk;
410 }
411 if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) {
412 tpc &= 0xffffffff;
413 tnpc &= 0xffffffff;
414 }
415 tstate &= (TSTATE_ICC | TSTATE_XCC);
416 cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
417 cregs->tstate |= tstate;
418 if (!((tpc | tnpc) & 3)) {
419 cregs->tpc = tpc;
420 cregs->tnpc = tnpc;
421 }
422 cregs->y = y;
423 for (i = 1; i < 16; i++) {
424 if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
425 pt_error_return(regs, EFAULT);
426 goto out_tsk;
427 }
428 } 811 }
429 pt_succ_return(regs, 0); 812 break;
430 goto out_tsk;
431 } 813 }
432 814
433 case PTRACE_GETFPREGS: { 815 case PTRACE_GETFPREGS: {
@@ -443,20 +825,24 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
443 } fpq[16]; 825 } fpq[16];
444 }; 826 };
445 struct fps __user *fps = (struct fps __user *) addr; 827 struct fps __user *fps = (struct fps __user *) addr;
446 unsigned long *fpregs = task_thread_info(child)->fpregs; 828
447 829 ret = copy_regset_to_user(child, view, REGSET_FP,
448 if (copy_to_user(&fps->regs[0], fpregs, 830 0 * sizeof(u32),
449 (32 * sizeof(unsigned int))) || 831 32 * sizeof(u32),
450 __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr)) || 832 &fps->regs[0]);
451 __put_user(0, (&fps->fpqd)) || 833 if (!ret)
452 __put_user(0, (&fps->flags)) || 834 ret = copy_regset_to_user(child, view, REGSET_FP,
453 __put_user(0, (&fps->extra)) || 835 33 * sizeof(u32),
454 clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) { 836 1 * sizeof(u32),
455 pt_error_return(regs, EFAULT); 837 &fps->fsr);
456 goto out_tsk; 838 if (!ret) {
839 if (__put_user(0, &fps->flags) ||
840 __put_user(0, &fps->extra) ||
841 __put_user(0, &fps->fpqd) ||
842 clear_user(&fps->fpq[0], 32 * sizeof(unsigned int)))
843 ret = -EFAULT;
457 } 844 }
458 pt_succ_return(regs, 0); 845 break;
459 goto out_tsk;
460 } 846 }
461 847
462 case PTRACE_GETFPREGS64: { 848 case PTRACE_GETFPREGS64: {
@@ -465,16 +851,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
465 unsigned long fsr; 851 unsigned long fsr;
466 }; 852 };
467 struct fps __user *fps = (struct fps __user *) addr; 853 struct fps __user *fps = (struct fps __user *) addr;
468 unsigned long *fpregs = task_thread_info(child)->fpregs;
469 854
470 if (copy_to_user(&fps->regs[0], fpregs, 855 ret = copy_regset_to_user(child, view, REGSET_FP,
471 (64 * sizeof(unsigned int))) || 856 0 * sizeof(u64),
472 __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) { 857 33 * sizeof(u64),
473 pt_error_return(regs, EFAULT); 858 fps);
474 goto out_tsk; 859 break;
475 }
476 pt_succ_return(regs, 0);
477 goto out_tsk;
478 } 860 }
479 861
480 case PTRACE_SETFPREGS: { 862 case PTRACE_SETFPREGS: {
@@ -490,22 +872,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
490 } fpq[16]; 872 } fpq[16];
491 }; 873 };
492 struct fps __user *fps = (struct fps __user *) addr; 874 struct fps __user *fps = (struct fps __user *) addr;
493 unsigned long *fpregs = task_thread_info(child)->fpregs; 875
494 unsigned fsr; 876 ret = copy_regset_from_user(child, view, REGSET_FP,
495 877 0 * sizeof(u32),
496 if (copy_from_user(fpregs, &fps->regs[0], 878 32 * sizeof(u32),
497 (32 * sizeof(unsigned int))) || 879 &fps->regs[0]);
498 __get_user(fsr, (&fps->fsr))) { 880 if (!ret)
499 pt_error_return(regs, EFAULT); 881 ret = copy_regset_from_user(child, view, REGSET_FP,
500 goto out_tsk; 882 33 * sizeof(u32),
501 } 883 1 * sizeof(u32),
502 task_thread_info(child)->xfsr[0] &= 0xffffffff00000000UL; 884 &fps->fsr);
503 task_thread_info(child)->xfsr[0] |= fsr; 885 break;
504 if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF))
505 task_thread_info(child)->gsr[0] = 0;
506 task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL);
507 pt_succ_return(regs, 0);
508 goto out_tsk;
509 } 886 }
510 887
511 case PTRACE_SETFPREGS64: { 888 case PTRACE_SETFPREGS64: {
@@ -514,134 +891,50 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
514 unsigned long fsr; 891 unsigned long fsr;
515 }; 892 };
516 struct fps __user *fps = (struct fps __user *) addr; 893 struct fps __user *fps = (struct fps __user *) addr;
517 unsigned long *fpregs = task_thread_info(child)->fpregs;
518 894
519 if (copy_from_user(fpregs, &fps->regs[0], 895 ret = copy_regset_to_user(child, view, REGSET_FP,
520 (64 * sizeof(unsigned int))) || 896 0 * sizeof(u64),
521 __get_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) { 897 33 * sizeof(u64),
522 pt_error_return(regs, EFAULT); 898 fps);
523 goto out_tsk; 899 break;
524 }
525 if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF))
526 task_thread_info(child)->gsr[0] = 0;
527 task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
528 pt_succ_return(regs, 0);
529 goto out_tsk;
530 } 900 }
531 901
532 case PTRACE_READTEXT: 902 case PTRACE_READTEXT:
533 case PTRACE_READDATA: { 903 case PTRACE_READDATA:
534 int res = ptrace_readdata(child, addr, 904 ret = ptrace_readdata(child, addr,
535 (char __user *)addr2, data); 905 (char __user *)addr2, data);
536 if (res == data) { 906 if (ret == data)
537 pt_succ_return(regs, 0); 907 ret = 0;
538 goto out_tsk; 908 else if (ret >= 0)
539 } 909 ret = -EIO;
540 if (res >= 0) 910 break;
541 res = -EIO;
542 pt_error_return(regs, -res);
543 goto out_tsk;
544 }
545 911
546 case PTRACE_WRITETEXT: 912 case PTRACE_WRITETEXT:
547 case PTRACE_WRITEDATA: { 913 case PTRACE_WRITEDATA:
548 int res = ptrace_writedata(child, (char __user *) addr2, 914 ret = ptrace_writedata(child, (char __user *) addr2,
549 addr, data); 915 addr, data);
550 if (res == data) { 916 if (ret == data)
551 pt_succ_return(regs, 0); 917 ret = 0;
552 goto out_tsk; 918 else if (ret >= 0)
553 } 919 ret = -EIO;
554 if (res >= 0) 920 break;
555 res = -EIO;
556 pt_error_return(regs, -res);
557 goto out_tsk;
558 }
559 case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
560 addr = 1;
561
562 case PTRACE_CONT: { /* restart after signal. */
563 if (!valid_signal(data)) {
564 pt_error_return(regs, EIO);
565 goto out_tsk;
566 }
567
568 if (request == PTRACE_SYSCALL) {
569 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
570 } else {
571 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
572 }
573
574 child->exit_code = data;
575#ifdef DEBUG_PTRACE
576 printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm,
577 child->pid, child->exit_code,
578 task_pt_regs(child)->tpc,
579 task_pt_regs(child)->tnpc);
580
581#endif
582 wake_up_process(child);
583 pt_succ_return(regs, 0);
584 goto out_tsk;
585 }
586
587/*
588 * make the child exit. Best I can do is send it a sigkill.
589 * perhaps it should be put in the status that it wants to
590 * exit.
591 */
592 case PTRACE_KILL: {
593 if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
594 pt_succ_return(regs, 0);
595 goto out_tsk;
596 }
597 child->exit_code = SIGKILL;
598 wake_up_process(child);
599 pt_succ_return(regs, 0);
600 goto out_tsk;
601 }
602
603 case PTRACE_SUNDETACH: { /* detach a process that was attached. */
604 int error = ptrace_detach(child, data);
605 if (error) {
606 pt_error_return(regs, EIO);
607 goto out_tsk;
608 }
609 pt_succ_return(regs, 0);
610 goto out_tsk;
611 }
612
613 /* PTRACE_DUMPCORE unsupported... */
614 921
615 case PTRACE_GETEVENTMSG: { 922 case PTRACE_GETEVENTMSG: {
616 int err;
617
618 if (test_thread_flag(TIF_32BIT)) 923 if (test_thread_flag(TIF_32BIT))
619 err = put_user(child->ptrace_message, 924 ret = put_user(child->ptrace_message,
620 (unsigned int __user *) data); 925 (unsigned int __user *) data);
621 else 926 else
622 err = put_user(child->ptrace_message, 927 ret = put_user(child->ptrace_message,
623 (unsigned long __user *) data); 928 (unsigned long __user *) data);
624 if (err)
625 pt_error_return(regs, -err);
626 else
627 pt_succ_return(regs, 0);
628 break; 929 break;
629 } 930 }
630 931
631 default: { 932 default:
632 int err = ptrace_request(child, request, addr, data); 933 ret = ptrace_request(child, request, addr, data);
633 if (err) 934 break;
634 pt_error_return(regs, -err);
635 else
636 pt_succ_return(regs, 0);
637 goto out_tsk;
638 }
639 } 935 }
640out_tsk: 936
641 if (child) 937 return ret;
642 put_task_struct(child);
643out:
644 unlock_kernel();
645} 938}
646 939
647asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p) 940asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p)
diff --git a/arch/sparc64/prom/init.c b/arch/sparc64/prom/init.c
index 1c0db842a6f4..87e7c7ea0ee6 100644
--- a/arch/sparc64/prom/init.c
+++ b/arch/sparc64/prom/init.c
@@ -48,7 +48,10 @@ void __init prom_init(void *cif_handler, void *cif_stack)
48 prom_getstring(node, "version", prom_version, sizeof(prom_version)); 48 prom_getstring(node, "version", prom_version, sizeof(prom_version));
49 49
50 prom_printf("\n"); 50 prom_printf("\n");
51}
51 52
53void __init prom_init_report(void)
54{
52 printk("PROMLIB: Sun IEEE Boot Prom '%s'\n", prom_version); 55 printk("PROMLIB: Sun IEEE Boot Prom '%s'\n", prom_version);
53 printk("PROMLIB: Root node compatible: %s\n", prom_root_compatible); 56 printk("PROMLIB: Root node compatible: %s\n", prom_root_compatible);
54} 57}