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