source: src/linux/universal/linux-3.18/arch/mips/kernel/ptrace.c @ 31885

Last change on this file since 31885 was 31885, checked in by brainslayer, 5 weeks ago

update

File size: 18.8 KB
Line 
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License.  See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1992 Ross Biro
7 * Copyright (C) Linus Torvalds
8 * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
9 * Copyright (C) 1996 David S. Miller
10 * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
11 * Copyright (C) 1999 MIPS Technologies, Inc.
12 * Copyright (C) 2000 Ulf Carlsson
13 *
14 * At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit
15 * binaries.
16 */
17#include <linux/compiler.h>
18#include <linux/context_tracking.h>
19#include <linux/elf.h>
20#include <linux/kernel.h>
21#include <linux/sched.h>
22#include <linux/mm.h>
23#include <linux/errno.h>
24#include <linux/ptrace.h>
25#include <linux/regset.h>
26#include <linux/smp.h>
27#include <linux/security.h>
28#include <linux/tracehook.h>
29#include <linux/audit.h>
30#include <linux/seccomp.h>
31#include <linux/ftrace.h>
32
33#include <asm/byteorder.h>
34#include <asm/cpu.h>
35#include <asm/dsp.h>
36#include <asm/fpu.h>
37#include <asm/mipsregs.h>
38#include <asm/mipsmtregs.h>
39#include <asm/pgtable.h>
40#include <asm/page.h>
41#include <asm/syscall.h>
42#include <asm/uaccess.h>
43#include <asm/bootinfo.h>
44#include <asm/reg.h>
45
46#define CREATE_TRACE_POINTS
47#include <trace/events/syscalls.h>
48
49/*
50 * Called by kernel/ptrace.c when detaching..
51 *
52 * Make sure single step bits etc are not set.
53 */
54void ptrace_disable(struct task_struct *child)
55{
56        /* Don't load the watchpoint registers for the ex-child. */
57        clear_tsk_thread_flag(child, TIF_LOAD_WATCH);
58}
59
60/*
61 * Read a general register set.  We always use the 64-bit format, even
62 * for 32-bit kernels and for 32-bit processes on a 64-bit kernel.
63 * Registers are sign extended to fill the available space.
64 */
65int ptrace_getregs(struct task_struct *child, struct user_pt_regs __user *data)
66{
67        struct pt_regs *regs;
68        int i;
69
70        if (!access_ok(VERIFY_WRITE, data, 38 * 8))
71                return -EIO;
72
73        regs = task_pt_regs(child);
74
75        for (i = 0; i < 32; i++)
76                __put_user((long)regs->regs[i], (__s64 __user *)&data->regs[i]);
77        __put_user((long)regs->lo, (__s64 __user *)&data->lo);
78        __put_user((long)regs->hi, (__s64 __user *)&data->hi);
79        __put_user((long)regs->cp0_epc, (__s64 __user *)&data->cp0_epc);
80        __put_user((long)regs->cp0_badvaddr, (__s64 __user *)&data->cp0_badvaddr);
81        __put_user((long)regs->cp0_status, (__s64 __user *)&data->cp0_status);
82        __put_user((long)regs->cp0_cause, (__s64 __user *)&data->cp0_cause);
83
84        return 0;
85}
86
87/*
88 * Write a general register set.  As for PTRACE_GETREGS, we always use
89 * the 64-bit format.  On a 32-bit kernel only the lower order half
90 * (according to endianness) will be used.
91 */
92int ptrace_setregs(struct task_struct *child, struct user_pt_regs __user *data)
93{
94        struct pt_regs *regs;
95        int i;
96
97        if (!access_ok(VERIFY_READ, data, 38 * 8))
98                return -EIO;
99
100        regs = task_pt_regs(child);
101
102        for (i = 0; i < 32; i++)
103                __get_user(regs->regs[i], (__s64 __user *)&data->regs[i]);
104        __get_user(regs->lo, (__s64 __user *)&data->lo);
105        __get_user(regs->hi, (__s64 __user *)&data->hi);
106        __get_user(regs->cp0_epc, (__s64 __user *)&data->cp0_epc);
107
108        /* badvaddr, status, and cause may not be written.  */
109
110        return 0;
111}
112
113int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
114{
115        int i;
116
117        if (!access_ok(VERIFY_WRITE, data, 33 * 8))
118                return -EIO;
119
120        if (tsk_used_math(child)) {
121                union fpureg *fregs = get_fpu_regs(child);
122                for (i = 0; i < 32; i++)
123                        __put_user(get_fpr64(&fregs[i], 0),
124                                   i + (__u64 __user *)data);
125        } else {
126                for (i = 0; i < 32; i++)
127                        __put_user((__u64) -1, i + (__u64 __user *) data);
128        }
129
130        __put_user(child->thread.fpu.fcr31, data + 64);
131        __put_user(boot_cpu_data.fpu_id, data + 65);
132
133        return 0;
134}
135
136int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
137{
138        union fpureg *fregs;
139        u64 fpr_val;
140        int i;
141
142        if (!access_ok(VERIFY_READ, data, 33 * 8))
143                return -EIO;
144
145        fregs = get_fpu_regs(child);
146
147        for (i = 0; i < 32; i++) {
148                __get_user(fpr_val, i + (__u64 __user *)data);
149                set_fpr64(&fregs[i], 0, fpr_val);
150        }
151
152        __get_user(child->thread.fpu.fcr31, data + 64);
153        child->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
154
155        /* FIR may not be written.  */
156
157        return 0;
158}
159
160int ptrace_get_watch_regs(struct task_struct *child,
161                          struct pt_watch_regs __user *addr)
162{
163        enum pt_watch_style style;
164        int i;
165
166        if (!cpu_has_watch || boot_cpu_data.watch_reg_use_cnt == 0)
167                return -EIO;
168        if (!access_ok(VERIFY_WRITE, addr, sizeof(struct pt_watch_regs)))
169                return -EIO;
170
171#ifdef CONFIG_32BIT
172        style = pt_watch_style_mips32;
173#define WATCH_STYLE mips32
174#else
175        style = pt_watch_style_mips64;
176#define WATCH_STYLE mips64
177#endif
178
179        __put_user(style, &addr->style);
180        __put_user(boot_cpu_data.watch_reg_use_cnt,
181                   &addr->WATCH_STYLE.num_valid);
182        for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) {
183                __put_user(child->thread.watch.mips3264.watchlo[i],
184                           &addr->WATCH_STYLE.watchlo[i]);
185                __put_user(child->thread.watch.mips3264.watchhi[i] & 0xfff,
186                           &addr->WATCH_STYLE.watchhi[i]);
187                __put_user(boot_cpu_data.watch_reg_masks[i],
188                           &addr->WATCH_STYLE.watch_masks[i]);
189        }
190        for (; i < 8; i++) {
191                __put_user(0, &addr->WATCH_STYLE.watchlo[i]);
192                __put_user(0, &addr->WATCH_STYLE.watchhi[i]);
193                __put_user(0, &addr->WATCH_STYLE.watch_masks[i]);
194        }
195
196        return 0;
197}
198
199int ptrace_set_watch_regs(struct task_struct *child,
200                          struct pt_watch_regs __user *addr)
201{
202        int i;
203        int watch_active = 0;
204        unsigned long lt[NUM_WATCH_REGS];
205        u16 ht[NUM_WATCH_REGS];
206
207        if (!cpu_has_watch || boot_cpu_data.watch_reg_use_cnt == 0)
208                return -EIO;
209        if (!access_ok(VERIFY_READ, addr, sizeof(struct pt_watch_regs)))
210                return -EIO;
211        /* Check the values. */
212        for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) {
213                __get_user(lt[i], &addr->WATCH_STYLE.watchlo[i]);
214#ifdef CONFIG_32BIT
215                if (lt[i] & __UA_LIMIT)
216                        return -EINVAL;
217#else
218                if (test_tsk_thread_flag(child, TIF_32BIT_ADDR)) {
219                        if (lt[i] & 0xffffffff80000000UL)
220                                return -EINVAL;
221                } else {
222                        if (lt[i] & __UA_LIMIT)
223                                return -EINVAL;
224                }
225#endif
226                __get_user(ht[i], &addr->WATCH_STYLE.watchhi[i]);
227                if (ht[i] & ~0xff8)
228                        return -EINVAL;
229        }
230        /* Install them. */
231        for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) {
232                if (lt[i] & 7)
233                        watch_active = 1;
234                child->thread.watch.mips3264.watchlo[i] = lt[i];
235                /* Set the G bit. */
236                child->thread.watch.mips3264.watchhi[i] = ht[i];
237        }
238
239        if (watch_active)
240                set_tsk_thread_flag(child, TIF_LOAD_WATCH);
241        else
242                clear_tsk_thread_flag(child, TIF_LOAD_WATCH);
243
244        return 0;
245}
246
247/* regset get/set implementations */
248
249#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
250
251static int gpr32_get(struct task_struct *target,
252                     const struct user_regset *regset,
253                     unsigned int pos, unsigned int count,
254                     void *kbuf, void __user *ubuf)
255{
256        struct pt_regs *regs = task_pt_regs(target);
257        u32 uregs[ELF_NGREG] = {};
258        unsigned i;
259
260        for (i = MIPS32_EF_R1; i <= MIPS32_EF_R31; i++) {
261                /* k0/k1 are copied as zero. */
262                if (i == MIPS32_EF_R26 || i == MIPS32_EF_R27)
263                        continue;
264
265                uregs[i] = regs->regs[i - MIPS32_EF_R0];
266        }
267
268        uregs[MIPS32_EF_LO] = regs->lo;
269        uregs[MIPS32_EF_HI] = regs->hi;
270        uregs[MIPS32_EF_CP0_EPC] = regs->cp0_epc;
271        uregs[MIPS32_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
272        uregs[MIPS32_EF_CP0_STATUS] = regs->cp0_status;
273        uregs[MIPS32_EF_CP0_CAUSE] = regs->cp0_cause;
274
275        return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
276                                   sizeof(uregs));
277}
278
279static int gpr32_set(struct task_struct *target,
280                     const struct user_regset *regset,
281                     unsigned int pos, unsigned int count,
282                     const void *kbuf, const void __user *ubuf)
283{
284        struct pt_regs *regs = task_pt_regs(target);
285        u32 uregs[ELF_NGREG];
286        unsigned start, num_regs, i;
287        int err;
288
289        start = pos / sizeof(u32);
290        num_regs = count / sizeof(u32);
291
292        if (start + num_regs > ELF_NGREG)
293                return -EIO;
294
295        err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
296                                 sizeof(uregs));
297        if (err)
298                return err;
299
300        for (i = start; i < num_regs; i++) {
301                /*
302                 * Cast all values to signed here so that if this is a 64-bit
303                 * kernel, the supplied 32-bit values will be sign extended.
304                 */
305                switch (i) {
306                case MIPS32_EF_R1 ... MIPS32_EF_R25:
307                        /* k0/k1 are ignored. */
308                case MIPS32_EF_R28 ... MIPS32_EF_R31:
309                        regs->regs[i - MIPS32_EF_R0] = (s32)uregs[i];
310                        break;
311                case MIPS32_EF_LO:
312                        regs->lo = (s32)uregs[i];
313                        break;
314                case MIPS32_EF_HI:
315                        regs->hi = (s32)uregs[i];
316                        break;
317                case MIPS32_EF_CP0_EPC:
318                        regs->cp0_epc = (s32)uregs[i];
319                        break;
320                }
321        }
322
323        return 0;
324}
325
326#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
327
328#ifdef CONFIG_64BIT
329
330static int gpr64_get(struct task_struct *target,
331                     const struct user_regset *regset,
332                     unsigned int pos, unsigned int count,
333                     void *kbuf, void __user *ubuf)
334{
335        struct pt_regs *regs = task_pt_regs(target);
336        u64 uregs[ELF_NGREG] = {};
337        unsigned i;
338
339        for (i = MIPS64_EF_R1; i <= MIPS64_EF_R31; i++) {
340                /* k0/k1 are copied as zero. */
341                if (i == MIPS64_EF_R26 || i == MIPS64_EF_R27)
342                        continue;
343
344                uregs[i] = regs->regs[i - MIPS64_EF_R0];
345        }
346
347        uregs[MIPS64_EF_LO] = regs->lo;
348        uregs[MIPS64_EF_HI] = regs->hi;
349        uregs[MIPS64_EF_CP0_EPC] = regs->cp0_epc;
350        uregs[MIPS64_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
351        uregs[MIPS64_EF_CP0_STATUS] = regs->cp0_status;
352        uregs[MIPS64_EF_CP0_CAUSE] = regs->cp0_cause;
353
354        return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
355                                   sizeof(uregs));
356}
357
358static int gpr64_set(struct task_struct *target,
359                     const struct user_regset *regset,
360                     unsigned int pos, unsigned int count,
361                     const void *kbuf, const void __user *ubuf)
362{
363        struct pt_regs *regs = task_pt_regs(target);
364        u64 uregs[ELF_NGREG];
365        unsigned start, num_regs, i;
366        int err;
367
368        start = pos / sizeof(u64);
369        num_regs = count / sizeof(u64);
370
371        if (start + num_regs > ELF_NGREG)
372                return -EIO;
373
374        err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
375                                 sizeof(uregs));
376        if (err)
377                return err;
378
379        for (i = start; i < num_regs; i++) {
380                switch (i) {
381                case MIPS64_EF_R1 ... MIPS64_EF_R25:
382                        /* k0/k1 are ignored. */
383                case MIPS64_EF_R28 ... MIPS64_EF_R31:
384                        regs->regs[i - MIPS64_EF_R0] = uregs[i];
385                        break;
386                case MIPS64_EF_LO:
387                        regs->lo = uregs[i];
388                        break;
389                case MIPS64_EF_HI:
390                        regs->hi = uregs[i];
391                        break;
392                case MIPS64_EF_CP0_EPC:
393                        regs->cp0_epc = uregs[i];
394                        break;
395                }
396        }
397
398        return 0;
399}
400
401#endif /* CONFIG_64BIT */
402
403static int fpr_get(struct task_struct *target,
404                   const struct user_regset *regset,
405                   unsigned int pos, unsigned int count,
406                   void *kbuf, void __user *ubuf)
407{
408        unsigned i;
409        int err;
410        u64 fpr_val;
411
412        /* XXX fcr31  */
413
414        if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
415                return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
416                                           &target->thread.fpu,
417                                           0, sizeof(elf_fpregset_t));
418
419        for (i = 0; i < NUM_FPU_REGS; i++) {
420                fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0);
421                err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
422                                          &fpr_val, i * sizeof(elf_fpreg_t),
423                                          (i + 1) * sizeof(elf_fpreg_t));
424                if (err)
425                        return err;
426        }
427
428        return 0;
429}
430
431static int fpr_set(struct task_struct *target,
432                   const struct user_regset *regset,
433                   unsigned int pos, unsigned int count,
434                   const void *kbuf, const void __user *ubuf)
435{
436        unsigned i;
437        int err;
438        u64 fpr_val;
439
440        /* XXX fcr31  */
441
442        if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
443                return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
444                                          &target->thread.fpu,
445                                          0, sizeof(elf_fpregset_t));
446
447        BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t));
448        for (i = 0; i < NUM_FPU_REGS && count >= sizeof(elf_fpreg_t); i++) {
449                err = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
450                                         &fpr_val, i * sizeof(elf_fpreg_t),
451                                         (i + 1) * sizeof(elf_fpreg_t));
452                if (err)
453                        return err;
454                set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val);
455        }
456
457        return 0;
458}
459
460enum mips_regset {
461        REGSET_GPR,
462        REGSET_FPR,
463};
464
465#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
466
467static const struct user_regset mips_regsets[] = {
468        [REGSET_GPR] = {
469                .core_note_type = NT_PRSTATUS,
470                .n              = ELF_NGREG,
471                .size           = sizeof(unsigned int),
472                .align          = sizeof(unsigned int),
473                .get            = gpr32_get,
474                .set            = gpr32_set,
475        },
476        [REGSET_FPR] = {
477                .core_note_type = NT_PRFPREG,
478                .n              = ELF_NFPREG,
479                .size           = sizeof(elf_fpreg_t),
480                .align          = sizeof(elf_fpreg_t),
481                .get            = fpr_get,
482                .set            = fpr_set,
483        },
484};
485
486static const struct user_regset_view user_mips_view = {
487        .name           = "mips",
488        .e_machine      = ELF_ARCH,
489        .ei_osabi       = ELF_OSABI,
490        .regsets        = mips_regsets,
491        .n              = ARRAY_SIZE(mips_regsets),
492};
493
494#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
495
496#ifdef CONFIG_64BIT
497
498static const struct user_regset mips64_regsets[] = {
499        [REGSET_GPR] = {
500                .core_note_type = NT_PRSTATUS,
501                .n              = ELF_NGREG,
502                .size           = sizeof(unsigned long),
503                .align          = sizeof(unsigned long),
504                .get            = gpr64_get,
505                .set            = gpr64_set,
506        },
507        [REGSET_FPR] = {
508                .core_note_type = NT_PRFPREG,
509                .n              = ELF_NFPREG,
510                .size           = sizeof(elf_fpreg_t),
511                .align          = sizeof(elf_fpreg_t),
512                .get            = fpr_get,
513                .set            = fpr_set,
514        },
515};
516
517static const struct user_regset_view user_mips64_view = {
518        .name           = "mips64",
519        .e_machine      = ELF_ARCH,
520        .ei_osabi       = ELF_OSABI,
521        .regsets        = mips64_regsets,
522        .n              = ARRAY_SIZE(mips64_regsets),
523};
524
525#endif /* CONFIG_64BIT */
526
527const struct user_regset_view *task_user_regset_view(struct task_struct *task)
528{
529#ifdef CONFIG_32BIT
530        return &user_mips_view;
531#else
532#ifdef CONFIG_MIPS32_O32
533        if (test_tsk_thread_flag(task, TIF_32BIT_REGS))
534                return &user_mips_view;
535#endif
536        return &user_mips64_view;
537#endif
538}
539
540long arch_ptrace(struct task_struct *child, long request,
541                 unsigned long addr, unsigned long data)
542{
543        int ret;
544        void __user *addrp = (void __user *) addr;
545        void __user *datavp = (void __user *) data;
546        unsigned long __user *datalp = (void __user *) data;
547
548        switch (request) {
549        /* when I and D space are separate, these will need to be fixed. */
550        case PTRACE_PEEKTEXT: /* read word at location addr. */
551        case PTRACE_PEEKDATA:
552                ret = generic_ptrace_peekdata(child, addr, data);
553                break;
554
555        /* Read the word at location addr in the USER area. */
556        case PTRACE_PEEKUSR: {
557                struct pt_regs *regs;
558                union fpureg *fregs;
559                unsigned long tmp = 0;
560
561                regs = task_pt_regs(child);
562                ret = 0;  /* Default return value. */
563
564                switch (addr) {
565                case 0 ... 31:
566                        tmp = regs->regs[addr];
567                        break;
568                case FPR_BASE ... FPR_BASE + 31:
569                        if (!tsk_used_math(child)) {
570                                /* FP not yet used */
571                                tmp = -1;
572                                break;
573                        }
574                        fregs = get_fpu_regs(child);
575
576#ifdef CONFIG_32BIT
577                        if (test_thread_flag(TIF_32BIT_FPREGS)) {
578                                /*
579                                 * The odd registers are actually the high
580                                 * order bits of the values stored in the even
581                                 * registers - unless we're using r2k_switch.S.
582                                 */
583                                tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
584                                                addr & 1);
585                                break;
586                        }
587#endif
588                        tmp = get_fpr32(&fregs[addr - FPR_BASE], 0);
589                        break;
590                case PC:
591                        tmp = regs->cp0_epc;
592                        break;
593                case CAUSE:
594                        tmp = regs->cp0_cause;
595                        break;
596                case BADVADDR:
597                        tmp = regs->cp0_badvaddr;
598                        break;
599                case MMHI:
600                        tmp = regs->hi;
601                        break;
602                case MMLO:
603                        tmp = regs->lo;
604                        break;
605#ifdef CONFIG_CPU_HAS_SMARTMIPS
606                case ACX:
607                        tmp = regs->acx;
608                        break;
609#endif
610                case FPC_CSR:
611                        tmp = child->thread.fpu.fcr31;
612                        break;
613                case FPC_EIR:
614                        /* implementation / version register */
615                        tmp = boot_cpu_data.fpu_id;
616                        break;
617                case DSP_BASE ... DSP_BASE + 5: {
618                        dspreg_t *dregs;
619
620                        if (!cpu_has_dsp) {
621                                tmp = 0;
622                                ret = -EIO;
623                                goto out;
624                        }
625                        dregs = __get_dsp_regs(child);
626                        tmp = (unsigned long) (dregs[addr - DSP_BASE]);
627                        break;
628                }
629                case DSP_CONTROL:
630                        if (!cpu_has_dsp) {
631                                tmp = 0;
632                                ret = -EIO;
633                                goto out;
634                        }
635                        tmp = child->thread.dsp.dspcontrol;
636                        break;
637                default:
638                        tmp = 0;
639                        ret = -EIO;
640                        goto out;
641                }
642                ret = put_user(tmp, datalp);
643                break;
644        }
645
646        /* when I and D space are separate, this will have to be fixed. */
647        case PTRACE_POKETEXT: /* write the word at location addr. */
648        case PTRACE_POKEDATA:
649                ret = generic_ptrace_pokedata(child, addr, data);
650                break;
651
652        case PTRACE_POKEUSR: {
653                struct pt_regs *regs;
654                ret = 0;
655                regs = task_pt_regs(child);
656
657                switch (addr) {
658                case 0 ... 31:
659                        regs->regs[addr] = data;
660                        break;
661                case FPR_BASE ... FPR_BASE + 31: {
662                        union fpureg *fregs = get_fpu_regs(child);
663
664                        if (!tsk_used_math(child)) {
665                                /* FP not yet used  */
666                                memset(&child->thread.fpu, ~0,
667                                       sizeof(child->thread.fpu));
668                                child->thread.fpu.fcr31 = 0;
669                        }
670#ifdef CONFIG_32BIT
671                        if (test_thread_flag(TIF_32BIT_FPREGS)) {
672                                /*
673                                 * The odd registers are actually the high
674                                 * order bits of the values stored in the even
675                                 * registers - unless we're using r2k_switch.S.
676                                 */
677                                set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
678                                          addr & 1, data);
679                                break;
680                        }
681#endif
682                        set_fpr64(&fregs[addr - FPR_BASE], 0, data);
683                        break;
684                }
685                case PC:
686                        regs->cp0_epc = data;
687                        break;
688                case MMHI:
689                        regs->hi = data;
690                        break;
691                case MMLO:
692                        regs->lo = data;
693                        break;
694#ifdef CONFIG_CPU_HAS_SMARTMIPS
695                case ACX:
696                        regs->acx = data;
697                        break;
698#endif
699                case FPC_CSR:
700                        child->thread.fpu.fcr31 = data & ~FPU_CSR_ALL_X;
701                        break;
702                case DSP_BASE ... DSP_BASE + 5: {
703                        dspreg_t *dregs;
704
705                        if (!cpu_has_dsp) {
706                                ret = -EIO;
707                                break;
708                        }
709
710                        dregs = __get_dsp_regs(child);
711                        dregs[addr - DSP_BASE] = data;
712                        break;
713                }
714                case DSP_CONTROL:
715                        if (!cpu_has_dsp) {
716                                ret = -EIO;
717                                break;
718                        }
719                        child->thread.dsp.dspcontrol = data;
720                        break;
721                default:
722                        /* The rest are not allowed. */
723                        ret = -EIO;
724                        break;
725                }
726                break;
727                }
728
729        case PTRACE_GETREGS:
730                ret = ptrace_getregs(child, datavp);
731                break;
732
733        case PTRACE_SETREGS:
734                ret = ptrace_setregs(child, datavp);
735                break;
736
737        case PTRACE_GETFPREGS:
738                ret = ptrace_getfpregs(child, datavp);
739                break;
740
741        case PTRACE_SETFPREGS:
742                ret = ptrace_setfpregs(child, datavp);
743                break;
744
745        case PTRACE_GET_THREAD_AREA:
746                ret = put_user(task_thread_info(child)->tp_value, datalp);
747                break;
748
749        case PTRACE_GET_WATCH_REGS:
750                ret = ptrace_get_watch_regs(child, addrp);
751                break;
752
753        case PTRACE_SET_WATCH_REGS:
754                ret = ptrace_set_watch_regs(child, addrp);
755                break;
756
757        default:
758                ret = ptrace_request(child, request, addr, data);
759                break;
760        }
761 out:
762        return ret;
763}
764
765/*
766 * Notification of system call entry/exit
767 * - triggered by current->work.syscall_trace
768 */
769asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall)
770{
771        long ret = 0;
772        user_exit();
773
774        if (secure_computing() == -1)
775                return -1;
776
777        if (test_thread_flag(TIF_SYSCALL_TRACE) &&
778            tracehook_report_syscall_entry(regs))
779                ret = -1;
780
781        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
782                trace_sys_enter(regs, regs->regs[2]);
783
784        audit_syscall_entry(syscall, regs->regs[4], regs->regs[5],
785                            regs->regs[6], regs->regs[7]);
786        return syscall;
787}
788
789/*
790 * Notification of system call entry/exit
791 * - triggered by current->work.syscall_trace
792 */
793asmlinkage void syscall_trace_leave(struct pt_regs *regs)
794{
795        /*
796         * We may come here right after calling schedule_user()
797         * or do_notify_resume(), in which case we can be in RCU
798         * user mode.
799         */
800        user_exit();
801
802        audit_syscall_exit(regs);
803
804        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
805                trace_sys_exit(regs, regs->regs[2]);
806
807        if (test_thread_flag(TIF_SYSCALL_TRACE))
808                tracehook_report_syscall_exit(regs, 0);
809
810        user_enter();
811}
Note: See TracBrowser for help on using the repository browser.