~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/sparc/kernel/ptrace_64.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ptrace.c: Sparc process tracing support.
 
2
 *
 
3
 * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
 
4
 * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
 
5
 *
 
6
 * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
 
7
 * and David Mosberger.
 
8
 *
 
9
 * Added Linux support -miguel (weird, eh?, the original code was meant
 
10
 * to emulate SunOS).
 
11
 */
 
12
 
 
13
#include <linux/kernel.h>
 
14
#include <linux/sched.h>
 
15
#include <linux/mm.h>
 
16
#include <linux/errno.h>
 
17
#include <linux/ptrace.h>
 
18
#include <linux/user.h>
 
19
#include <linux/smp.h>
 
20
#include <linux/security.h>
 
21
#include <linux/seccomp.h>
 
22
#include <linux/audit.h>
 
23
#include <linux/signal.h>
 
24
#include <linux/regset.h>
 
25
#include <linux/tracehook.h>
 
26
#include <trace/syscall.h>
 
27
#include <linux/compat.h>
 
28
#include <linux/elf.h>
 
29
 
 
30
#include <asm/asi.h>
 
31
#include <asm/pgtable.h>
 
32
#include <asm/system.h>
 
33
#include <asm/uaccess.h>
 
34
#include <asm/psrcompat.h>
 
35
#include <asm/visasm.h>
 
36
#include <asm/spitfire.h>
 
37
#include <asm/page.h>
 
38
#include <asm/cpudata.h>
 
39
#include <asm/cacheflush.h>
 
40
 
 
41
#define CREATE_TRACE_POINTS
 
42
#include <trace/events/syscalls.h>
 
43
 
 
44
#include "entry.h"
 
45
 
 
46
/* #define ALLOW_INIT_TRACING */
 
47
 
 
48
/*
 
49
 * Called by kernel/ptrace.c when detaching..
 
50
 *
 
51
 * Make sure single step bits etc are not set.
 
52
 */
 
53
void ptrace_disable(struct task_struct *child)
 
54
{
 
55
        /* nothing to do */
 
56
}
 
57
 
 
58
/* To get the necessary page struct, access_process_vm() first calls
 
59
 * get_user_pages().  This has done a flush_dcache_page() on the
 
60
 * accessed page.  Then our caller (copy_{to,from}_user_page()) did
 
61
 * to memcpy to read/write the data from that page.
 
62
 *
 
63
 * Now, the only thing we have to do is:
 
64
 * 1) flush the D-cache if it's possible than an illegal alias
 
65
 *    has been created
 
66
 * 2) flush the I-cache if this is pre-cheetah and we did a write
 
67
 */
 
68
void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
 
69
                         unsigned long uaddr, void *kaddr,
 
70
                         unsigned long len, int write)
 
71
{
 
72
        BUG_ON(len > PAGE_SIZE);
 
73
 
 
74
        if (tlb_type == hypervisor)
 
75
                return;
 
76
 
 
77
        preempt_disable();
 
78
 
 
79
#ifdef DCACHE_ALIASING_POSSIBLE
 
80
        /* If bit 13 of the kernel address we used to access the
 
81
         * user page is the same as the virtual address that page
 
82
         * is mapped to in the user's address space, we can skip the
 
83
         * D-cache flush.
 
84
         */
 
85
        if ((uaddr ^ (unsigned long) kaddr) & (1UL << 13)) {
 
86
                unsigned long start = __pa(kaddr);
 
87
                unsigned long end = start + len;
 
88
                unsigned long dcache_line_size;
 
89
 
 
90
                dcache_line_size = local_cpu_data().dcache_line_size;
 
91
 
 
92
                if (tlb_type == spitfire) {
 
93
                        for (; start < end; start += dcache_line_size)
 
94
                                spitfire_put_dcache_tag(start & 0x3fe0, 0x0);
 
95
                } else {
 
96
                        start &= ~(dcache_line_size - 1);
 
97
                        for (; start < end; start += dcache_line_size)
 
98
                                __asm__ __volatile__(
 
99
                                        "stxa %%g0, [%0] %1\n\t"
 
100
                                        "membar #Sync"
 
101
                                        : /* no outputs */
 
102
                                        : "r" (start),
 
103
                                        "i" (ASI_DCACHE_INVALIDATE));
 
104
                }
 
105
        }
 
106
#endif
 
107
        if (write && tlb_type == spitfire) {
 
108
                unsigned long start = (unsigned long) kaddr;
 
109
                unsigned long end = start + len;
 
110
                unsigned long icache_line_size;
 
111
 
 
112
                icache_line_size = local_cpu_data().icache_line_size;
 
113
 
 
114
                for (; start < end; start += icache_line_size)
 
115
                        flushi(start);
 
116
        }
 
117
 
 
118
        preempt_enable();
 
119
}
 
120
 
 
121
static int get_from_target(struct task_struct *target, unsigned long uaddr,
 
122
                           void *kbuf, int len)
 
123
{
 
124
        if (target == current) {
 
125
                if (copy_from_user(kbuf, (void __user *) uaddr, len))
 
126
                        return -EFAULT;
 
127
        } else {
 
128
                int len2 = access_process_vm(target, uaddr, kbuf, len, 0);
 
129
                if (len2 != len)
 
130
                        return -EFAULT;
 
131
        }
 
132
        return 0;
 
133
}
 
134
 
 
135
static int set_to_target(struct task_struct *target, unsigned long uaddr,
 
136
                         void *kbuf, int len)
 
137
{
 
138
        if (target == current) {
 
139
                if (copy_to_user((void __user *) uaddr, kbuf, len))
 
140
                        return -EFAULT;
 
141
        } else {
 
142
                int len2 = access_process_vm(target, uaddr, kbuf, len, 1);
 
143
                if (len2 != len)
 
144
                        return -EFAULT;
 
145
        }
 
146
        return 0;
 
147
}
 
148
 
 
149
static int regwindow64_get(struct task_struct *target,
 
150
                           const struct pt_regs *regs,
 
151
                           struct reg_window *wbuf)
 
152
{
 
153
        unsigned long rw_addr = regs->u_regs[UREG_I6];
 
154
 
 
155
        if (test_tsk_thread_flag(current, TIF_32BIT)) {
 
156
                struct reg_window32 win32;
 
157
                int i;
 
158
 
 
159
                if (get_from_target(target, rw_addr, &win32, sizeof(win32)))
 
160
                        return -EFAULT;
 
161
                for (i = 0; i < 8; i++)
 
162
                        wbuf->locals[i] = win32.locals[i];
 
163
                for (i = 0; i < 8; i++)
 
164
                        wbuf->ins[i] = win32.ins[i];
 
165
        } else {
 
166
                rw_addr += STACK_BIAS;
 
167
                if (get_from_target(target, rw_addr, wbuf, sizeof(*wbuf)))
 
168
                        return -EFAULT;
 
169
        }
 
170
 
 
171
        return 0;
 
172
}
 
173
 
 
174
static int regwindow64_set(struct task_struct *target,
 
175
                           const struct pt_regs *regs,
 
176
                           struct reg_window *wbuf)
 
177
{
 
178
        unsigned long rw_addr = regs->u_regs[UREG_I6];
 
179
 
 
180
        if (test_tsk_thread_flag(current, TIF_32BIT)) {
 
181
                struct reg_window32 win32;
 
182
                int i;
 
183
 
 
184
                for (i = 0; i < 8; i++)
 
185
                        win32.locals[i] = wbuf->locals[i];
 
186
                for (i = 0; i < 8; i++)
 
187
                        win32.ins[i] = wbuf->ins[i];
 
188
 
 
189
                if (set_to_target(target, rw_addr, &win32, sizeof(win32)))
 
190
                        return -EFAULT;
 
191
        } else {
 
192
                rw_addr += STACK_BIAS;
 
193
                if (set_to_target(target, rw_addr, wbuf, sizeof(*wbuf)))
 
194
                        return -EFAULT;
 
195
        }
 
196
 
 
197
        return 0;
 
198
}
 
199
 
 
200
enum sparc_regset {
 
201
        REGSET_GENERAL,
 
202
        REGSET_FP,
 
203
};
 
204
 
 
205
static int genregs64_get(struct task_struct *target,
 
206
                         const struct user_regset *regset,
 
207
                         unsigned int pos, unsigned int count,
 
208
                         void *kbuf, void __user *ubuf)
 
209
{
 
210
        const struct pt_regs *regs = task_pt_regs(target);
 
211
        int ret;
 
212
 
 
213
        if (target == current)
 
214
                flushw_user();
 
215
 
 
216
        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 
217
                                  regs->u_regs,
 
218
                                  0, 16 * sizeof(u64));
 
219
        if (!ret && count && pos < (32 * sizeof(u64))) {
 
220
                struct reg_window window;
 
221
 
 
222
                if (regwindow64_get(target, regs, &window))
 
223
                        return -EFAULT;
 
224
                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 
225
                                          &window,
 
226
                                          16 * sizeof(u64),
 
227
                                          32 * sizeof(u64));
 
228
        }
 
229
 
 
230
        if (!ret) {
 
231
                /* TSTATE, TPC, TNPC */
 
232
                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 
233
                                          &regs->tstate,
 
234
                                          32 * sizeof(u64),
 
235
                                          35 * sizeof(u64));
 
236
        }
 
237
 
 
238
        if (!ret) {
 
239
                unsigned long y = regs->y;
 
240
 
 
241
                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 
242
                                          &y,
 
243
                                          35 * sizeof(u64),
 
244
                                          36 * sizeof(u64));
 
245
        }
 
246
 
 
247
        if (!ret) {
 
248
                ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
 
249
                                               36 * sizeof(u64), -1);
 
250
 
 
251
        }
 
252
        return ret;
 
253
}
 
254
 
 
255
static int genregs64_set(struct task_struct *target,
 
256
                         const struct user_regset *regset,
 
257
                         unsigned int pos, unsigned int count,
 
258
                         const void *kbuf, const void __user *ubuf)
 
259
{
 
260
        struct pt_regs *regs = task_pt_regs(target);
 
261
        int ret;
 
262
 
 
263
        if (target == current)
 
264
                flushw_user();
 
265
 
 
266
        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 
267
                                 regs->u_regs,
 
268
                                 0, 16 * sizeof(u64));
 
269
        if (!ret && count && pos < (32 * sizeof(u64))) {
 
270
                struct reg_window window;
 
271
 
 
272
                if (regwindow64_get(target, regs, &window))
 
273
                        return -EFAULT;
 
274
 
 
275
                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 
276
                                         &window,
 
277
                                         16 * sizeof(u64),
 
278
                                         32 * sizeof(u64));
 
279
 
 
280
                if (!ret &&
 
281
                    regwindow64_set(target, regs, &window))
 
282
                        return -EFAULT;
 
283
        }
 
284
 
 
285
        if (!ret && count > 0) {
 
286
                unsigned long tstate;
 
287
 
 
288
                /* TSTATE */
 
289
                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 
290
                                         &tstate,
 
291
                                         32 * sizeof(u64),
 
292
                                         33 * sizeof(u64));
 
293
                if (!ret) {
 
294
                        /* Only the condition codes and the "in syscall"
 
295
                         * state can be modified in the %tstate register.
 
296
                         */
 
297
                        tstate &= (TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
 
298
                        regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
 
299
                        regs->tstate |= tstate;
 
300
                }
 
301
        }
 
302
 
 
303
        if (!ret) {
 
304
                /* TPC, TNPC */
 
305
                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 
306
                                         &regs->tpc,
 
307
                                         33 * sizeof(u64),
 
308
                                         35 * sizeof(u64));
 
309
        }
 
310
 
 
311
        if (!ret) {
 
312
                unsigned long y;
 
313
 
 
314
                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 
315
                                         &y,
 
316
                                         35 * sizeof(u64),
 
317
                                         36 * sizeof(u64));
 
318
                if (!ret)
 
319
                        regs->y = y;
 
320
        }
 
321
 
 
322
        if (!ret)
 
323
                ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
 
324
                                                36 * sizeof(u64), -1);
 
325
 
 
326
        return ret;
 
327
}
 
328
 
 
329
static int fpregs64_get(struct task_struct *target,
 
330
                        const struct user_regset *regset,
 
331
                        unsigned int pos, unsigned int count,
 
332
                        void *kbuf, void __user *ubuf)
 
333
{
 
334
        const unsigned long *fpregs = task_thread_info(target)->fpregs;
 
335
        unsigned long fprs, fsr, gsr;
 
336
        int ret;
 
337
 
 
338
        if (target == current)
 
339
                save_and_clear_fpu();
 
340
 
 
341
        fprs = task_thread_info(target)->fpsaved[0];
 
342
 
 
343
        if (fprs & FPRS_DL)
 
344
                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 
345
                                          fpregs,
 
346
                                          0, 16 * sizeof(u64));
 
347
        else
 
348
                ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
 
349
                                               0,
 
350
                                               16 * sizeof(u64));
 
351
 
 
352
        if (!ret) {
 
353
                if (fprs & FPRS_DU)
 
354
                        ret = user_regset_copyout(&pos, &count,
 
355
                                                  &kbuf, &ubuf,
 
356
                                                  fpregs + 16,
 
357
                                                  16 * sizeof(u64),
 
358
                                                  32 * sizeof(u64));
 
359
                else
 
360
                        ret = user_regset_copyout_zero(&pos, &count,
 
361
                                                       &kbuf, &ubuf,
 
362
                                                       16 * sizeof(u64),
 
363
                                                       32 * sizeof(u64));
 
364
        }
 
365
 
 
366
        if (fprs & FPRS_FEF) {
 
367
                fsr = task_thread_info(target)->xfsr[0];
 
368
                gsr = task_thread_info(target)->gsr[0];
 
369
        } else {
 
370
                fsr = gsr = 0;
 
371
        }
 
372
 
 
373
        if (!ret)
 
374
                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 
375
                                          &fsr,
 
376
                                          32 * sizeof(u64),
 
377
                                          33 * sizeof(u64));
 
378
        if (!ret)
 
379
                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 
380
                                          &gsr,
 
381
                                          33 * sizeof(u64),
 
382
                                          34 * sizeof(u64));
 
383
        if (!ret)
 
384
                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 
385
                                          &fprs,
 
386
                                          34 * sizeof(u64),
 
387
                                          35 * sizeof(u64));
 
388
 
 
389
        if (!ret)
 
390
                ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
 
391
                                               35 * sizeof(u64), -1);
 
392
 
 
393
        return ret;
 
394
}
 
395
 
 
396
static int fpregs64_set(struct task_struct *target,
 
397
                        const struct user_regset *regset,
 
398
                        unsigned int pos, unsigned int count,
 
399
                        const void *kbuf, const void __user *ubuf)
 
400
{
 
401
        unsigned long *fpregs = task_thread_info(target)->fpregs;
 
402
        unsigned long fprs;
 
403
        int ret;
 
404
 
 
405
        if (target == current)
 
406
                save_and_clear_fpu();
 
407
 
 
408
        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 
409
                                 fpregs,
 
410
                                 0, 32 * sizeof(u64));
 
411
        if (!ret)
 
412
                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 
413
                                         task_thread_info(target)->xfsr,
 
414
                                         32 * sizeof(u64),
 
415
                                         33 * sizeof(u64));
 
416
        if (!ret)
 
417
                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 
418
                                         task_thread_info(target)->gsr,
 
419
                                         33 * sizeof(u64),
 
420
                                         34 * sizeof(u64));
 
421
 
 
422
        fprs = task_thread_info(target)->fpsaved[0];
 
423
        if (!ret && count > 0) {
 
424
                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 
425
                                         &fprs,
 
426
                                         34 * sizeof(u64),
 
427
                                         35 * sizeof(u64));
 
428
        }
 
429
 
 
430
        fprs |= (FPRS_FEF | FPRS_DL | FPRS_DU);
 
431
        task_thread_info(target)->fpsaved[0] = fprs;
 
432
 
 
433
        if (!ret)
 
434
                ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
 
435
                                                35 * sizeof(u64), -1);
 
436
        return ret;
 
437
}
 
438
 
 
439
static const struct user_regset sparc64_regsets[] = {
 
440
        /* Format is:
 
441
         *      G0 --> G7
 
442
         *      O0 --> O7
 
443
         *      L0 --> L7
 
444
         *      I0 --> I7
 
445
         *      TSTATE, TPC, TNPC, Y
 
446
         */
 
447
        [REGSET_GENERAL] = {
 
448
                .core_note_type = NT_PRSTATUS,
 
449
                .n = 36,
 
450
                .size = sizeof(u64), .align = sizeof(u64),
 
451
                .get = genregs64_get, .set = genregs64_set
 
452
        },
 
453
        /* Format is:
 
454
         *      F0 --> F63
 
455
         *      FSR
 
456
         *      GSR
 
457
         *      FPRS
 
458
         */
 
459
        [REGSET_FP] = {
 
460
                .core_note_type = NT_PRFPREG,
 
461
                .n = 35,
 
462
                .size = sizeof(u64), .align = sizeof(u64),
 
463
                .get = fpregs64_get, .set = fpregs64_set
 
464
        },
 
465
};
 
466
 
 
467
static const struct user_regset_view user_sparc64_view = {
 
468
        .name = "sparc64", .e_machine = EM_SPARCV9,
 
469
        .regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets)
 
470
};
 
471
 
 
472
#ifdef CONFIG_COMPAT
 
473
static int genregs32_get(struct task_struct *target,
 
474
                         const struct user_regset *regset,
 
475
                         unsigned int pos, unsigned int count,
 
476
                         void *kbuf, void __user *ubuf)
 
477
{
 
478
        const struct pt_regs *regs = task_pt_regs(target);
 
479
        compat_ulong_t __user *reg_window;
 
480
        compat_ulong_t *k = kbuf;
 
481
        compat_ulong_t __user *u = ubuf;
 
482
        compat_ulong_t reg;
 
483
 
 
484
        if (target == current)
 
485
                flushw_user();
 
486
 
 
487
        pos /= sizeof(reg);
 
488
        count /= sizeof(reg);
 
489
 
 
490
        if (kbuf) {
 
491
                for (; count > 0 && pos < 16; count--)
 
492
                        *k++ = regs->u_regs[pos++];
 
493
 
 
494
                reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
 
495
                reg_window -= 16;
 
496
                if (target == current) {
 
497
                        for (; count > 0 && pos < 32; count--) {
 
498
                                if (get_user(*k++, &reg_window[pos++]))
 
499
                                        return -EFAULT;
 
500
                        }
 
501
                } else {
 
502
                        for (; count > 0 && pos < 32; count--) {
 
503
                                if (access_process_vm(target,
 
504
                                                      (unsigned long)
 
505
                                                      &reg_window[pos],
 
506
                                                      k, sizeof(*k), 0)
 
507
                                    != sizeof(*k))
 
508
                                        return -EFAULT;
 
509
                                k++;
 
510
                                pos++;
 
511
                        }
 
512
                }
 
513
        } else {
 
514
                for (; count > 0 && pos < 16; count--) {
 
515
                        if (put_user((compat_ulong_t) regs->u_regs[pos++], u++))
 
516
                                return -EFAULT;
 
517
                }
 
518
 
 
519
                reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
 
520
                reg_window -= 16;
 
521
                if (target == current) {
 
522
                        for (; count > 0 && pos < 32; count--) {
 
523
                                if (get_user(reg, &reg_window[pos++]) ||
 
524
                                    put_user(reg, u++))
 
525
                                        return -EFAULT;
 
526
                        }
 
527
                } else {
 
528
                        for (; count > 0 && pos < 32; count--) {
 
529
                                if (access_process_vm(target,
 
530
                                                      (unsigned long)
 
531
                                                      &reg_window[pos],
 
532
                                                      &reg, sizeof(reg), 0)
 
533
                                    != sizeof(reg))
 
534
                                        return -EFAULT;
 
535
                                if (access_process_vm(target,
 
536
                                                      (unsigned long) u,
 
537
                                                      &reg, sizeof(reg), 1)
 
538
                                    != sizeof(reg))
 
539
                                        return -EFAULT;
 
540
                                pos++;
 
541
                                u++;
 
542
                        }
 
543
                }
 
544
        }
 
545
        while (count > 0) {
 
546
                switch (pos) {
 
547
                case 32: /* PSR */
 
548
                        reg = tstate_to_psr(regs->tstate);
 
549
                        break;
 
550
                case 33: /* PC */
 
551
                        reg = regs->tpc;
 
552
                        break;
 
553
                case 34: /* NPC */
 
554
                        reg = regs->tnpc;
 
555
                        break;
 
556
                case 35: /* Y */
 
557
                        reg = regs->y;
 
558
                        break;
 
559
                case 36: /* WIM */
 
560
                case 37: /* TBR */
 
561
                        reg = 0;
 
562
                        break;
 
563
                default:
 
564
                        goto finish;
 
565
                }
 
566
 
 
567
                if (kbuf)
 
568
                        *k++ = reg;
 
569
                else if (put_user(reg, u++))
 
570
                        return -EFAULT;
 
571
                pos++;
 
572
                count--;
 
573
        }
 
574
finish:
 
575
        pos *= sizeof(reg);
 
576
        count *= sizeof(reg);
 
577
 
 
578
        return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
 
579
                                        38 * sizeof(reg), -1);
 
580
}
 
581
 
 
582
static int genregs32_set(struct task_struct *target,
 
583
                         const struct user_regset *regset,
 
584
                         unsigned int pos, unsigned int count,
 
585
                         const void *kbuf, const void __user *ubuf)
 
586
{
 
587
        struct pt_regs *regs = task_pt_regs(target);
 
588
        compat_ulong_t __user *reg_window;
 
589
        const compat_ulong_t *k = kbuf;
 
590
        const compat_ulong_t __user *u = ubuf;
 
591
        compat_ulong_t reg;
 
592
 
 
593
        if (target == current)
 
594
                flushw_user();
 
595
 
 
596
        pos /= sizeof(reg);
 
597
        count /= sizeof(reg);
 
598
 
 
599
        if (kbuf) {
 
600
                for (; count > 0 && pos < 16; count--)
 
601
                        regs->u_regs[pos++] = *k++;
 
602
 
 
603
                reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
 
604
                reg_window -= 16;
 
605
                if (target == current) {
 
606
                        for (; count > 0 && pos < 32; count--) {
 
607
                                if (put_user(*k++, &reg_window[pos++]))
 
608
                                        return -EFAULT;
 
609
                        }
 
610
                } else {
 
611
                        for (; count > 0 && pos < 32; count--) {
 
612
                                if (access_process_vm(target,
 
613
                                                      (unsigned long)
 
614
                                                      &reg_window[pos],
 
615
                                                      (void *) k,
 
616
                                                      sizeof(*k), 1)
 
617
                                    != sizeof(*k))
 
618
                                        return -EFAULT;
 
619
                                k++;
 
620
                                pos++;
 
621
                        }
 
622
                }
 
623
        } else {
 
624
                for (; count > 0 && pos < 16; count--) {
 
625
                        if (get_user(reg, u++))
 
626
                                return -EFAULT;
 
627
                        regs->u_regs[pos++] = reg;
 
628
                }
 
629
 
 
630
                reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
 
631
                reg_window -= 16;
 
632
                if (target == current) {
 
633
                        for (; count > 0 && pos < 32; count--) {
 
634
                                if (get_user(reg, u++) ||
 
635
                                    put_user(reg, &reg_window[pos++]))
 
636
                                        return -EFAULT;
 
637
                        }
 
638
                } else {
 
639
                        for (; count > 0 && pos < 32; count--) {
 
640
                                if (access_process_vm(target,
 
641
                                                      (unsigned long)
 
642
                                                      u,
 
643
                                                      &reg, sizeof(reg), 0)
 
644
                                    != sizeof(reg))
 
645
                                        return -EFAULT;
 
646
                                if (access_process_vm(target,
 
647
                                                      (unsigned long)
 
648
                                                      &reg_window[pos],
 
649
                                                      &reg, sizeof(reg), 1)
 
650
                                    != sizeof(reg))
 
651
                                        return -EFAULT;
 
652
                                pos++;
 
653
                                u++;
 
654
                        }
 
655
                }
 
656
        }
 
657
        while (count > 0) {
 
658
                unsigned long tstate;
 
659
 
 
660
                if (kbuf)
 
661
                        reg = *k++;
 
662
                else if (get_user(reg, u++))
 
663
                        return -EFAULT;
 
664
 
 
665
                switch (pos) {
 
666
                case 32: /* PSR */
 
667
                        tstate = regs->tstate;
 
668
                        tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
 
669
                        tstate |= psr_to_tstate_icc(reg);
 
670
                        if (reg & PSR_SYSCALL)
 
671
                                tstate |= TSTATE_SYSCALL;
 
672
                        regs->tstate = tstate;
 
673
                        break;
 
674
                case 33: /* PC */
 
675
                        regs->tpc = reg;
 
676
                        break;
 
677
                case 34: /* NPC */
 
678
                        regs->tnpc = reg;
 
679
                        break;
 
680
                case 35: /* Y */
 
681
                        regs->y = reg;
 
682
                        break;
 
683
                case 36: /* WIM */
 
684
                case 37: /* TBR */
 
685
                        break;
 
686
                default:
 
687
                        goto finish;
 
688
                }
 
689
 
 
690
                pos++;
 
691
                count--;
 
692
        }
 
693
finish:
 
694
        pos *= sizeof(reg);
 
695
        count *= sizeof(reg);
 
696
 
 
697
        return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
 
698
                                         38 * sizeof(reg), -1);
 
699
}
 
700
 
 
701
static int fpregs32_get(struct task_struct *target,
 
702
                        const struct user_regset *regset,
 
703
                        unsigned int pos, unsigned int count,
 
704
                        void *kbuf, void __user *ubuf)
 
705
{
 
706
        const unsigned long *fpregs = task_thread_info(target)->fpregs;
 
707
        compat_ulong_t enabled;
 
708
        unsigned long fprs;
 
709
        compat_ulong_t fsr;
 
710
        int ret = 0;
 
711
 
 
712
        if (target == current)
 
713
                save_and_clear_fpu();
 
714
 
 
715
        fprs = task_thread_info(target)->fpsaved[0];
 
716
        if (fprs & FPRS_FEF) {
 
717
                fsr = task_thread_info(target)->xfsr[0];
 
718
                enabled = 1;
 
719
        } else {
 
720
                fsr = 0;
 
721
                enabled = 0;
 
722
        }
 
723
 
 
724
        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 
725
                                  fpregs,
 
726
                                  0, 32 * sizeof(u32));
 
727
 
 
728
        if (!ret)
 
729
                ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
 
730
                                               32 * sizeof(u32),
 
731
                                               33 * sizeof(u32));
 
732
        if (!ret)
 
733
                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 
734
                                          &fsr,
 
735
                                          33 * sizeof(u32),
 
736
                                          34 * sizeof(u32));
 
737
 
 
738
        if (!ret) {
 
739
                compat_ulong_t val;
 
740
 
 
741
                val = (enabled << 8) | (8 << 16);
 
742
                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 
743
                                          &val,
 
744
                                          34 * sizeof(u32),
 
745
                                          35 * sizeof(u32));
 
746
        }
 
747
 
 
748
        if (!ret)
 
749
                ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
 
750
                                               35 * sizeof(u32), -1);
 
751
 
 
752
        return ret;
 
753
}
 
754
 
 
755
static int fpregs32_set(struct task_struct *target,
 
756
                        const struct user_regset *regset,
 
757
                        unsigned int pos, unsigned int count,
 
758
                        const void *kbuf, const void __user *ubuf)
 
759
{
 
760
        unsigned long *fpregs = task_thread_info(target)->fpregs;
 
761
        unsigned long fprs;
 
762
        int ret;
 
763
 
 
764
        if (target == current)
 
765
                save_and_clear_fpu();
 
766
 
 
767
        fprs = task_thread_info(target)->fpsaved[0];
 
768
 
 
769
        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 
770
                                 fpregs,
 
771
                                 0, 32 * sizeof(u32));
 
772
        if (!ret)
 
773
                user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
 
774
                                          32 * sizeof(u32),
 
775
                                          33 * sizeof(u32));
 
776
        if (!ret && count > 0) {
 
777
                compat_ulong_t fsr;
 
778
                unsigned long val;
 
779
 
 
780
                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 
781
                                         &fsr,
 
782
                                         33 * sizeof(u32),
 
783
                                         34 * sizeof(u32));
 
784
                if (!ret) {
 
785
                        val = task_thread_info(target)->xfsr[0];
 
786
                        val &= 0xffffffff00000000UL;
 
787
                        val |= fsr;
 
788
                        task_thread_info(target)->xfsr[0] = val;
 
789
                }
 
790
        }
 
791
 
 
792
        fprs |= (FPRS_FEF | FPRS_DL);
 
793
        task_thread_info(target)->fpsaved[0] = fprs;
 
794
 
 
795
        if (!ret)
 
796
                ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
 
797
                                                34 * sizeof(u32), -1);
 
798
        return ret;
 
799
}
 
800
 
 
801
static const struct user_regset sparc32_regsets[] = {
 
802
        /* Format is:
 
803
         *      G0 --> G7
 
804
         *      O0 --> O7
 
805
         *      L0 --> L7
 
806
         *      I0 --> I7
 
807
         *      PSR, PC, nPC, Y, WIM, TBR
 
808
         */
 
809
        [REGSET_GENERAL] = {
 
810
                .core_note_type = NT_PRSTATUS,
 
811
                .n = 38,
 
812
                .size = sizeof(u32), .align = sizeof(u32),
 
813
                .get = genregs32_get, .set = genregs32_set
 
814
        },
 
815
        /* Format is:
 
816
         *      F0 --> F31
 
817
         *      empty 32-bit word
 
818
         *      FSR (32--bit word)
 
819
         *      FPU QUEUE COUNT (8-bit char)
 
820
         *      FPU QUEUE ENTRYSIZE (8-bit char)
 
821
         *      FPU ENABLED (8-bit char)
 
822
         *      empty 8-bit char
 
823
         *      FPU QUEUE (64 32-bit ints)
 
824
         */
 
825
        [REGSET_FP] = {
 
826
                .core_note_type = NT_PRFPREG,
 
827
                .n = 99,
 
828
                .size = sizeof(u32), .align = sizeof(u32),
 
829
                .get = fpregs32_get, .set = fpregs32_set
 
830
        },
 
831
};
 
832
 
 
833
static const struct user_regset_view user_sparc32_view = {
 
834
        .name = "sparc", .e_machine = EM_SPARC,
 
835
        .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
 
836
};
 
837
#endif /* CONFIG_COMPAT */
 
838
 
 
839
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 
840
{
 
841
#ifdef CONFIG_COMPAT
 
842
        if (test_tsk_thread_flag(task, TIF_32BIT))
 
843
                return &user_sparc32_view;
 
844
#endif
 
845
        return &user_sparc64_view;
 
846
}
 
847
 
 
848
#ifdef CONFIG_COMPAT
 
849
struct compat_fps {
 
850
        unsigned int regs[32];
 
851
        unsigned int fsr;
 
852
        unsigned int flags;
 
853
        unsigned int extra;
 
854
        unsigned int fpqd;
 
855
        struct compat_fq {
 
856
                unsigned int insnaddr;
 
857
                unsigned int insn;
 
858
        } fpq[16];
 
859
};
 
860
 
 
861
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 
862
                        compat_ulong_t caddr, compat_ulong_t cdata)
 
863
{
 
864
        const struct user_regset_view *view = task_user_regset_view(current);
 
865
        compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4];
 
866
        struct pt_regs32 __user *pregs;
 
867
        struct compat_fps __user *fps;
 
868
        unsigned long addr2 = caddr2;
 
869
        unsigned long addr = caddr;
 
870
        unsigned long data = cdata;
 
871
        int ret;
 
872
 
 
873
        pregs = (struct pt_regs32 __user *) addr;
 
874
        fps = (struct compat_fps __user *) addr;
 
875
 
 
876
        switch (request) {
 
877
        case PTRACE_PEEKUSR:
 
878
                ret = (addr != 0) ? -EIO : 0;
 
879
                break;
 
880
 
 
881
        case PTRACE_GETREGS:
 
882
                ret = copy_regset_to_user(child, view, REGSET_GENERAL,
 
883
                                          32 * sizeof(u32),
 
884
                                          4 * sizeof(u32),
 
885
                                          &pregs->psr);
 
886
                if (!ret)
 
887
                        ret = copy_regset_to_user(child, view, REGSET_GENERAL,
 
888
                                                  1 * sizeof(u32),
 
889
                                                  15 * sizeof(u32),
 
890
                                                  &pregs->u_regs[0]);
 
891
                break;
 
892
 
 
893
        case PTRACE_SETREGS:
 
894
                ret = copy_regset_from_user(child, view, REGSET_GENERAL,
 
895
                                            32 * sizeof(u32),
 
896
                                            4 * sizeof(u32),
 
897
                                            &pregs->psr);
 
898
                if (!ret)
 
899
                        ret = copy_regset_from_user(child, view, REGSET_GENERAL,
 
900
                                                    1 * sizeof(u32),
 
901
                                                    15 * sizeof(u32),
 
902
                                                    &pregs->u_regs[0]);
 
903
                break;
 
904
 
 
905
        case PTRACE_GETFPREGS:
 
906
                ret = copy_regset_to_user(child, view, REGSET_FP,
 
907
                                          0 * sizeof(u32),
 
908
                                          32 * sizeof(u32),
 
909
                                          &fps->regs[0]);
 
910
                if (!ret)
 
911
                        ret = copy_regset_to_user(child, view, REGSET_FP,
 
912
                                                  33 * sizeof(u32),
 
913
                                                  1 * sizeof(u32),
 
914
                                                  &fps->fsr);
 
915
                if (!ret) {
 
916
                        if (__put_user(0, &fps->flags) ||
 
917
                            __put_user(0, &fps->extra) ||
 
918
                            __put_user(0, &fps->fpqd) ||
 
919
                            clear_user(&fps->fpq[0], 32 * sizeof(unsigned int)))
 
920
                                ret = -EFAULT;
 
921
                }
 
922
                break;
 
923
 
 
924
        case PTRACE_SETFPREGS:
 
925
                ret = copy_regset_from_user(child, view, REGSET_FP,
 
926
                                            0 * sizeof(u32),
 
927
                                            32 * sizeof(u32),
 
928
                                            &fps->regs[0]);
 
929
                if (!ret)
 
930
                        ret = copy_regset_from_user(child, view, REGSET_FP,
 
931
                                                    33 * sizeof(u32),
 
932
                                                    1 * sizeof(u32),
 
933
                                                    &fps->fsr);
 
934
                break;
 
935
 
 
936
        case PTRACE_READTEXT:
 
937
        case PTRACE_READDATA:
 
938
                ret = ptrace_readdata(child, addr,
 
939
                                      (char __user *)addr2, data);
 
940
                if (ret == data)
 
941
                        ret = 0;
 
942
                else if (ret >= 0)
 
943
                        ret = -EIO;
 
944
                break;
 
945
 
 
946
        case PTRACE_WRITETEXT:
 
947
        case PTRACE_WRITEDATA:
 
948
                ret = ptrace_writedata(child, (char __user *) addr2,
 
949
                                       addr, data);
 
950
                if (ret == data)
 
951
                        ret = 0;
 
952
                else if (ret >= 0)
 
953
                        ret = -EIO;
 
954
                break;
 
955
 
 
956
        default:
 
957
                if (request == PTRACE_SPARC_DETACH)
 
958
                        request = PTRACE_DETACH;
 
959
                ret = compat_ptrace_request(child, request, addr, data);
 
960
                break;
 
961
        }
 
962
 
 
963
        return ret;
 
964
}
 
965
#endif /* CONFIG_COMPAT */
 
966
 
 
967
struct fps {
 
968
        unsigned int regs[64];
 
969
        unsigned long fsr;
 
970
};
 
971
 
 
972
long arch_ptrace(struct task_struct *child, long request,
 
973
                 unsigned long addr, unsigned long data)
 
974
{
 
975
        const struct user_regset_view *view = task_user_regset_view(current);
 
976
        unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4];
 
977
        struct pt_regs __user *pregs;
 
978
        struct fps __user *fps;
 
979
        void __user *addr2p;
 
980
        int ret;
 
981
 
 
982
        pregs = (struct pt_regs __user *) addr;
 
983
        fps = (struct fps __user *) addr;
 
984
        addr2p = (void __user *) addr2;
 
985
 
 
986
        switch (request) {
 
987
        case PTRACE_PEEKUSR:
 
988
                ret = (addr != 0) ? -EIO : 0;
 
989
                break;
 
990
 
 
991
        case PTRACE_GETREGS64:
 
992
                ret = copy_regset_to_user(child, view, REGSET_GENERAL,
 
993
                                          1 * sizeof(u64),
 
994
                                          15 * sizeof(u64),
 
995
                                          &pregs->u_regs[0]);
 
996
                if (!ret) {
 
997
                        /* XXX doesn't handle 'y' register correctly XXX */
 
998
                        ret = copy_regset_to_user(child, view, REGSET_GENERAL,
 
999
                                                  32 * sizeof(u64),
 
1000
                                                  4 * sizeof(u64),
 
1001
                                                  &pregs->tstate);
 
1002
                }
 
1003
                break;
 
1004
 
 
1005
        case PTRACE_SETREGS64:
 
1006
                ret = copy_regset_from_user(child, view, REGSET_GENERAL,
 
1007
                                            1 * sizeof(u64),
 
1008
                                            15 * sizeof(u64),
 
1009
                                            &pregs->u_regs[0]);
 
1010
                if (!ret) {
 
1011
                        /* XXX doesn't handle 'y' register correctly XXX */
 
1012
                        ret = copy_regset_from_user(child, view, REGSET_GENERAL,
 
1013
                                                    32 * sizeof(u64),
 
1014
                                                    4 * sizeof(u64),
 
1015
                                                    &pregs->tstate);
 
1016
                }
 
1017
                break;
 
1018
 
 
1019
        case PTRACE_GETFPREGS64:
 
1020
                ret = copy_regset_to_user(child, view, REGSET_FP,
 
1021
                                          0 * sizeof(u64),
 
1022
                                          33 * sizeof(u64),
 
1023
                                          fps);
 
1024
                break;
 
1025
 
 
1026
        case PTRACE_SETFPREGS64:
 
1027
                ret = copy_regset_from_user(child, view, REGSET_FP,
 
1028
                                          0 * sizeof(u64),
 
1029
                                          33 * sizeof(u64),
 
1030
                                          fps);
 
1031
                break;
 
1032
 
 
1033
        case PTRACE_READTEXT:
 
1034
        case PTRACE_READDATA:
 
1035
                ret = ptrace_readdata(child, addr, addr2p, data);
 
1036
                if (ret == data)
 
1037
                        ret = 0;
 
1038
                else if (ret >= 0)
 
1039
                        ret = -EIO;
 
1040
                break;
 
1041
 
 
1042
        case PTRACE_WRITETEXT:
 
1043
        case PTRACE_WRITEDATA:
 
1044
                ret = ptrace_writedata(child, addr2p, addr, data);
 
1045
                if (ret == data)
 
1046
                        ret = 0;
 
1047
                else if (ret >= 0)
 
1048
                        ret = -EIO;
 
1049
                break;
 
1050
 
 
1051
        default:
 
1052
                if (request == PTRACE_SPARC_DETACH)
 
1053
                        request = PTRACE_DETACH;
 
1054
                ret = ptrace_request(child, request, addr, data);
 
1055
                break;
 
1056
        }
 
1057
 
 
1058
        return ret;
 
1059
}
 
1060
 
 
1061
asmlinkage int syscall_trace_enter(struct pt_regs *regs)
 
1062
{
 
1063
        int ret = 0;
 
1064
 
 
1065
        /* do the secure computing check first */
 
1066
        secure_computing(regs->u_regs[UREG_G1]);
 
1067
 
 
1068
        if (test_thread_flag(TIF_SYSCALL_TRACE))
 
1069
                ret = tracehook_report_syscall_entry(regs);
 
1070
 
 
1071
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
 
1072
                trace_sys_enter(regs, regs->u_regs[UREG_G1]);
 
1073
 
 
1074
        if (unlikely(current->audit_context) && !ret)
 
1075
                audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
 
1076
                                     AUDIT_ARCH_SPARC :
 
1077
                                     AUDIT_ARCH_SPARC64),
 
1078
                                    regs->u_regs[UREG_G1],
 
1079
                                    regs->u_regs[UREG_I0],
 
1080
                                    regs->u_regs[UREG_I1],
 
1081
                                    regs->u_regs[UREG_I2],
 
1082
                                    regs->u_regs[UREG_I3]);
 
1083
 
 
1084
        return ret;
 
1085
}
 
1086
 
 
1087
asmlinkage void syscall_trace_leave(struct pt_regs *regs)
 
1088
{
 
1089
#ifdef CONFIG_AUDITSYSCALL
 
1090
        if (unlikely(current->audit_context)) {
 
1091
                unsigned long tstate = regs->tstate;
 
1092
                int result = AUDITSC_SUCCESS;
 
1093
 
 
1094
                if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
 
1095
                        result = AUDITSC_FAILURE;
 
1096
 
 
1097
                audit_syscall_exit(result, regs->u_regs[UREG_I0]);
 
1098
        }
 
1099
#endif
 
1100
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
 
1101
                trace_sys_exit(regs, regs->u_regs[UREG_G1]);
 
1102
 
 
1103
        if (test_thread_flag(TIF_SYSCALL_TRACE))
 
1104
                tracehook_report_syscall_exit(regs, 0);
 
1105
}