linux/arch/metag/kernel/ptrace.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 2005-2012 Imagination Technologies Ltd.
   3 *
   4 * This file is subject to the terms and conditions of the GNU General
   5 * Public License.  See the file COPYING in the main directory of
   6 * this archive for more details.
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/mm.h>
  11#include <linux/errno.h>
  12#include <linux/ptrace.h>
  13#include <linux/user.h>
  14#include <linux/regset.h>
  15#include <linux/tracehook.h>
  16#include <linux/elf.h>
  17#include <linux/uaccess.h>
  18#include <trace/syscall.h>
  19
  20#define CREATE_TRACE_POINTS
  21#include <trace/events/syscalls.h>
  22
  23/*
  24 * user_regset definitions.
  25 */
  26
  27int metag_gp_regs_copyout(const struct pt_regs *regs,
  28                          unsigned int pos, unsigned int count,
  29                          void *kbuf, void __user *ubuf)
  30{
  31        const void *ptr;
  32        unsigned long data;
  33        int ret;
  34
  35        /* D{0-1}.{0-7} */
  36        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  37                                  regs->ctx.DX, 0, 4*16);
  38        if (ret)
  39                goto out;
  40        /* A{0-1}.{0-1} */
  41        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  42                                  regs->ctx.AX, 4*16, 4*20);
  43        if (ret)
  44                goto out;
  45        /* A{0-1}.2 */
  46        if (regs->ctx.SaveMask & TBICTX_XEXT_BIT)
  47                ptr = regs->ctx.Ext.Ctx.pExt;
  48        else
  49                ptr = &regs->ctx.Ext.AX2;
  50        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  51                                  ptr, 4*20, 4*22);
  52        if (ret)
  53                goto out;
  54        /* A{0-1}.3 */
  55        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  56                                  &regs->ctx.AX3, 4*22, 4*24);
  57        if (ret)
  58                goto out;
  59        /* PC */
  60        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  61                                  &regs->ctx.CurrPC, 4*24, 4*25);
  62        if (ret)
  63                goto out;
  64        /* TXSTATUS */
  65        data = (unsigned long)regs->ctx.Flags;
  66        if (regs->ctx.SaveMask & TBICTX_CBUF_BIT)
  67                data |= USER_GP_REGS_STATUS_CATCH_BIT;
  68        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  69                                  &data, 4*25, 4*26);
  70        if (ret)
  71                goto out;
  72        /* TXRPT, TXBPOBITS, TXMODE */
  73        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  74                                  &regs->ctx.CurrRPT, 4*26, 4*29);
  75        if (ret)
  76                goto out;
  77        /* Padding */
  78        ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
  79                                       4*29, 4*30);
  80out:
  81        return ret;
  82}
  83
  84int metag_gp_regs_copyin(struct pt_regs *regs,
  85                         unsigned int pos, unsigned int count,
  86                         const void *kbuf, const void __user *ubuf)
  87{
  88        void *ptr;
  89        unsigned long data;
  90        int ret;
  91
  92        /* D{0-1}.{0-7} */
  93        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  94                                 regs->ctx.DX, 0, 4*16);
  95        if (ret)
  96                goto out;
  97        /* A{0-1}.{0-1} */
  98        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  99                                 regs->ctx.AX, 4*16, 4*20);
 100        if (ret)
 101                goto out;
 102        /* A{0-1}.2 */
 103        if (regs->ctx.SaveMask & TBICTX_XEXT_BIT)
 104                ptr = regs->ctx.Ext.Ctx.pExt;
 105        else
 106                ptr = &regs->ctx.Ext.AX2;
 107        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 108                                 ptr, 4*20, 4*22);
 109        if (ret)
 110                goto out;
 111        /* A{0-1}.3 */
 112        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 113                                 &regs->ctx.AX3, 4*22, 4*24);
 114        if (ret)
 115                goto out;
 116        /* PC */
 117        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 118                                 &regs->ctx.CurrPC, 4*24, 4*25);
 119        if (ret)
 120                goto out;
 121        /* TXSTATUS */
 122        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 123                                 &data, 4*25, 4*26);
 124        if (ret)
 125                goto out;
 126        regs->ctx.Flags = data & 0xffff;
 127        if (data & USER_GP_REGS_STATUS_CATCH_BIT)
 128                regs->ctx.SaveMask |= TBICTX_XCBF_BIT | TBICTX_CBUF_BIT;
 129        else
 130                regs->ctx.SaveMask &= ~TBICTX_CBUF_BIT;
 131        /* TXRPT, TXBPOBITS, TXMODE */
 132        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 133                                 &regs->ctx.CurrRPT, 4*26, 4*29);
 134out:
 135        return ret;
 136}
 137
 138static int metag_gp_regs_get(struct task_struct *target,
 139                             const struct user_regset *regset,
 140                             unsigned int pos, unsigned int count,
 141                             void *kbuf, void __user *ubuf)
 142{
 143        const struct pt_regs *regs = task_pt_regs(target);
 144        return metag_gp_regs_copyout(regs, pos, count, kbuf, ubuf);
 145}
 146
 147static int metag_gp_regs_set(struct task_struct *target,
 148                             const struct user_regset *regset,
 149                             unsigned int pos, unsigned int count,
 150                             const void *kbuf, const void __user *ubuf)
 151{
 152        struct pt_regs *regs = task_pt_regs(target);
 153        return metag_gp_regs_copyin(regs, pos, count, kbuf, ubuf);
 154}
 155
 156int metag_cb_regs_copyout(const struct pt_regs *regs,
 157                          unsigned int pos, unsigned int count,
 158                          void *kbuf, void __user *ubuf)
 159{
 160        int ret;
 161
 162        /* TXCATCH{0-3} */
 163        if (regs->ctx.SaveMask & TBICTX_XCBF_BIT)
 164                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 165                                          regs->extcb0, 0, 4*4);
 166        else
 167                ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
 168                                               0, 4*4);
 169        return ret;
 170}
 171
 172int metag_cb_regs_copyin(struct pt_regs *regs,
 173                         unsigned int pos, unsigned int count,
 174                         const void *kbuf, const void __user *ubuf)
 175{
 176        int ret;
 177
 178        /* TXCATCH{0-3} */
 179        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 180                                 regs->extcb0, 0, 4*4);
 181        return ret;
 182}
 183
 184static int metag_cb_regs_get(struct task_struct *target,
 185                             const struct user_regset *regset,
 186                             unsigned int pos, unsigned int count,
 187                             void *kbuf, void __user *ubuf)
 188{
 189        const struct pt_regs *regs = task_pt_regs(target);
 190        return metag_cb_regs_copyout(regs, pos, count, kbuf, ubuf);
 191}
 192
 193static int metag_cb_regs_set(struct task_struct *target,
 194                             const struct user_regset *regset,
 195                             unsigned int pos, unsigned int count,
 196                             const void *kbuf, const void __user *ubuf)
 197{
 198        struct pt_regs *regs = task_pt_regs(target);
 199        return metag_cb_regs_copyin(regs, pos, count, kbuf, ubuf);
 200}
 201
 202int metag_rp_state_copyout(const struct pt_regs *regs,
 203                           unsigned int pos, unsigned int count,
 204                           void *kbuf, void __user *ubuf)
 205{
 206        unsigned long mask;
 207        u64 *ptr;
 208        int ret, i;
 209
 210        /* Empty read pipeline */
 211        if (!(regs->ctx.SaveMask & TBICTX_CBRP_BIT)) {
 212                ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
 213                                               0, 4*13);
 214                goto out;
 215        }
 216
 217        mask = (regs->ctx.CurrDIVTIME & TXDIVTIME_RPMASK_BITS) >>
 218                TXDIVTIME_RPMASK_S;
 219
 220        /* Read pipeline entries */
 221        ptr = (void *)&regs->extcb0[1];
 222        for (i = 0; i < 6; ++i, ++ptr) {
 223                if (mask & (1 << i))
 224                        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 225                                                  ptr, 8*i, 8*(i + 1));
 226                else
 227                        ret = user_regset_copyout_zero(&pos, &count, &kbuf,
 228                                                       &ubuf, 8*i, 8*(i + 1));
 229                if (ret)
 230                        goto out;
 231        }
 232        /* Mask of entries */
 233        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 234                                  &mask, 4*12, 4*13);
 235out:
 236        return ret;
 237}
 238
 239int metag_rp_state_copyin(struct pt_regs *regs,
 240                          unsigned int pos, unsigned int count,
 241                          const void *kbuf, const void __user *ubuf)
 242{
 243        struct user_rp_state rp;
 244        unsigned long long *ptr;
 245        int ret, i;
 246
 247        /* Read the entire pipeline before making any changes */
 248        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 249                                 &rp, 0, 4*13);
 250        if (ret)
 251                goto out;
 252
 253        /* Write pipeline entries */
 254        ptr = (void *)&regs->extcb0[1];
 255        for (i = 0; i < 6; ++i, ++ptr)
 256                if (rp.mask & (1 << i))
 257                        *ptr = rp.entries[i];
 258
 259        /* Update RPMask in TXDIVTIME */
 260        regs->ctx.CurrDIVTIME &= ~TXDIVTIME_RPMASK_BITS;
 261        regs->ctx.CurrDIVTIME |= (rp.mask << TXDIVTIME_RPMASK_S)
 262                                 & TXDIVTIME_RPMASK_BITS;
 263
 264        /* Set/clear flags to indicate catch/read pipeline state */
 265        if (rp.mask)
 266                regs->ctx.SaveMask |= TBICTX_XCBF_BIT | TBICTX_CBRP_BIT;
 267        else
 268                regs->ctx.SaveMask &= ~TBICTX_CBRP_BIT;
 269out:
 270        return ret;
 271}
 272
 273static int metag_rp_state_get(struct task_struct *target,
 274                              const struct user_regset *regset,
 275                              unsigned int pos, unsigned int count,
 276                              void *kbuf, void __user *ubuf)
 277{
 278        const struct pt_regs *regs = task_pt_regs(target);
 279        return metag_rp_state_copyout(regs, pos, count, kbuf, ubuf);
 280}
 281
 282static int metag_rp_state_set(struct task_struct *target,
 283                              const struct user_regset *regset,
 284                              unsigned int pos, unsigned int count,
 285                              const void *kbuf, const void __user *ubuf)
 286{
 287        struct pt_regs *regs = task_pt_regs(target);
 288        return metag_rp_state_copyin(regs, pos, count, kbuf, ubuf);
 289}
 290
 291static int metag_tls_get(struct task_struct *target,
 292                        const struct user_regset *regset,
 293                        unsigned int pos, unsigned int count,
 294                        void *kbuf, void __user *ubuf)
 295{
 296        void __user *tls = target->thread.tls_ptr;
 297        return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
 298}
 299
 300static int metag_tls_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)
 304{
 305        int ret;
 306        void __user *tls;
 307
 308        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
 309        if (ret)
 310                return ret;
 311
 312        target->thread.tls_ptr = tls;
 313        return ret;
 314}
 315
 316enum metag_regset {
 317        REGSET_GENERAL,
 318        REGSET_CBUF,
 319        REGSET_READPIPE,
 320        REGSET_TLS,
 321};
 322
 323static const struct user_regset metag_regsets[] = {
 324        [REGSET_GENERAL] = {
 325                .core_note_type = NT_PRSTATUS,
 326                .n = ELF_NGREG,
 327                .size = sizeof(long),
 328                .align = sizeof(long long),
 329                .get = metag_gp_regs_get,
 330                .set = metag_gp_regs_set,
 331        },
 332        [REGSET_CBUF] = {
 333                .core_note_type = NT_METAG_CBUF,
 334                .n = sizeof(struct user_cb_regs) / sizeof(long),
 335                .size = sizeof(long),
 336                .align = sizeof(long long),
 337                .get = metag_cb_regs_get,
 338                .set = metag_cb_regs_set,
 339        },
 340        [REGSET_READPIPE] = {
 341                .core_note_type = NT_METAG_RPIPE,
 342                .n = sizeof(struct user_rp_state) / sizeof(long),
 343                .size = sizeof(long),
 344                .align = sizeof(long long),
 345                .get = metag_rp_state_get,
 346                .set = metag_rp_state_set,
 347        },
 348        [REGSET_TLS] = {
 349                .core_note_type = NT_METAG_TLS,
 350                .n = 1,
 351                .size = sizeof(void *),
 352                .align = sizeof(void *),
 353                .get = metag_tls_get,
 354                .set = metag_tls_set,
 355        },
 356};
 357
 358static const struct user_regset_view user_metag_view = {
 359        .name = "metag",
 360        .e_machine = EM_METAG,
 361        .regsets = metag_regsets,
 362        .n = ARRAY_SIZE(metag_regsets)
 363};
 364
 365const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 366{
 367        return &user_metag_view;
 368}
 369
 370/*
 371 * Called by kernel/ptrace.c when detaching..
 372 *
 373 * Make sure single step bits etc are not set.
 374 */
 375void ptrace_disable(struct task_struct *child)
 376{
 377        /* nothing to do.. */
 378}
 379
 380long arch_ptrace(struct task_struct *child, long request, unsigned long addr,
 381                 unsigned long data)
 382{
 383        int ret;
 384
 385        switch (request) {
 386        default:
 387                ret = ptrace_request(child, request, addr, data);
 388                break;
 389        }
 390
 391        return ret;
 392}
 393
 394int syscall_trace_enter(struct pt_regs *regs)
 395{
 396        int ret = 0;
 397
 398        if (test_thread_flag(TIF_SYSCALL_TRACE))
 399                ret = tracehook_report_syscall_entry(regs);
 400
 401        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
 402                trace_sys_enter(regs, regs->ctx.DX[0].U1);
 403
 404        return ret ? -1 : regs->ctx.DX[0].U1;
 405}
 406
 407void syscall_trace_leave(struct pt_regs *regs)
 408{
 409        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
 410                trace_sys_exit(regs, regs->ctx.DX[0].U1);
 411
 412        if (test_thread_flag(TIF_SYSCALL_TRACE))
 413                tracehook_report_syscall_exit(regs, 0);
 414}
 415