linux/arch/hexagon/kernel/ptrace.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Ptrace support for Hexagon
   4 *
   5 * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
   6 */
   7
   8#include <linux/kernel.h>
   9#include <linux/sched.h>
  10#include <linux/sched/task_stack.h>
  11#include <linux/mm.h>
  12#include <linux/smp.h>
  13#include <linux/errno.h>
  14#include <linux/ptrace.h>
  15#include <linux/regset.h>
  16#include <linux/user.h>
  17#include <linux/elf.h>
  18
  19#include <asm/user.h>
  20
  21#if arch_has_single_step()
  22/*  Both called from ptrace_resume  */
  23void user_enable_single_step(struct task_struct *child)
  24{
  25        pt_set_singlestep(task_pt_regs(child));
  26        set_tsk_thread_flag(child, TIF_SINGLESTEP);
  27}
  28
  29void user_disable_single_step(struct task_struct *child)
  30{
  31        pt_clr_singlestep(task_pt_regs(child));
  32        clear_tsk_thread_flag(child, TIF_SINGLESTEP);
  33}
  34#endif
  35
  36static int genregs_get(struct task_struct *target,
  37                   const struct user_regset *regset,
  38                   struct membuf to)
  39{
  40        struct pt_regs *regs = task_pt_regs(target);
  41
  42        /* The general idea here is that the copyout must happen in
  43         * exactly the same order in which the userspace expects these
  44         * regs. Now, the sequence in userspace does not match the
  45         * sequence in the kernel, so everything past the 32 gprs
  46         * happens one at a time.
  47         */
  48        membuf_write(&to, &regs->r00, 32*sizeof(unsigned long));
  49        /* Must be exactly same sequence as struct user_regs_struct */
  50        membuf_store(&to, regs->sa0);
  51        membuf_store(&to, regs->lc0);
  52        membuf_store(&to, regs->sa1);
  53        membuf_store(&to, regs->lc1);
  54        membuf_store(&to, regs->m0);
  55        membuf_store(&to, regs->m1);
  56        membuf_store(&to, regs->usr);
  57        membuf_store(&to, regs->preds);
  58        membuf_store(&to, regs->gp);
  59        membuf_store(&to, regs->ugp);
  60        membuf_store(&to, pt_elr(regs)); // pc
  61        membuf_store(&to, (unsigned long)pt_cause(regs)); // cause
  62        membuf_store(&to, pt_badva(regs)); // badva
  63#if CONFIG_HEXAGON_ARCH_VERSION >=4
  64        membuf_store(&to, regs->cs0);
  65        membuf_store(&to, regs->cs1);
  66        return membuf_zero(&to, sizeof(unsigned long));
  67#else
  68        return membuf_zero(&to, 3 * sizeof(unsigned long));
  69#endif
  70}
  71
  72static int genregs_set(struct task_struct *target,
  73                   const struct user_regset *regset,
  74                   unsigned int pos, unsigned int count,
  75                   const void *kbuf, const void __user *ubuf)
  76{
  77        int ret;
  78        unsigned long bucket;
  79        struct pt_regs *regs = task_pt_regs(target);
  80
  81        if (!regs)
  82                return -EIO;
  83
  84        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  85                                 &regs->r00, 0, 32*sizeof(unsigned long));
  86
  87#define INEXT(KPT_REG, USR_REG) \
  88        if (!ret) \
  89                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \
  90                        KPT_REG, offsetof(struct user_regs_struct, USR_REG), \
  91                        offsetof(struct user_regs_struct, USR_REG) + \
  92                                sizeof(unsigned long));
  93
  94        /* Must be exactly same sequence as struct user_regs_struct */
  95        INEXT(&regs->sa0, sa0);
  96        INEXT(&regs->lc0, lc0);
  97        INEXT(&regs->sa1, sa1);
  98        INEXT(&regs->lc1, lc1);
  99        INEXT(&regs->m0, m0);
 100        INEXT(&regs->m1, m1);
 101        INEXT(&regs->usr, usr);
 102        INEXT(&regs->preds, p3_0);
 103        INEXT(&regs->gp, gp);
 104        INEXT(&regs->ugp, ugp);
 105        INEXT(&pt_elr(regs), pc);
 106
 107        /* CAUSE and BADVA aren't writeable. */
 108        INEXT(&bucket, cause);
 109        INEXT(&bucket, badva);
 110
 111#if CONFIG_HEXAGON_ARCH_VERSION >=4
 112        INEXT(&regs->cs0, cs0);
 113        INEXT(&regs->cs1, cs1);
 114#endif
 115
 116        /* Ignore the rest, if needed */
 117        if (!ret)
 118                ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
 119                                        offsetof(struct user_regs_struct, pad1), -1);
 120
 121        if (ret)
 122                return ret;
 123
 124        /*
 125         * This is special; SP is actually restored by the VM via the
 126         * special event record which is set by the special trap.
 127         */
 128        regs->hvmer.vmpsp = regs->r29;
 129        return 0;
 130}
 131
 132enum hexagon_regset {
 133        REGSET_GENERAL,
 134};
 135
 136static const struct user_regset hexagon_regsets[] = {
 137        [REGSET_GENERAL] = {
 138                .core_note_type = NT_PRSTATUS,
 139                .n = ELF_NGREG,
 140                .size = sizeof(unsigned long),
 141                .align = sizeof(unsigned long),
 142                .regset_get = genregs_get,
 143                .set = genregs_set,
 144        },
 145};
 146
 147static const struct user_regset_view hexagon_user_view = {
 148        .name = "hexagon",
 149        .e_machine = ELF_ARCH,
 150        .ei_osabi = ELF_OSABI,
 151        .regsets = hexagon_regsets,
 152        .e_flags = ELF_CORE_EFLAGS,
 153        .n = ARRAY_SIZE(hexagon_regsets)
 154};
 155
 156const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 157{
 158        return &hexagon_user_view;
 159}
 160
 161void ptrace_disable(struct task_struct *child)
 162{
 163        /* Boilerplate - resolves to null inline if no HW single-step */
 164        user_disable_single_step(child);
 165}
 166
 167long arch_ptrace(struct task_struct *child, long request,
 168                 unsigned long addr, unsigned long data)
 169{
 170        return ptrace_request(child, request, addr, data);
 171}
 172