aboutsummaryrefslogtreecommitdiff
path: root/arch/xtensa
diff options
context:
space:
mode:
authorMax Filippov2018-11-09 19:32:06 -0800
committerMax Filippov2018-12-17 13:48:21 -0800
commit06fbac8e8971f2fa526e189304dd95ee62f39dbe (patch)
tree16618a31098c5838d59e37b5da5d1e63da4b596e /arch/xtensa
parent3aee3e25deeab083df21012060c98e9987ac9177 (diff)
xtensa: implement task_user_regset_view
- define struct user_pt_regs in the arch/xtensa/include/uapi/asm/ptrace.h with the same layout as xtensa_gregset_t; make xtensa_gregset_t a typedef; - define REGSET_GPR regset, implement register get and set functions; - define task_user_regset_view function and expose REGSET_GPR. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Diffstat (limited to 'arch/xtensa')
-rw-r--r--arch/xtensa/include/asm/elf.h14
-rw-r--r--arch/xtensa/include/uapi/asm/ptrace.h20
-rw-r--r--arch/xtensa/kernel/ptrace.c175
3 files changed, 129 insertions, 80 deletions
diff --git a/arch/xtensa/include/asm/elf.h b/arch/xtensa/include/asm/elf.h
index f3291b110a0d..c30c73eea267 100644
--- a/arch/xtensa/include/asm/elf.h
+++ b/arch/xtensa/include/asm/elf.h
@@ -75,19 +75,7 @@
typedef unsigned long elf_greg_t;
-typedef struct {
- elf_greg_t pc;
- elf_greg_t ps;
- elf_greg_t lbeg;
- elf_greg_t lend;
- elf_greg_t lcount;
- elf_greg_t sar;
- elf_greg_t windowstart;
- elf_greg_t windowbase;
- elf_greg_t threadptr;
- elf_greg_t reserved[7+48];
- elf_greg_t a[64];
-} xtensa_gregset_t;
+typedef struct user_pt_regs xtensa_gregset_t;
#define ELF_NGREG (sizeof(xtensa_gregset_t) / sizeof(elf_greg_t))
diff --git a/arch/xtensa/include/uapi/asm/ptrace.h b/arch/xtensa/include/uapi/asm/ptrace.h
index a10b42963703..2ec0f9100a06 100644
--- a/arch/xtensa/include/uapi/asm/ptrace.h
+++ b/arch/xtensa/include/uapi/asm/ptrace.h
@@ -12,6 +12,8 @@
#ifndef _UAPI_XTENSA_PTRACE_H
#define _UAPI_XTENSA_PTRACE_H
+#include <linux/types.h>
+
/* Registers used by strace */
#define REG_A_BASE 0x0000
@@ -36,5 +38,21 @@
#define PTRACE_GETHBPREGS 20
#define PTRACE_SETHBPREGS 21
-
+#ifndef __ASSEMBLY__
+
+struct user_pt_regs {
+ __u32 pc;
+ __u32 ps;
+ __u32 lbeg;
+ __u32 lend;
+ __u32 lcount;
+ __u32 sar;
+ __u32 windowstart;
+ __u32 windowbase;
+ __u32 threadptr;
+ __u32 reserved[7 + 48];
+ __u32 a[64];
+};
+
+#endif
#endif /* _UAPI_XTENSA_PTRACE_H */
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
index f73a6a71323e..ce751b1af7b3 100644
--- a/arch/xtensa/kernel/ptrace.c
+++ b/arch/xtensa/kernel/ptrace.c
@@ -18,6 +18,7 @@
#include <linux/mm.h>
#include <linux/perf_event.h>
#include <linux/ptrace.h>
+#include <linux/regset.h>
#include <linux/sched.h>
#include <linux/sched/task_stack.h>
#include <linux/security.h>
@@ -32,6 +33,110 @@
#include <asm/pgtable.h>
#include <asm/ptrace.h>
+static int gpr_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ struct pt_regs *regs = task_pt_regs(target);
+ struct user_pt_regs newregs = {
+ .pc = regs->pc,
+ .ps = regs->ps & ~(1 << PS_EXCM_BIT),
+ .lbeg = regs->lbeg,
+ .lend = regs->lend,
+ .lcount = regs->lcount,
+ .sar = regs->sar,
+ .threadptr = regs->threadptr,
+ .windowbase = regs->windowbase,
+ .windowstart = regs->windowstart,
+ };
+
+ memcpy(newregs.a,
+ regs->areg + XCHAL_NUM_AREGS - regs->windowbase * 4,
+ regs->windowbase * 16);
+ memcpy(newregs.a + regs->windowbase * 4,
+ regs->areg,
+ (WSBITS - regs->windowbase) * 16);
+
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &newregs, 0, -1);
+}
+
+static int gpr_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+ struct user_pt_regs newregs = {0};
+ struct pt_regs *regs;
+ const u32 ps_mask = PS_CALLINC_MASK | PS_OWB_MASK;
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1);
+ if (ret)
+ return ret;
+
+ if (newregs.windowbase >= XCHAL_NUM_AREGS / 4)
+ return -EINVAL;
+
+ regs = task_pt_regs(target);
+ regs->pc = newregs.pc;
+ regs->ps = (regs->ps & ~ps_mask) | (newregs.ps & ps_mask);
+ regs->lbeg = newregs.lbeg;
+ regs->lend = newregs.lend;
+ regs->lcount = newregs.lcount;
+ regs->sar = newregs.sar;
+ regs->threadptr = newregs.threadptr;
+
+ if (newregs.windowbase != regs->windowbase ||
+ newregs.windowstart != regs->windowstart) {
+ u32 rotws, wmask;
+
+ rotws = (((newregs.windowstart |
+ (newregs.windowstart << WSBITS)) >>
+ newregs.windowbase) &
+ ((1 << WSBITS) - 1)) & ~1;
+ wmask = ((rotws ? WSBITS + 1 - ffs(rotws) : 0) << 4) |
+ (rotws & 0xF) | 1;
+ regs->windowbase = newregs.windowbase;
+ regs->windowstart = newregs.windowstart;
+ regs->wmask = wmask;
+ }
+
+ memcpy(regs->areg + XCHAL_NUM_AREGS - newregs.windowbase * 4,
+ newregs.a, newregs.windowbase * 16);
+ memcpy(regs->areg, newregs.a + newregs.windowbase * 4,
+ (WSBITS - newregs.windowbase) * 16);
+
+ return 0;
+}
+
+enum xtensa_regset {
+ REGSET_GPR,
+};
+
+static const struct user_regset xtensa_regsets[] = {
+ [REGSET_GPR] = {
+ .core_note_type = NT_PRSTATUS,
+ .n = sizeof(struct user_pt_regs) / sizeof(u32),
+ .size = sizeof(u32),
+ .align = sizeof(u32),
+ .get = gpr_get,
+ .set = gpr_set
+ },
+};
+
+static const struct user_regset_view user_xtensa_view = {
+ .name = "xtensa",
+ .e_machine = EM_XTENSA,
+ .regsets = xtensa_regsets,
+ .n = ARRAY_SIZE(xtensa_regsets)
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+ return &user_xtensa_view;
+}
void user_enable_single_step(struct task_struct *child)
{
@@ -54,76 +159,14 @@ void ptrace_disable(struct task_struct *child)
static int ptrace_getregs(struct task_struct *child, void __user *uregs)
{
- struct pt_regs *regs = task_pt_regs(child);
- xtensa_gregset_t __user *gregset = uregs;
- unsigned long wb = regs->windowbase;
- int i;
-
- if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
- return -EIO;
-
- __put_user(regs->pc, &gregset->pc);
- __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps);
- __put_user(regs->lbeg, &gregset->lbeg);
- __put_user(regs->lend, &gregset->lend);
- __put_user(regs->lcount, &gregset->lcount);
- __put_user(regs->windowstart, &gregset->windowstart);
- __put_user(regs->windowbase, &gregset->windowbase);
- __put_user(regs->threadptr, &gregset->threadptr);
-
- for (i = 0; i < XCHAL_NUM_AREGS; i++)
- __put_user(regs->areg[i],
- gregset->a + ((wb * 4 + i) % XCHAL_NUM_AREGS));
-
- return 0;
+ return copy_regset_to_user(child, &user_xtensa_view, REGSET_GPR,
+ 0, sizeof(xtensa_gregset_t), uregs);
}
static int ptrace_setregs(struct task_struct *child, void __user *uregs)
{
- struct pt_regs *regs = task_pt_regs(child);
- xtensa_gregset_t *gregset = uregs;
- const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK;
- unsigned long ps;
- unsigned long wb, ws;
-
- if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
- return -EIO;
-
- __get_user(regs->pc, &gregset->pc);
- __get_user(ps, &gregset->ps);
- __get_user(regs->lbeg, &gregset->lbeg);
- __get_user(regs->lend, &gregset->lend);
- __get_user(regs->lcount, &gregset->lcount);
- __get_user(ws, &gregset->windowstart);
- __get_user(wb, &gregset->windowbase);
- __get_user(regs->threadptr, &gregset->threadptr);
-
- regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT);
-
- if (wb >= XCHAL_NUM_AREGS / 4)
- return -EFAULT;
-
- if (wb != regs->windowbase || ws != regs->windowstart) {
- unsigned long rotws, wmask;
-
- rotws = (((ws | (ws << WSBITS)) >> wb) &
- ((1 << WSBITS) - 1)) & ~1;
- wmask = ((rotws ? WSBITS + 1 - ffs(rotws) : 0) << 4) |
- (rotws & 0xF) | 1;
- regs->windowbase = wb;
- regs->windowstart = ws;
- regs->wmask = wmask;
- }
-
- if (wb != 0 && __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4,
- gregset->a, wb * 16))
- return -EFAULT;
-
- if (__copy_from_user(regs->areg, gregset->a + wb * 4,
- (WSBITS - wb) * 16))
- return -EFAULT;
-
- return 0;
+ return copy_regset_from_user(child, &user_xtensa_view, REGSET_GPR,
+ 0, sizeof(xtensa_gregset_t), uregs);
}