~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/sparc/kernel/ptrace_64.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php