blob: 7da6e324dd354a77991c4fe2dd998c07b998d956 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/compiler.h>
Ralf Baechlec3fc5cd2013-05-29 01:07:19 +020018#include <linux/context_tracking.h>
Ralf Baechle7aeb7532012-08-02 14:44:11 +020019#include <linux/elf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <linux/kernel.h>
21#include <linux/sched.h>
22#include <linux/mm.h>
23#include <linux/errno.h>
24#include <linux/ptrace.h>
Ralf Baechle7aeb7532012-08-02 14:44:11 +020025#include <linux/regset.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/security.h>
Ralf Baechlebc3d22c2012-07-17 19:43:58 +020028#include <linux/tracehook.h>
Ralf Baechle293c5bd2007-07-25 16:19:33 +010029#include <linux/audit.h>
30#include <linux/seccomp.h>
Ralf Baechle1d7bf992013-09-06 20:24:48 +020031#include <linux/ftrace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
Ralf Baechlef8280c82005-05-19 12:08:04 +000033#include <asm/byteorder.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <asm/cpu.h>
Ralf Baechlee50c0a82005-05-31 11:49:19 +000035#include <asm/dsp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/fpu.h>
37#include <asm/mipsregs.h>
Ralf Baechle101b3532005-10-06 17:39:32 +010038#include <asm/mipsmtregs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <asm/pgtable.h>
40#include <asm/page.h>
Ralf Baechlebec9b2b2012-09-26 20:16:47 +020041#include <asm/syscall.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <asm/uaccess.h>
43#include <asm/bootinfo.h>
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -040044#include <asm/reg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
Ralf Baechle1d7bf992013-09-06 20:24:48 +020046#define CREATE_TRACE_POINTS
47#include <trace/events/syscalls.h>
48
Paul Burtonac9ad832015-01-30 12:09:36 +000049static void init_fp_ctx(struct task_struct *target)
50{
51 /* If FP has been used then the target already has context */
52 if (tsk_used_math(target))
53 return;
54
55 /* Begin with data registers set to all 1s... */
56 memset(&target->thread.fpu.fpr, ~0, sizeof(target->thread.fpu.fpr));
57
58 /* ...and FCSR zeroed */
59 target->thread.fpu.fcr31 = 0;
60
61 /*
62 * Record that the target has "used" math, such that the context
63 * just initialised, and any modifications made by the caller,
64 * aren't discarded.
65 */
66 set_stopped_child_used_math(target);
67}
68
Linus Torvalds1da177e2005-04-16 15:20:36 -070069/*
70 * Called by kernel/ptrace.c when detaching..
71 *
72 * Make sure single step bits etc are not set.
73 */
74void ptrace_disable(struct task_struct *child)
75{
David Daney0926bf92008-09-23 00:11:26 -070076 /* Don't load the watchpoint registers for the ex-child. */
77 clear_tsk_thread_flag(child, TIF_LOAD_WATCH);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078}
79
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -040080/*
Ralf Baechle70342282013-01-22 12:59:30 +010081 * Read a general register set. We always use the 64-bit format, even
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -040082 * for 32-bit kernels and for 32-bit processes on a 64-bit kernel.
83 * Registers are sign extended to fill the available space.
84 */
Alex Smitha79ebea2014-07-23 14:40:13 +010085int ptrace_getregs(struct task_struct *child, struct user_pt_regs __user *data)
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -040086{
87 struct pt_regs *regs;
88 int i;
89
90 if (!access_ok(VERIFY_WRITE, data, 38 * 8))
91 return -EIO;
92
Al Viro40bc9c62006-01-12 01:06:07 -080093 regs = task_pt_regs(child);
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -040094
95 for (i = 0; i < 32; i++)
Alex Smitha79ebea2014-07-23 14:40:13 +010096 __put_user((long)regs->regs[i], (__s64 __user *)&data->regs[i]);
97 __put_user((long)regs->lo, (__s64 __user *)&data->lo);
98 __put_user((long)regs->hi, (__s64 __user *)&data->hi);
99 __put_user((long)regs->cp0_epc, (__s64 __user *)&data->cp0_epc);
100 __put_user((long)regs->cp0_badvaddr, (__s64 __user *)&data->cp0_badvaddr);
101 __put_user((long)regs->cp0_status, (__s64 __user *)&data->cp0_status);
102 __put_user((long)regs->cp0_cause, (__s64 __user *)&data->cp0_cause);
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400103
104 return 0;
105}
106
107/*
108 * Write a general register set. As for PTRACE_GETREGS, we always use
109 * the 64-bit format. On a 32-bit kernel only the lower order half
110 * (according to endianness) will be used.
111 */
Alex Smitha79ebea2014-07-23 14:40:13 +0100112int ptrace_setregs(struct task_struct *child, struct user_pt_regs __user *data)
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400113{
114 struct pt_regs *regs;
115 int i;
116
117 if (!access_ok(VERIFY_READ, data, 38 * 8))
118 return -EIO;
119
Al Viro40bc9c62006-01-12 01:06:07 -0800120 regs = task_pt_regs(child);
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400121
122 for (i = 0; i < 32; i++)
Alex Smitha79ebea2014-07-23 14:40:13 +0100123 __get_user(regs->regs[i], (__s64 __user *)&data->regs[i]);
124 __get_user(regs->lo, (__s64 __user *)&data->lo);
125 __get_user(regs->hi, (__s64 __user *)&data->hi);
126 __get_user(regs->cp0_epc, (__s64 __user *)&data->cp0_epc);
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400127
128 /* badvaddr, status, and cause may not be written. */
129
130 return 0;
131}
132
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100133int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400134{
135 int i;
136
137 if (!access_ok(VERIFY_WRITE, data, 33 * 8))
138 return -EIO;
139
140 if (tsk_used_math(child)) {
Paul Burtonbbd426f2014-02-13 11:26:41 +0000141 union fpureg *fregs = get_fpu_regs(child);
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400142 for (i = 0; i < 32; i++)
Paul Burtonbbd426f2014-02-13 11:26:41 +0000143 __put_user(get_fpr64(&fregs[i], 0),
144 i + (__u64 __user *)data);
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400145 } else {
146 for (i = 0; i < 32; i++)
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100147 __put_user((__u64) -1, i + (__u64 __user *) data);
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400148 }
149
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100150 __put_user(child->thread.fpu.fcr31, data + 64);
Alex Smith656ff9b2014-07-23 14:40:06 +0100151 __put_user(boot_cpu_data.fpu_id, data + 65);
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400152
153 return 0;
154}
155
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100156int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400157{
Paul Burtonbbd426f2014-02-13 11:26:41 +0000158 union fpureg *fregs;
159 u64 fpr_val;
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400160 int i;
161
162 if (!access_ok(VERIFY_READ, data, 33 * 8))
163 return -EIO;
164
Paul Burtonac9ad832015-01-30 12:09:36 +0000165 init_fp_ctx(child);
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400166 fregs = get_fpu_regs(child);
167
Paul Burtonbbd426f2014-02-13 11:26:41 +0000168 for (i = 0; i < 32; i++) {
169 __get_user(fpr_val, i + (__u64 __user *)data);
170 set_fpr64(&fregs[i], 0, fpr_val);
171 }
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400172
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100173 __get_user(child->thread.fpu.fcr31, data + 64);
Paul Burtonb1442d32014-07-22 14:21:21 +0100174 child->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400175
176 /* FIR may not be written. */
177
178 return 0;
179}
180
David Daney0926bf92008-09-23 00:11:26 -0700181int ptrace_get_watch_regs(struct task_struct *child,
182 struct pt_watch_regs __user *addr)
183{
184 enum pt_watch_style style;
185 int i;
186
Alex Smith57c7ea52014-05-01 12:51:19 +0100187 if (!cpu_has_watch || boot_cpu_data.watch_reg_use_cnt == 0)
David Daney0926bf92008-09-23 00:11:26 -0700188 return -EIO;
189 if (!access_ok(VERIFY_WRITE, addr, sizeof(struct pt_watch_regs)))
190 return -EIO;
191
192#ifdef CONFIG_32BIT
193 style = pt_watch_style_mips32;
194#define WATCH_STYLE mips32
195#else
196 style = pt_watch_style_mips64;
197#define WATCH_STYLE mips64
198#endif
199
200 __put_user(style, &addr->style);
Alex Smith57c7ea52014-05-01 12:51:19 +0100201 __put_user(boot_cpu_data.watch_reg_use_cnt,
David Daney0926bf92008-09-23 00:11:26 -0700202 &addr->WATCH_STYLE.num_valid);
Alex Smith57c7ea52014-05-01 12:51:19 +0100203 for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) {
David Daney0926bf92008-09-23 00:11:26 -0700204 __put_user(child->thread.watch.mips3264.watchlo[i],
205 &addr->WATCH_STYLE.watchlo[i]);
206 __put_user(child->thread.watch.mips3264.watchhi[i] & 0xfff,
207 &addr->WATCH_STYLE.watchhi[i]);
Alex Smith57c7ea52014-05-01 12:51:19 +0100208 __put_user(boot_cpu_data.watch_reg_masks[i],
David Daney0926bf92008-09-23 00:11:26 -0700209 &addr->WATCH_STYLE.watch_masks[i]);
210 }
211 for (; i < 8; i++) {
212 __put_user(0, &addr->WATCH_STYLE.watchlo[i]);
213 __put_user(0, &addr->WATCH_STYLE.watchhi[i]);
214 __put_user(0, &addr->WATCH_STYLE.watch_masks[i]);
215 }
216
217 return 0;
218}
219
220int ptrace_set_watch_regs(struct task_struct *child,
221 struct pt_watch_regs __user *addr)
222{
223 int i;
224 int watch_active = 0;
225 unsigned long lt[NUM_WATCH_REGS];
226 u16 ht[NUM_WATCH_REGS];
227
Alex Smith57c7ea52014-05-01 12:51:19 +0100228 if (!cpu_has_watch || boot_cpu_data.watch_reg_use_cnt == 0)
David Daney0926bf92008-09-23 00:11:26 -0700229 return -EIO;
230 if (!access_ok(VERIFY_READ, addr, sizeof(struct pt_watch_regs)))
231 return -EIO;
232 /* Check the values. */
Alex Smith57c7ea52014-05-01 12:51:19 +0100233 for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) {
David Daney0926bf92008-09-23 00:11:26 -0700234 __get_user(lt[i], &addr->WATCH_STYLE.watchlo[i]);
235#ifdef CONFIG_32BIT
236 if (lt[i] & __UA_LIMIT)
237 return -EINVAL;
238#else
239 if (test_tsk_thread_flag(child, TIF_32BIT_ADDR)) {
240 if (lt[i] & 0xffffffff80000000UL)
241 return -EINVAL;
242 } else {
243 if (lt[i] & __UA_LIMIT)
244 return -EINVAL;
245 }
246#endif
247 __get_user(ht[i], &addr->WATCH_STYLE.watchhi[i]);
248 if (ht[i] & ~0xff8)
249 return -EINVAL;
250 }
251 /* Install them. */
Alex Smith57c7ea52014-05-01 12:51:19 +0100252 for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) {
David Daney0926bf92008-09-23 00:11:26 -0700253 if (lt[i] & 7)
254 watch_active = 1;
255 child->thread.watch.mips3264.watchlo[i] = lt[i];
256 /* Set the G bit. */
257 child->thread.watch.mips3264.watchhi[i] = ht[i];
258 }
259
260 if (watch_active)
261 set_tsk_thread_flag(child, TIF_LOAD_WATCH);
262 else
263 clear_tsk_thread_flag(child, TIF_LOAD_WATCH);
264
265 return 0;
266}
267
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200268/* regset get/set implementations */
269
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100270#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
271
272static int gpr32_get(struct task_struct *target,
273 const struct user_regset *regset,
274 unsigned int pos, unsigned int count,
275 void *kbuf, void __user *ubuf)
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200276{
277 struct pt_regs *regs = task_pt_regs(target);
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100278 u32 uregs[ELF_NGREG] = {};
279 unsigned i;
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200280
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100281 for (i = MIPS32_EF_R1; i <= MIPS32_EF_R31; i++) {
282 /* k0/k1 are copied as zero. */
283 if (i == MIPS32_EF_R26 || i == MIPS32_EF_R27)
284 continue;
285
286 uregs[i] = regs->regs[i - MIPS32_EF_R0];
287 }
288
289 uregs[MIPS32_EF_LO] = regs->lo;
290 uregs[MIPS32_EF_HI] = regs->hi;
291 uregs[MIPS32_EF_CP0_EPC] = regs->cp0_epc;
292 uregs[MIPS32_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
293 uregs[MIPS32_EF_CP0_STATUS] = regs->cp0_status;
294 uregs[MIPS32_EF_CP0_CAUSE] = regs->cp0_cause;
295
296 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
297 sizeof(uregs));
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200298}
299
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100300static int gpr32_set(struct task_struct *target,
301 const struct user_regset *regset,
302 unsigned int pos, unsigned int count,
303 const void *kbuf, const void __user *ubuf)
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200304{
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100305 struct pt_regs *regs = task_pt_regs(target);
306 u32 uregs[ELF_NGREG];
307 unsigned start, num_regs, i;
308 int err;
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200309
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100310 start = pos / sizeof(u32);
311 num_regs = count / sizeof(u32);
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200312
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100313 if (start + num_regs > ELF_NGREG)
314 return -EIO;
315
316 err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
317 sizeof(uregs));
318 if (err)
319 return err;
320
321 for (i = start; i < num_regs; i++) {
322 /*
323 * Cast all values to signed here so that if this is a 64-bit
324 * kernel, the supplied 32-bit values will be sign extended.
325 */
326 switch (i) {
327 case MIPS32_EF_R1 ... MIPS32_EF_R25:
328 /* k0/k1 are ignored. */
329 case MIPS32_EF_R28 ... MIPS32_EF_R31:
330 regs->regs[i - MIPS32_EF_R0] = (s32)uregs[i];
331 break;
332 case MIPS32_EF_LO:
333 regs->lo = (s32)uregs[i];
334 break;
335 case MIPS32_EF_HI:
336 regs->hi = (s32)uregs[i];
337 break;
338 case MIPS32_EF_CP0_EPC:
339 regs->cp0_epc = (s32)uregs[i];
340 break;
341 }
342 }
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200343
344 return 0;
345}
346
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100347#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
348
349#ifdef CONFIG_64BIT
350
351static int gpr64_get(struct task_struct *target,
352 const struct user_regset *regset,
353 unsigned int pos, unsigned int count,
354 void *kbuf, void __user *ubuf)
355{
356 struct pt_regs *regs = task_pt_regs(target);
357 u64 uregs[ELF_NGREG] = {};
358 unsigned i;
359
360 for (i = MIPS64_EF_R1; i <= MIPS64_EF_R31; i++) {
361 /* k0/k1 are copied as zero. */
362 if (i == MIPS64_EF_R26 || i == MIPS64_EF_R27)
363 continue;
364
365 uregs[i] = regs->regs[i - MIPS64_EF_R0];
366 }
367
368 uregs[MIPS64_EF_LO] = regs->lo;
369 uregs[MIPS64_EF_HI] = regs->hi;
370 uregs[MIPS64_EF_CP0_EPC] = regs->cp0_epc;
371 uregs[MIPS64_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
372 uregs[MIPS64_EF_CP0_STATUS] = regs->cp0_status;
373 uregs[MIPS64_EF_CP0_CAUSE] = regs->cp0_cause;
374
375 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
376 sizeof(uregs));
377}
378
379static int gpr64_set(struct task_struct *target,
380 const struct user_regset *regset,
381 unsigned int pos, unsigned int count,
382 const void *kbuf, const void __user *ubuf)
383{
384 struct pt_regs *regs = task_pt_regs(target);
385 u64 uregs[ELF_NGREG];
386 unsigned start, num_regs, i;
387 int err;
388
389 start = pos / sizeof(u64);
390 num_regs = count / sizeof(u64);
391
392 if (start + num_regs > ELF_NGREG)
393 return -EIO;
394
395 err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
396 sizeof(uregs));
397 if (err)
398 return err;
399
400 for (i = start; i < num_regs; i++) {
401 switch (i) {
402 case MIPS64_EF_R1 ... MIPS64_EF_R25:
403 /* k0/k1 are ignored. */
404 case MIPS64_EF_R28 ... MIPS64_EF_R31:
405 regs->regs[i - MIPS64_EF_R0] = uregs[i];
406 break;
407 case MIPS64_EF_LO:
408 regs->lo = uregs[i];
409 break;
410 case MIPS64_EF_HI:
411 regs->hi = uregs[i];
412 break;
413 case MIPS64_EF_CP0_EPC:
414 regs->cp0_epc = uregs[i];
415 break;
416 }
417 }
418
419 return 0;
420}
421
422#endif /* CONFIG_64BIT */
423
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200424static int fpr_get(struct task_struct *target,
425 const struct user_regset *regset,
426 unsigned int pos, unsigned int count,
427 void *kbuf, void __user *ubuf)
428{
Paul Burton72b22bb2014-01-27 15:23:07 +0000429 unsigned i;
430 int err;
431 u64 fpr_val;
432
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200433 /* XXX fcr31 */
Paul Burton72b22bb2014-01-27 15:23:07 +0000434
435 if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
436 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
437 &target->thread.fpu,
438 0, sizeof(elf_fpregset_t));
439
440 for (i = 0; i < NUM_FPU_REGS; i++) {
441 fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0);
442 err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
443 &fpr_val, i * sizeof(elf_fpreg_t),
444 (i + 1) * sizeof(elf_fpreg_t));
445 if (err)
446 return err;
447 }
448
449 return 0;
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200450}
451
452static int fpr_set(struct task_struct *target,
453 const struct user_regset *regset,
454 unsigned int pos, unsigned int count,
455 const void *kbuf, const void __user *ubuf)
456{
Paul Burton72b22bb2014-01-27 15:23:07 +0000457 unsigned i;
458 int err;
459 u64 fpr_val;
460
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200461 /* XXX fcr31 */
Paul Burton72b22bb2014-01-27 15:23:07 +0000462
Paul Burtonac9ad832015-01-30 12:09:36 +0000463 init_fp_ctx(target);
464
Paul Burton72b22bb2014-01-27 15:23:07 +0000465 if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
466 return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
467 &target->thread.fpu,
468 0, sizeof(elf_fpregset_t));
469
470 for (i = 0; i < NUM_FPU_REGS; i++) {
471 err = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
472 &fpr_val, i * sizeof(elf_fpreg_t),
473 (i + 1) * sizeof(elf_fpreg_t));
474 if (err)
475 return err;
476 set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val);
477 }
478
479 return 0;
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200480}
481
482enum mips_regset {
483 REGSET_GPR,
484 REGSET_FPR,
485};
486
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100487#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
488
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200489static const struct user_regset mips_regsets[] = {
490 [REGSET_GPR] = {
491 .core_note_type = NT_PRSTATUS,
492 .n = ELF_NGREG,
493 .size = sizeof(unsigned int),
494 .align = sizeof(unsigned int),
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100495 .get = gpr32_get,
496 .set = gpr32_set,
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200497 },
498 [REGSET_FPR] = {
499 .core_note_type = NT_PRFPREG,
500 .n = ELF_NFPREG,
501 .size = sizeof(elf_fpreg_t),
502 .align = sizeof(elf_fpreg_t),
503 .get = fpr_get,
504 .set = fpr_set,
505 },
506};
507
508static const struct user_regset_view user_mips_view = {
509 .name = "mips",
510 .e_machine = ELF_ARCH,
511 .ei_osabi = ELF_OSABI,
512 .regsets = mips_regsets,
513 .n = ARRAY_SIZE(mips_regsets),
514};
515
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100516#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
517
518#ifdef CONFIG_64BIT
519
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200520static const struct user_regset mips64_regsets[] = {
521 [REGSET_GPR] = {
522 .core_note_type = NT_PRSTATUS,
523 .n = ELF_NGREG,
524 .size = sizeof(unsigned long),
525 .align = sizeof(unsigned long),
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100526 .get = gpr64_get,
527 .set = gpr64_set,
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200528 },
529 [REGSET_FPR] = {
530 .core_note_type = NT_PRFPREG,
531 .n = ELF_NFPREG,
532 .size = sizeof(elf_fpreg_t),
533 .align = sizeof(elf_fpreg_t),
534 .get = fpr_get,
535 .set = fpr_set,
536 },
537};
538
539static const struct user_regset_view user_mips64_view = {
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100540 .name = "mips64",
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200541 .e_machine = ELF_ARCH,
542 .ei_osabi = ELF_OSABI,
543 .regsets = mips64_regsets,
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100544 .n = ARRAY_SIZE(mips64_regsets),
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200545};
546
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100547#endif /* CONFIG_64BIT */
548
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200549const struct user_regset_view *task_user_regset_view(struct task_struct *task)
550{
551#ifdef CONFIG_32BIT
552 return &user_mips_view;
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100553#else
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200554#ifdef CONFIG_MIPS32_O32
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100555 if (test_tsk_thread_flag(task, TIF_32BIT_REGS))
556 return &user_mips_view;
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200557#endif
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200558 return &user_mips64_view;
Alex Smithc23b3d1a2014-07-23 14:40:09 +0100559#endif
Ralf Baechle7aeb7532012-08-02 14:44:11 +0200560}
561
Namhyung Kim9b05a692010-10-27 15:33:47 -0700562long arch_ptrace(struct task_struct *child, long request,
563 unsigned long addr, unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 int ret;
Namhyung Kimfb671132010-10-27 15:33:58 -0700566 void __user *addrp = (void __user *) addr;
567 void __user *datavp = (void __user *) data;
568 unsigned long __user *datalp = (void __user *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 switch (request) {
571 /* when I and D space are separate, these will need to be fixed. */
572 case PTRACE_PEEKTEXT: /* read word at location addr. */
Alexey Dobriyan76647322007-07-17 04:03:43 -0700573 case PTRACE_PEEKDATA:
574 ret = generic_ptrace_peekdata(child, addr, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
577 /* Read the word at location addr in the USER area. */
578 case PTRACE_PEEKUSR: {
579 struct pt_regs *regs;
Paul Burtonbbd426f2014-02-13 11:26:41 +0000580 union fpureg *fregs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 unsigned long tmp = 0;
582
Al Viro40bc9c62006-01-12 01:06:07 -0800583 regs = task_pt_regs(child);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 ret = 0; /* Default return value. */
585
586 switch (addr) {
587 case 0 ... 31:
588 tmp = regs->regs[addr];
589 break;
590 case FPR_BASE ... FPR_BASE + 31:
Paul Burton597ce172013-11-22 13:12:07 +0000591 if (!tsk_used_math(child)) {
592 /* FP not yet used */
593 tmp = -1;
594 break;
595 }
596 fregs = get_fpu_regs(child);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
Ralf Baechle875d43e2005-09-03 15:56:16 -0700598#ifdef CONFIG_32BIT
Paul Burton597ce172013-11-22 13:12:07 +0000599 if (test_thread_flag(TIF_32BIT_FPREGS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 /*
601 * The odd registers are actually the high
602 * order bits of the values stored in the even
603 * registers - unless we're using r2k_switch.S.
604 */
Paul Burtonbbd426f2014-02-13 11:26:41 +0000605 tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
606 addr & 1);
Paul Burton597ce172013-11-22 13:12:07 +0000607 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 }
Paul Burton597ce172013-11-22 13:12:07 +0000609#endif
Paul Burtonbbd426f2014-02-13 11:26:41 +0000610 tmp = get_fpr32(&fregs[addr - FPR_BASE], 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 break;
612 case PC:
613 tmp = regs->cp0_epc;
614 break;
615 case CAUSE:
616 tmp = regs->cp0_cause;
617 break;
618 case BADVADDR:
619 tmp = regs->cp0_badvaddr;
620 break;
621 case MMHI:
622 tmp = regs->hi;
623 break;
624 case MMLO:
625 tmp = regs->lo;
626 break;
Franck Bui-Huu9693a852007-02-02 17:41:47 +0100627#ifdef CONFIG_CPU_HAS_SMARTMIPS
628 case ACX:
629 tmp = regs->acx;
630 break;
631#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 case FPC_CSR:
Atsushi Nemotoeae89072006-05-16 01:26:03 +0900633 tmp = child->thread.fpu.fcr31;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 break;
Paul Burton33510472013-11-19 17:30:35 +0000635 case FPC_EIR:
636 /* implementation / version register */
Alex Smith656ff9b2014-07-23 14:40:06 +0100637 tmp = boot_cpu_data.fpu_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 break;
Ralf Baechlec134a5e2005-06-30 09:42:00 +0000639 case DSP_BASE ... DSP_BASE + 5: {
640 dspreg_t *dregs;
641
Ralf Baechlee50c0a82005-05-31 11:49:19 +0000642 if (!cpu_has_dsp) {
643 tmp = 0;
644 ret = -EIO;
Christoph Hellwig481bed42005-11-07 00:59:47 -0800645 goto out;
Ralf Baechlee50c0a82005-05-31 11:49:19 +0000646 }
Ralf Baechle6c355852005-12-05 13:47:25 +0000647 dregs = __get_dsp_regs(child);
648 tmp = (unsigned long) (dregs[addr - DSP_BASE]);
Ralf Baechlee50c0a82005-05-31 11:49:19 +0000649 break;
Ralf Baechlec134a5e2005-06-30 09:42:00 +0000650 }
Ralf Baechlee50c0a82005-05-31 11:49:19 +0000651 case DSP_CONTROL:
652 if (!cpu_has_dsp) {
653 tmp = 0;
654 ret = -EIO;
Christoph Hellwig481bed42005-11-07 00:59:47 -0800655 goto out;
Ralf Baechlee50c0a82005-05-31 11:49:19 +0000656 }
657 tmp = child->thread.dsp.dspcontrol;
658 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 default:
660 tmp = 0;
661 ret = -EIO;
Christoph Hellwig481bed42005-11-07 00:59:47 -0800662 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 }
Namhyung Kimfb671132010-10-27 15:33:58 -0700664 ret = put_user(tmp, datalp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 break;
666 }
667
668 /* when I and D space are separate, this will have to be fixed. */
669 case PTRACE_POKETEXT: /* write the word at location addr. */
670 case PTRACE_POKEDATA:
Alexey Dobriyanf284ce72007-07-17 04:03:44 -0700671 ret = generic_ptrace_pokedata(child, addr, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 break;
673
674 case PTRACE_POKEUSR: {
675 struct pt_regs *regs;
676 ret = 0;
Al Viro40bc9c62006-01-12 01:06:07 -0800677 regs = task_pt_regs(child);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
679 switch (addr) {
680 case 0 ... 31:
681 regs->regs[addr] = data;
682 break;
683 case FPR_BASE ... FPR_BASE + 31: {
Paul Burtonbbd426f2014-02-13 11:26:41 +0000684 union fpureg *fregs = get_fpu_regs(child);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
Paul Burtonac9ad832015-01-30 12:09:36 +0000686 init_fp_ctx(child);
Ralf Baechle875d43e2005-09-03 15:56:16 -0700687#ifdef CONFIG_32BIT
Paul Burton597ce172013-11-22 13:12:07 +0000688 if (test_thread_flag(TIF_32BIT_FPREGS)) {
689 /*
690 * The odd registers are actually the high
691 * order bits of the values stored in the even
692 * registers - unless we're using r2k_switch.S.
693 */
Paul Burtonbbd426f2014-02-13 11:26:41 +0000694 set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
695 addr & 1, data);
Paul Burton597ce172013-11-22 13:12:07 +0000696 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 }
698#endif
Paul Burtonbbd426f2014-02-13 11:26:41 +0000699 set_fpr64(&fregs[addr - FPR_BASE], 0, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 break;
701 }
702 case PC:
703 regs->cp0_epc = data;
704 break;
705 case MMHI:
706 regs->hi = data;
707 break;
708 case MMLO:
709 regs->lo = data;
710 break;
Franck Bui-Huu9693a852007-02-02 17:41:47 +0100711#ifdef CONFIG_CPU_HAS_SMARTMIPS
712 case ACX:
713 regs->acx = data;
714 break;
715#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 case FPC_CSR:
Paul Burtonb1442d32014-07-22 14:21:21 +0100717 child->thread.fpu.fcr31 = data & ~FPU_CSR_ALL_X;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 break;
Ralf Baechlec134a5e2005-06-30 09:42:00 +0000719 case DSP_BASE ... DSP_BASE + 5: {
720 dspreg_t *dregs;
721
Ralf Baechlee50c0a82005-05-31 11:49:19 +0000722 if (!cpu_has_dsp) {
723 ret = -EIO;
724 break;
725 }
726
Ralf Baechlec134a5e2005-06-30 09:42:00 +0000727 dregs = __get_dsp_regs(child);
Ralf Baechlee50c0a82005-05-31 11:49:19 +0000728 dregs[addr - DSP_BASE] = data;
729 break;
Ralf Baechlec134a5e2005-06-30 09:42:00 +0000730 }
Ralf Baechlee50c0a82005-05-31 11:49:19 +0000731 case DSP_CONTROL:
732 if (!cpu_has_dsp) {
733 ret = -EIO;
734 break;
735 }
736 child->thread.dsp.dspcontrol = data;
737 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 default:
739 /* The rest are not allowed. */
740 ret = -EIO;
741 break;
742 }
743 break;
744 }
745
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400746 case PTRACE_GETREGS:
Namhyung Kimfb671132010-10-27 15:33:58 -0700747 ret = ptrace_getregs(child, datavp);
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400748 break;
749
750 case PTRACE_SETREGS:
Namhyung Kimfb671132010-10-27 15:33:58 -0700751 ret = ptrace_setregs(child, datavp);
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400752 break;
753
754 case PTRACE_GETFPREGS:
Namhyung Kimfb671132010-10-27 15:33:58 -0700755 ret = ptrace_getfpregs(child, datavp);
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400756 break;
757
758 case PTRACE_SETFPREGS:
Namhyung Kimfb671132010-10-27 15:33:58 -0700759 ret = ptrace_setfpregs(child, datavp);
Daniel Jacobowitzea3d7102005-09-28 18:11:15 -0400760 break;
761
Ralf Baechle3c370262005-04-13 17:43:59 +0000762 case PTRACE_GET_THREAD_AREA:
Namhyung Kimfb671132010-10-27 15:33:58 -0700763 ret = put_user(task_thread_info(child)->tp_value, datalp);
Ralf Baechle3c370262005-04-13 17:43:59 +0000764 break;
765
David Daney0926bf92008-09-23 00:11:26 -0700766 case PTRACE_GET_WATCH_REGS:
Namhyung Kimfb671132010-10-27 15:33:58 -0700767 ret = ptrace_get_watch_regs(child, addrp);
David Daney0926bf92008-09-23 00:11:26 -0700768 break;
769
770 case PTRACE_SET_WATCH_REGS:
Namhyung Kimfb671132010-10-27 15:33:58 -0700771 ret = ptrace_set_watch_regs(child, addrp);
David Daney0926bf92008-09-23 00:11:26 -0700772 break;
773
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 default:
775 ret = ptrace_request(child, request, addr, data);
776 break;
777 }
Christoph Hellwig481bed42005-11-07 00:59:47 -0800778 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 return ret;
780}
781
782/*
783 * Notification of system call entry/exit
784 * - triggered by current->work.syscall_trace
785 */
Markos Chandras4c21b8f2014-01-22 14:40:03 +0000786asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787{
Ralf Baechle0dfa95a2012-09-26 21:30:47 +0200788 long ret = 0;
Ralf Baechlec3fc5cd2013-05-29 01:07:19 +0200789 user_exit();
790
Lars Perssonc2d9f172015-02-03 17:08:17 +0100791 current_thread_info()->syscall = syscall;
792
Andy Lutomirskia4412fc2014-07-21 18:49:14 -0700793 if (secure_computing() == -1)
Markos Chandras1225eb82014-01-22 14:40:01 +0000794 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
Ralf Baechle0dfa95a2012-09-26 21:30:47 +0200796 if (test_thread_flag(TIF_SYSCALL_TRACE) &&
797 tracehook_report_syscall_entry(regs))
798 ret = -1;
Ralf Baechle293c5bd2007-07-25 16:19:33 +0100799
Ralf Baechle1d7bf992013-09-06 20:24:48 +0200800 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
801 trace_sys_enter(regs, regs->regs[2]);
802
Eric Paris91397402014-03-11 13:29:28 -0400803 audit_syscall_entry(syscall, regs->regs[4], regs->regs[5],
Eric Parisb05d8442012-01-03 14:23:06 -0500804 regs->regs[6], regs->regs[7]);
Markos Chandras1225eb82014-01-22 14:40:01 +0000805 return syscall;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806}
Ralf Baechle8b659a32011-05-19 09:21:29 +0100807
808/*
809 * Notification of system call entry/exit
810 * - triggered by current->work.syscall_trace
811 */
812asmlinkage void syscall_trace_leave(struct pt_regs *regs)
813{
Ralf Baechlec3fc5cd2013-05-29 01:07:19 +0200814 /*
815 * We may come here right after calling schedule_user()
816 * or do_notify_resume(), in which case we can be in RCU
817 * user mode.
818 */
819 user_exit();
820
Eric Parisd7e75282012-01-03 14:23:06 -0500821 audit_syscall_exit(regs);
Ralf Baechle8b659a32011-05-19 09:21:29 +0100822
Ralf Baechle1d7bf992013-09-06 20:24:48 +0200823 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
824 trace_sys_exit(regs, regs->regs[2]);
825
Ralf Baechlebc3d22c2012-07-17 19:43:58 +0200826 if (test_thread_flag(TIF_SYSCALL_TRACE))
827 tracehook_report_syscall_exit(regs, 0);
Ralf Baechlec3fc5cd2013-05-29 01:07:19 +0200828
829 user_enter();
Ralf Baechle8b659a32011-05-19 09:21:29 +0100830}