aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64')
-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
5 files changed, 726 insertions, 432 deletions
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}