Commit 19b39c38 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'work.regset' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull ptrace regset updates from Al Viro:
 "Internal regset API changes:

   - regularize copy_regset_{to,from}_user() callers

   - switch to saner calling conventions for ->get()

   - kill user_regset_copyout()

  The ->put() side of things will have to wait for the next cycle,
  unfortunately.

  The balance is about -1KLoC and replacements for ->get() instances are
  a lot saner"

* 'work.regset' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (41 commits)
  regset: kill user_regset_copyout{,_zero}()
  regset(): kill ->get_size()
  regset: kill ->get()
  csky: switch to ->regset_get()
  xtensa: switch to ->regset_get()
  parisc: switch to ->regset_get()
  nds32: switch to ->regset_get()
  nios2: switch to ->regset_get()
  hexagon: switch to ->regset_get()
  h8300: switch to ->regset_get()
  openrisc: switch to ->regset_get()
  riscv: switch to ->regset_get()
  c6x: switch to ->regset_get()
  ia64: switch to ->regset_get()
  arc: switch to ->regset_get()
  arm: switch to ->regset_get()
  sh: convert to ->regset_get()
  arm64: switch to ->regset_get()
  mips: switch to ->regset_get()
  sparc: switch to ->regset_get()
  ...
parents 995909a4 ce327e1c
...@@ -18,88 +18,61 @@ static struct callee_regs *task_callee_regs(struct task_struct *tsk) ...@@ -18,88 +18,61 @@ static struct callee_regs *task_callee_regs(struct task_struct *tsk)
static int genregs_get(struct task_struct *target, static int genregs_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
const struct pt_regs *ptregs = task_pt_regs(target); const struct pt_regs *ptregs = task_pt_regs(target);
const struct callee_regs *cregs = task_callee_regs(target); const struct callee_regs *cregs = task_callee_regs(target);
int ret = 0;
unsigned int stop_pc_val; unsigned int stop_pc_val;
#define REG_O_CHUNK(START, END, PTR) \ membuf_zero(&to, 4); // pad
if (!ret) \ membuf_store(&to, ptregs->bta);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \ membuf_store(&to, ptregs->lp_start);
offsetof(struct user_regs_struct, START), \ membuf_store(&to, ptregs->lp_end);
offsetof(struct user_regs_struct, END)); membuf_store(&to, ptregs->lp_count);
membuf_store(&to, ptregs->status32);
#define REG_O_ONE(LOC, PTR) \ membuf_store(&to, ptregs->ret);
if (!ret) \ membuf_store(&to, ptregs->blink);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \ membuf_store(&to, ptregs->fp);
offsetof(struct user_regs_struct, LOC), \ membuf_store(&to, ptregs->r26); // gp
offsetof(struct user_regs_struct, LOC) + 4); membuf_store(&to, ptregs->r12);
membuf_store(&to, ptregs->r11);
#define REG_O_ZERO(LOC) \ membuf_store(&to, ptregs->r10);
if (!ret) \ membuf_store(&to, ptregs->r9);
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \ membuf_store(&to, ptregs->r8);
offsetof(struct user_regs_struct, LOC), \ membuf_store(&to, ptregs->r7);
offsetof(struct user_regs_struct, LOC) + 4); membuf_store(&to, ptregs->r6);
membuf_store(&to, ptregs->r5);
REG_O_ZERO(pad); membuf_store(&to, ptregs->r4);
REG_O_ONE(scratch.bta, &ptregs->bta); membuf_store(&to, ptregs->r3);
REG_O_ONE(scratch.lp_start, &ptregs->lp_start); membuf_store(&to, ptregs->r2);
REG_O_ONE(scratch.lp_end, &ptregs->lp_end); membuf_store(&to, ptregs->r1);
REG_O_ONE(scratch.lp_count, &ptregs->lp_count); membuf_store(&to, ptregs->r0);
REG_O_ONE(scratch.status32, &ptregs->status32); membuf_store(&to, ptregs->sp);
REG_O_ONE(scratch.ret, &ptregs->ret); membuf_zero(&to, 4); // pad2
REG_O_ONE(scratch.blink, &ptregs->blink); membuf_store(&to, cregs->r25);
REG_O_ONE(scratch.fp, &ptregs->fp); membuf_store(&to, cregs->r24);
REG_O_ONE(scratch.gp, &ptregs->r26); membuf_store(&to, cregs->r23);
REG_O_ONE(scratch.r12, &ptregs->r12); membuf_store(&to, cregs->r22);
REG_O_ONE(scratch.r11, &ptregs->r11); membuf_store(&to, cregs->r21);
REG_O_ONE(scratch.r10, &ptregs->r10); membuf_store(&to, cregs->r20);
REG_O_ONE(scratch.r9, &ptregs->r9); membuf_store(&to, cregs->r19);
REG_O_ONE(scratch.r8, &ptregs->r8); membuf_store(&to, cregs->r18);
REG_O_ONE(scratch.r7, &ptregs->r7); membuf_store(&to, cregs->r17);
REG_O_ONE(scratch.r6, &ptregs->r6); membuf_store(&to, cregs->r16);
REG_O_ONE(scratch.r5, &ptregs->r5); membuf_store(&to, cregs->r15);
REG_O_ONE(scratch.r4, &ptregs->r4); membuf_store(&to, cregs->r14);
REG_O_ONE(scratch.r3, &ptregs->r3); membuf_store(&to, cregs->r13);
REG_O_ONE(scratch.r2, &ptregs->r2); membuf_store(&to, target->thread.fault_address); // efa
REG_O_ONE(scratch.r1, &ptregs->r1);
REG_O_ONE(scratch.r0, &ptregs->r0); if (in_brkpt_trap(ptregs)) {
REG_O_ONE(scratch.sp, &ptregs->sp); stop_pc_val = target->thread.fault_address;
pr_debug("\t\tstop_pc (brk-pt)\n");
REG_O_ZERO(pad2); } else {
stop_pc_val = ptregs->ret;
REG_O_ONE(callee.r25, &cregs->r25); pr_debug("\t\tstop_pc (others)\n");
REG_O_ONE(callee.r24, &cregs->r24);
REG_O_ONE(callee.r23, &cregs->r23);
REG_O_ONE(callee.r22, &cregs->r22);
REG_O_ONE(callee.r21, &cregs->r21);
REG_O_ONE(callee.r20, &cregs->r20);
REG_O_ONE(callee.r19, &cregs->r19);
REG_O_ONE(callee.r18, &cregs->r18);
REG_O_ONE(callee.r17, &cregs->r17);
REG_O_ONE(callee.r16, &cregs->r16);
REG_O_ONE(callee.r15, &cregs->r15);
REG_O_ONE(callee.r14, &cregs->r14);
REG_O_ONE(callee.r13, &cregs->r13);
REG_O_ONE(efa, &target->thread.fault_address);
if (!ret) {
if (in_brkpt_trap(ptregs)) {
stop_pc_val = target->thread.fault_address;
pr_debug("\t\tstop_pc (brk-pt)\n");
} else {
stop_pc_val = ptregs->ret;
pr_debug("\t\tstop_pc (others)\n");
}
REG_O_ONE(stop_pc, &stop_pc_val);
} }
return ret; return membuf_store(&to, stop_pc_val); // stop_pc
} }
static int genregs_set(struct task_struct *target, static int genregs_set(struct task_struct *target,
...@@ -184,25 +157,20 @@ static int genregs_set(struct task_struct *target, ...@@ -184,25 +157,20 @@ static int genregs_set(struct task_struct *target,
#ifdef CONFIG_ISA_ARCV2 #ifdef CONFIG_ISA_ARCV2
static int arcv2regs_get(struct task_struct *target, static int arcv2regs_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
const struct pt_regs *regs = task_pt_regs(target); const struct pt_regs *regs = task_pt_regs(target);
int ret, copy_sz;
if (IS_ENABLED(CONFIG_ARC_HAS_ACCL_REGS)) if (IS_ENABLED(CONFIG_ARC_HAS_ACCL_REGS))
copy_sz = sizeof(struct user_regs_arcv2); /*
else * itemized copy not needed like above as layout of regs (r30,r58,r59)
copy_sz = 4; /* r30 only */ * is exactly same in kernel (pt_regs) and userspace (user_regs_arcv2)
*/
return membuf_write(&to, &regs->r30, sizeof(struct user_regs_arcv2));
/*
* itemized copy not needed like above as layout of regs (r30,r58,r59)
* is exactly same in kernel (pt_regs) and userspace (user_regs_arcv2)
*/
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &regs->r30,
0, copy_sz);
return ret; membuf_write(&to, &regs->r30, 4); /* r30 only */
return membuf_zero(&to, sizeof(struct user_regs_arcv2) - 4);
} }
static int arcv2regs_set(struct task_struct *target, static int arcv2regs_set(struct task_struct *target,
...@@ -237,7 +205,7 @@ static const struct user_regset arc_regsets[] = { ...@@ -237,7 +205,7 @@ static const struct user_regset arc_regsets[] = {
.n = ELF_NGREG, .n = ELF_NGREG,
.size = sizeof(unsigned long), .size = sizeof(unsigned long),
.align = sizeof(unsigned long), .align = sizeof(unsigned long),
.get = genregs_get, .regset_get = genregs_get,
.set = genregs_set, .set = genregs_set,
}, },
#ifdef CONFIG_ISA_ARCV2 #ifdef CONFIG_ISA_ARCV2
...@@ -246,7 +214,7 @@ static const struct user_regset arc_regsets[] = { ...@@ -246,7 +214,7 @@ static const struct user_regset arc_regsets[] = {
.n = ELF_ARCV2REG, .n = ELF_ARCV2REG,
.size = sizeof(unsigned long), .size = sizeof(unsigned long),
.align = sizeof(unsigned long), .align = sizeof(unsigned long),
.get = arcv2regs_get, .regset_get = arcv2regs_get,
.set = arcv2regs_set, .set = arcv2regs_set,
}, },
#endif #endif
......
...@@ -569,14 +569,9 @@ static int ptrace_sethbpregs(struct task_struct *tsk, long num, ...@@ -569,14 +569,9 @@ static int ptrace_sethbpregs(struct task_struct *tsk, long num,
static int gpr_get(struct task_struct *target, static int gpr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct pt_regs *regs = task_pt_regs(target); return membuf_write(&to, task_pt_regs(target), sizeof(struct pt_regs));
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
regs,
0, sizeof(*regs));
} }
static int gpr_set(struct task_struct *target, static int gpr_set(struct task_struct *target,
...@@ -602,12 +597,10 @@ static int gpr_set(struct task_struct *target, ...@@ -602,12 +597,10 @@ static int gpr_set(struct task_struct *target,
static int fpa_get(struct task_struct *target, static int fpa_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, &task_thread_info(target)->fpstate,
&task_thread_info(target)->fpstate, sizeof(struct user_fp));
0, sizeof(struct user_fp));
} }
static int fpa_set(struct task_struct *target, static int fpa_set(struct task_struct *target,
...@@ -642,41 +635,20 @@ static int fpa_set(struct task_struct *target, ...@@ -642,41 +635,20 @@ static int fpa_set(struct task_struct *target,
* vfp_set() ignores this chunk * vfp_set() ignores this chunk
* *
* 1 word for the FPSCR * 1 word for the FPSCR
*
* The bounds-checking logic built into user_regset_copyout and friends
* means that we can make a simple sequence of calls to map the relevant data
* to/from the specified slice of the user regset structure.
*/ */
static int vfp_get(struct task_struct *target, static int vfp_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
int ret;
struct thread_info *thread = task_thread_info(target); struct thread_info *thread = task_thread_info(target);
struct vfp_hard_struct const *vfp = &thread->vfpstate.hard; struct vfp_hard_struct const *vfp = &thread->vfpstate.hard;
const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs);
const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr); const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr);
vfp_sync_hwstate(thread); vfp_sync_hwstate(thread);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_write(&to, vfp->fpregs, sizeof(vfp->fpregs));
&vfp->fpregs, membuf_zero(&to, user_fpscr_offset - sizeof(vfp->fpregs));
user_fpregs_offset, return membuf_store(&to, vfp->fpscr);
user_fpregs_offset + sizeof(vfp->fpregs));
if (ret)
return ret;
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
user_fpregs_offset + sizeof(vfp->fpregs),
user_fpscr_offset);
if (ret)
return ret;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&vfp->fpscr,
user_fpscr_offset,
user_fpscr_offset + sizeof(vfp->fpscr));
} }
/* /*
...@@ -739,7 +711,7 @@ static const struct user_regset arm_regsets[] = { ...@@ -739,7 +711,7 @@ static const struct user_regset arm_regsets[] = {
.n = ELF_NGREG, .n = ELF_NGREG,
.size = sizeof(u32), .size = sizeof(u32),
.align = sizeof(u32), .align = sizeof(u32),
.get = gpr_get, .regset_get = gpr_get,
.set = gpr_set .set = gpr_set
}, },
[REGSET_FPR] = { [REGSET_FPR] = {
...@@ -751,7 +723,7 @@ static const struct user_regset arm_regsets[] = { ...@@ -751,7 +723,7 @@ static const struct user_regset arm_regsets[] = {
.n = sizeof(struct user_fp) / sizeof(u32), .n = sizeof(struct user_fp) / sizeof(u32),
.size = sizeof(u32), .size = sizeof(u32),
.align = sizeof(u32), .align = sizeof(u32),
.get = fpa_get, .regset_get = fpa_get,
.set = fpa_set .set = fpa_set
}, },
#ifdef CONFIG_VFP #ifdef CONFIG_VFP
...@@ -764,7 +736,7 @@ static const struct user_regset arm_regsets[] = { ...@@ -764,7 +736,7 @@ static const struct user_regset arm_regsets[] = {
.n = ARM_VFPREGS_SIZE / sizeof(u32), .n = ARM_VFPREGS_SIZE / sizeof(u32),
.size = sizeof(u32), .size = sizeof(u32),
.align = sizeof(u32), .align = sizeof(u32),
.get = vfp_get, .regset_get = vfp_get,
.set = vfp_set .set = vfp_set
}, },
#endif /* CONFIG_VFP */ #endif /* CONFIG_VFP */
......
...@@ -474,11 +474,10 @@ static int ptrace_hbp_set_addr(unsigned int note_type, ...@@ -474,11 +474,10 @@ static int ptrace_hbp_set_addr(unsigned int note_type,
static int hw_break_get(struct task_struct *target, static int hw_break_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
unsigned int note_type = regset->core_note_type; unsigned int note_type = regset->core_note_type;
int ret, idx = 0, offset, limit; int ret, idx = 0;
u32 info, ctrl; u32 info, ctrl;
u64 addr; u64 addr;
...@@ -487,49 +486,21 @@ static int hw_break_get(struct task_struct *target, ...@@ -487,49 +486,21 @@ static int hw_break_get(struct task_struct *target,
if (ret) if (ret)
return ret; return ret;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &info, 0, membuf_write(&to, &info, sizeof(info));
sizeof(info)); membuf_zero(&to, sizeof(u32));
if (ret)
return ret;
/* Pad */
offset = offsetof(struct user_hwdebug_state, pad);
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, offset,
offset + PTRACE_HBP_PAD_SZ);
if (ret)
return ret;
/* (address, ctrl) registers */ /* (address, ctrl) registers */
offset = offsetof(struct user_hwdebug_state, dbg_regs); while (to.left) {
limit = regset->n * regset->size;
while (count && offset < limit) {
ret = ptrace_hbp_get_addr(note_type, target, idx, &addr); ret = ptrace_hbp_get_addr(note_type, target, idx, &addr);
if (ret) if (ret)
return ret; return ret;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &addr,
offset, offset + PTRACE_HBP_ADDR_SZ);
if (ret)
return ret;
offset += PTRACE_HBP_ADDR_SZ;
ret = ptrace_hbp_get_ctrl(note_type, target, idx, &ctrl); ret = ptrace_hbp_get_ctrl(note_type, target, idx, &ctrl);
if (ret) if (ret)
return ret; return ret;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &ctrl, membuf_store(&to, addr);
offset, offset + PTRACE_HBP_CTRL_SZ); membuf_store(&to, ctrl);
if (ret) membuf_zero(&to, sizeof(u32));
return ret;
offset += PTRACE_HBP_CTRL_SZ;
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
offset,
offset + PTRACE_HBP_PAD_SZ);
if (ret)
return ret;
offset += PTRACE_HBP_PAD_SZ;
idx++; idx++;
} }
return 0; return 0;
} }
...@@ -589,11 +560,10 @@ static int hw_break_set(struct task_struct *target, ...@@ -589,11 +560,10 @@ static int hw_break_set(struct task_struct *target,
static int gpr_get(struct task_struct *target, static int gpr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs; struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1); return membuf_write(&to, uregs, sizeof(*uregs));
} }
static int gpr_set(struct task_struct *target, const struct user_regset *regset, static int gpr_set(struct task_struct *target, const struct user_regset *regset,
...@@ -626,8 +596,7 @@ static int fpr_active(struct task_struct *target, const struct user_regset *regs ...@@ -626,8 +596,7 @@ static int fpr_active(struct task_struct *target, const struct user_regset *regs
*/ */
static int __fpr_get(struct task_struct *target, static int __fpr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf, unsigned int start_pos)
{ {
struct user_fpsimd_state *uregs; struct user_fpsimd_state *uregs;
...@@ -635,13 +604,11 @@ static int __fpr_get(struct task_struct *target, ...@@ -635,13 +604,11 @@ static int __fpr_get(struct task_struct *target,
uregs = &target->thread.uw.fpsimd_state; uregs = &target->thread.uw.fpsimd_state;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, return membuf_write(&to, uregs, sizeof(*uregs));
start_pos, start_pos + sizeof(*uregs));
} }
static int fpr_get(struct task_struct *target, const struct user_regset *regset, static int fpr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
if (!system_supports_fpsimd()) if (!system_supports_fpsimd())
return -EINVAL; return -EINVAL;
...@@ -649,7 +616,7 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset, ...@@ -649,7 +616,7 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
if (target == current) if (target == current)
fpsimd_preserve_current_state(); fpsimd_preserve_current_state();
return __fpr_get(target, regset, pos, count, kbuf, ubuf, 0); return __fpr_get(target, regset, to);
} }
static int __fpr_set(struct task_struct *target, static int __fpr_set(struct task_struct *target,
...@@ -699,15 +666,12 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset, ...@@ -699,15 +666,12 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
} }
static int tls_get(struct task_struct *target, const struct user_regset *regset, static int tls_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
unsigned long *tls = &target->thread.uw.tp_value;
if (target == current) if (target == current)
tls_preserve_current_state(); tls_preserve_current_state();
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, tls, 0, -1); return membuf_store(&to, target->thread.uw.tp_value);
} }
static int tls_set(struct task_struct *target, const struct user_regset *regset, static int tls_set(struct task_struct *target, const struct user_regset *regset,
...@@ -727,13 +691,9 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset, ...@@ -727,13 +691,9 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset,
static int system_call_get(struct task_struct *target, static int system_call_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
int syscallno = task_pt_regs(target)->syscallno; return membuf_store(&to, task_pt_regs(target)->syscallno);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&syscallno, 0, -1);
} }
static int system_call_set(struct task_struct *target, static int system_call_set(struct task_struct *target,
...@@ -780,24 +740,10 @@ static unsigned int sve_size_from_header(struct user_sve_header const *header) ...@@ -780,24 +740,10 @@ static unsigned int sve_size_from_header(struct user_sve_header const *header)
return ALIGN(header->size, SVE_VQ_BYTES); return ALIGN(header->size, SVE_VQ_BYTES);
} }
static unsigned int sve_get_size(struct task_struct *target,
const struct user_regset *regset)
{
struct user_sve_header header;
if (!system_supports_sve())
return 0;
sve_init_header_from_task(&header, target);
return sve_size_from_header(&header);
}
static int sve_get(struct task_struct *target, static int sve_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
int ret;
struct user_sve_header header; struct user_sve_header header;
unsigned int vq; unsigned int vq;
unsigned long start, end; unsigned long start, end;
...@@ -809,10 +755,7 @@ static int sve_get(struct task_struct *target, ...@@ -809,10 +755,7 @@ static int sve_get(struct task_struct *target,
sve_init_header_from_task(&header, target); sve_init_header_from_task(&header, target);
vq = sve_vq_from_vl(header.vl); vq = sve_vq_from_vl(header.vl);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &header, membuf_write(&to, &header, sizeof(header));
0, sizeof(header));
if (ret)
return ret;
if (target == current) if (target == current)
fpsimd_preserve_current_state(); fpsimd_preserve_current_state();
...@@ -821,26 +764,18 @@ static int sve_get(struct task_struct *target, ...@@ -821,26 +764,18 @@ static int sve_get(struct task_struct *target,
BUILD_BUG_ON(SVE_PT_FPSIMD_OFFSET != sizeof(header)); BUILD_BUG_ON(SVE_PT_FPSIMD_OFFSET != sizeof(header));
if ((header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD) if ((header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD)
return __fpr_get(target, regset, pos, count, kbuf, ubuf, return __fpr_get(target, regset, to);
SVE_PT_FPSIMD_OFFSET);
/* Otherwise: full SVE case */ /* Otherwise: full SVE case */
BUILD_BUG_ON(SVE_PT_SVE_OFFSET != sizeof(header)); BUILD_BUG_ON(SVE_PT_SVE_OFFSET != sizeof(header));
start = SVE_PT_SVE_OFFSET; start = SVE_PT_SVE_OFFSET;
end = SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq); end = SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_write(&to, target->thread.sve_state, end - start);
target->thread.sve_state,
start, end);
if (ret)
return ret;
start = end; start = end;
end = SVE_PT_SVE_FPSR_OFFSET(vq); end = SVE_PT_SVE_FPSR_OFFSET(vq);
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, membuf_zero(&to, end - start);
start, end);
if (ret)
return ret;
/* /*
* Copy fpsr, and fpcr which must follow contiguously in * Copy fpsr, and fpcr which must follow contiguously in
...@@ -848,16 +783,11 @@ static int sve_get(struct task_struct *target, ...@@ -848,16 +783,11 @@ static int sve_get(struct task_struct *target,
*/ */
start = end; start = end;
end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE; end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_write(&to, &target->thread.uw.fpsimd_state.fpsr, end - start);
&target->thread.uw.fpsimd_state.fpsr,
start, end);
if (ret)
return ret;
start = end; start = end;
end = sve_size_from_header(&header); end = sve_size_from_header(&header);
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, return membuf_zero(&to, end - start);
start, end);
} }
static int sve_set(struct task_struct *target, static int sve_set(struct task_struct *target,
...@@ -961,8 +891,7 @@ static int sve_set(struct task_struct *target, ...@@ -961,8 +891,7 @@ static int sve_set(struct task_struct *target,
#ifdef CONFIG_ARM64_PTR_AUTH #ifdef CONFIG_ARM64_PTR_AUTH
static int pac_mask_get(struct task_struct *target, static int pac_mask_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
/* /*
* The PAC bits can differ across data and instruction pointers * The PAC bits can differ across data and instruction pointers
...@@ -978,7 +907,7 @@ static int pac_mask_get(struct task_struct *target, ...@@ -978,7 +907,7 @@ static int pac_mask_get(struct task_struct *target,
if (!system_supports_address_auth()) if (!system_supports_address_auth())
return -EINVAL; return -EINVAL;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &uregs, 0, -1); return membuf_write(&to, &uregs, sizeof(uregs));
} }
#ifdef CONFIG_CHECKPOINT_RESTORE #ifdef CONFIG_CHECKPOINT_RESTORE
...@@ -1017,8 +946,7 @@ static void pac_address_keys_from_user(struct ptrauth_keys_user *keys, ...@@ -1017,8 +946,7 @@ static void pac_address_keys_from_user(struct ptrauth_keys_user *keys,
static int pac_address_keys_get(struct task_struct *target, static int pac_address_keys_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct ptrauth_keys_user *keys = &target->thread.keys_user; struct ptrauth_keys_user *keys = &target->thread.keys_user;
struct user_pac_address_keys user_keys; struct user_pac_address_keys user_keys;
...@@ -1028,8 +956,7 @@ static int pac_address_keys_get(struct task_struct *target, ...@@ -1028,8 +956,7 @@ static int pac_address_keys_get(struct task_struct *target,
pac_address_keys_to_user(&user_keys, keys); pac_address_keys_to_user(&user_keys, keys);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, &user_keys, sizeof(user_keys));
&user_keys, 0, -1);
} }
static int pac_address_keys_set(struct task_struct *target, static int pac_address_keys_set(struct task_struct *target,
...@@ -1068,8 +995,7 @@ static void pac_generic_keys_from_user(struct ptrauth_keys_user *keys, ...@@ -1068,8 +995,7 @@ static void pac_generic_keys_from_user(struct ptrauth_keys_user *keys,
static int pac_generic_keys_get(struct task_struct *target, static int pac_generic_keys_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct ptrauth_keys_user *keys = &target->thread.keys_user; struct ptrauth_keys_user *keys = &target->thread.keys_user;
struct user_pac_generic_keys user_keys; struct user_pac_generic_keys user_keys;
...@@ -1079,8 +1005,7 @@ static int pac_generic_keys_get(struct task_struct *target, ...@@ -1079,8 +1005,7 @@ static int pac_generic_keys_get(struct task_struct *target,
pac_generic_keys_to_user(&user_keys, keys); pac_generic_keys_to_user(&user_keys, keys);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, &user_keys, sizeof(user_keys));
&user_keys, 0, -1);
} }
static int pac_generic_keys_set(struct task_struct *target, static int pac_generic_keys_set(struct task_struct *target,
...@@ -1134,7 +1059,7 @@ static const struct user_regset aarch64_regsets[] = { ...@@ -1134,7 +1059,7 @@ static const struct user_regset aarch64_regsets[] = {
.n = sizeof(struct user_pt_regs) / sizeof(u64), .n = sizeof(struct user_pt_regs) / sizeof(u64),
.size = sizeof(u64), .size = sizeof(u64),
.align = sizeof(u64), .align = sizeof(u64),
.get = gpr_get, .regset_get = gpr_get,
.set = gpr_set .set = gpr_set
}, },
[REGSET_FPR] = { [REGSET_FPR] = {
...@@ -1147,7 +1072,7 @@ static const struct user_regset aarch64_regsets[] = { ...@@ -1147,7 +1072,7 @@ static const struct user_regset aarch64_regsets[] = {
.size = sizeof(u32), .size = sizeof(u32),
.align = sizeof(u32), .align = sizeof(u32),
.active = fpr_active, .active = fpr_active,
.get = fpr_get, .regset_get = fpr_get,
.set = fpr_set .set = fpr_set
}, },
[REGSET_TLS] = { [REGSET_TLS] = {
...@@ -1155,7 +1080,7 @@ static const struct user_regset aarch64_regsets[] = { ...@@ -1155,7 +1080,7 @@ static const struct user_regset aarch64_regsets[] = {
.n = 1, .n = 1,
.size = sizeof(void *), .size = sizeof(void *),
.align = sizeof(void *), .align = sizeof(void *),
.get = tls_get, .regset_get = tls_get,
.set = tls_set, .set = tls_set,
}, },
#ifdef CONFIG_HAVE_HW_BREAKPOINT #ifdef CONFIG_HAVE_HW_BREAKPOINT
...@@ -1164,7 +1089,7 @@ static const struct user_regset aarch64_regsets[] = { ...@@ -1164,7 +1089,7 @@ static const struct user_regset aarch64_regsets[] = {
.n = sizeof(struct user_hwdebug_state) / sizeof(u32), .n = sizeof(struct user_hwdebug_state) / sizeof(u32),
.size = sizeof(u32), .size = sizeof(u32),
.align = sizeof(u32), .align = sizeof(u32),
.get = hw_break_get, .regset_get = hw_break_get,
.set = hw_break_set, .set = hw_break_set,
}, },
[REGSET_HW_WATCH] = { [REGSET_HW_WATCH] = {
...@@ -1172,7 +1097,7 @@ static const struct user_regset aarch64_regsets[] = { ...@@ -1172,7 +1097,7 @@ static const struct user_regset aarch64_regsets[] = {
.n = sizeof(struct user_hwdebug_state) / sizeof(u32), .n = sizeof(struct user_hwdebug_state) / sizeof(u32),
.size = sizeof(u32), .size = sizeof(u32),
.align = sizeof(u32), .align = sizeof(u32),
.get = hw_break_get, .regset_get = hw_break_get,
.set = hw_break_set, .set = hw_break_set,
}, },
#endif #endif
...@@ -1181,7 +1106,7 @@ static const struct user_regset aarch64_regsets[] = { ...@@ -1181,7 +1106,7 @@ static const struct user_regset aarch64_regsets[] = {
.n = 1, .n = 1,
.size = sizeof(int), .size = sizeof(int),
.align = sizeof(int), .align = sizeof(int),
.get = system_call_get, .regset_get = system_call_get,
.set = system_call_set, .set = system_call_set,
}, },
#ifdef CONFIG_ARM64_SVE #ifdef CONFIG_ARM64_SVE
...@@ -1191,9 +1116,8 @@ static const struct user_regset aarch64_regsets[] = { ...@@ -1191,9 +1116,8 @@ static const struct user_regset aarch64_regsets[] = {
SVE_VQ_BYTES), SVE_VQ_BYTES),
.size = SVE_VQ_BYTES, .size = SVE_VQ_BYTES,
.align = SVE_VQ_BYTES, .align = SVE_VQ_BYTES,
.get = sve_get, .regset_get = sve_get,
.set = sve_set, .set = sve_set,
.get_size = sve_get_size,
}, },
#endif #endif
#ifdef CONFIG_ARM64_PTR_AUTH #ifdef CONFIG_ARM64_PTR_AUTH
...@@ -1202,7 +1126,7 @@ static const struct user_regset aarch64_regsets[] = { ...@@ -1202,7 +1126,7 @@ static const struct user_regset aarch64_regsets[] = {
.n = sizeof(struct user_pac_mask) / sizeof(u64), .n = sizeof(struct user_pac_mask) / sizeof(u64),
.size = sizeof(u64), .size = sizeof(u64),
.align = sizeof(u64), .align = sizeof(u64),
.get = pac_mask_get, .regset_get = pac_mask_get,
/* this cannot be set dynamically */ /* this cannot be set dynamically */
}, },
#ifdef CONFIG_CHECKPOINT_RESTORE #ifdef CONFIG_CHECKPOINT_RESTORE
...@@ -1211,7 +1135,7 @@ static const struct user_regset aarch64_regsets[] = { ...@@ -1211,7 +1135,7 @@ static const struct user_regset aarch64_regsets[] = {
.n = sizeof(struct user_pac_address_keys) / sizeof(__uint128_t), .n = sizeof(struct user_pac_address_keys) / sizeof(__uint128_t),
.size = sizeof(__uint128_t), .size = sizeof(__uint128_t),
.align = sizeof(__uint128_t), .align = sizeof(__uint128_t),
.get = pac_address_keys_get, .regset_get = pac_address_keys_get,
.set = pac_address_keys_set, .set = pac_address_keys_set,
}, },
[REGSET_PACG_KEYS] = { [REGSET_PACG_KEYS] = {
...@@ -1219,7 +1143,7 @@ static const struct user_regset aarch64_regsets[] = { ...@@ -1219,7 +1143,7 @@ static const struct user_regset aarch64_regsets[] = {
.n = sizeof(struct user_pac_generic_keys) / sizeof(__uint128_t), .n = sizeof(struct user_pac_generic_keys) / sizeof(__uint128_t),
.size = sizeof(__uint128_t), .size = sizeof(__uint128_t),
.align = sizeof(__uint128_t), .align = sizeof(__uint128_t),
.get = pac_generic_keys_get, .regset_get = pac_generic_keys_get,
.set = pac_generic_keys_set, .set = pac_generic_keys_set,
}, },
#endif #endif
...@@ -1237,57 +1161,31 @@ enum compat_regset { ...@@ -1237,57 +1161,31 @@ enum compat_regset {
REGSET_COMPAT_VFP, REGSET_COMPAT_VFP,
}; };
static int compat_gpr_get(struct task_struct *target, static inline compat_ulong_t compat_get_user_reg(struct task_struct *task, int idx)
const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{ {
int ret = 0; struct pt_regs *regs = task_pt_regs(task);
unsigned int i, start, num_regs;
/* Calculate the number of AArch32 registers contained in count */ switch (idx) {
num_regs = count / regset->size; case 15:
return regs->pc;
/* Convert pos into an register number */ case 16:
start = pos / regset->size; return pstate_to_compat_psr(regs->pstate);
case 17:
if (start + num_regs > regset->n) return regs->orig_x0;
return -EIO; default:
return regs->regs[idx];
for (i = 0; i < num_regs; ++i) {
unsigned int idx = start + i;
compat_ulong_t reg;
switch (idx) {
case 15:
reg = task_pt_regs(target)->pc;
break;
case 16:
reg = task_pt_regs(target)->pstate;
reg = pstate_to_compat_psr(reg);
break;
case 17:
reg = task_pt_regs(target)->orig_x0;
break;
default:
reg = task_pt_regs(target)->regs[idx];
}
if (kbuf) {
memcpy(kbuf, &reg, sizeof(reg));
kbuf += sizeof(reg);
} else {
ret = copy_to_user(ubuf, &reg, sizeof(reg));
if (ret) {
ret = -EFAULT;
break;
}
ubuf += sizeof(reg);
}
} }
}
return ret; static int compat_gpr_get(struct task_struct *target,
const struct user_regset *regset,
struct membuf to)
{
int i = 0;
while (to.left)
membuf_store(&to, compat_get_user_reg(target, i++));
return 0;
} }
static int compat_gpr_set(struct task_struct *target, static int compat_gpr_set(struct task_struct *target,
...@@ -1354,12 +1252,10 @@ static int compat_gpr_set(struct task_struct *target, ...@@ -1354,12 +1252,10 @@ static int compat_gpr_set(struct task_struct *target,
static int compat_vfp_get(struct task_struct *target, static int compat_vfp_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct user_fpsimd_state *uregs; struct user_fpsimd_state *uregs;
compat_ulong_t fpscr; compat_ulong_t fpscr;
int ret, vregs_end_pos;
if (!system_supports_fpsimd()) if (!system_supports_fpsimd())
return -EINVAL; return -EINVAL;
...@@ -1373,19 +1269,10 @@ static int compat_vfp_get(struct task_struct *target, ...@@ -1373,19 +1269,10 @@ static int compat_vfp_get(struct task_struct *target,
* The VFP registers are packed into the fpsimd_state, so they all sit * The VFP registers are packed into the fpsimd_state, so they all sit
* nicely together for us. We just need to create the fpscr separately. * nicely together for us. We just need to create the fpscr separately.
*/ */
vregs_end_pos = VFP_STATE_SIZE - sizeof(compat_ulong_t); membuf_write(&to, uregs, VFP_STATE_SIZE - sizeof(compat_ulong_t));
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, fpscr = (uregs->fpsr & VFP_FPSCR_STAT_MASK) |
0, vregs_end_pos); (uregs->fpcr & VFP_FPSCR_CTRL_MASK);
return membuf_store(&to, fpscr);
if (count && !ret) {
fpscr = (uregs->fpsr & VFP_FPSCR_STAT_MASK) |
(uregs->fpcr & VFP_FPSCR_CTRL_MASK);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &fpscr,
vregs_end_pos, VFP_STATE_SIZE);
}
return ret;
} }
static int compat_vfp_set(struct task_struct *target, static int compat_vfp_set(struct task_struct *target,
...@@ -1420,11 +1307,10 @@ static int compat_vfp_set(struct task_struct *target, ...@@ -1420,11 +1307,10 @@ static int compat_vfp_set(struct task_struct *target,
} }
static int compat_tls_get(struct task_struct *target, static int compat_tls_get(struct task_struct *target,
const struct user_regset *regset, unsigned int pos, const struct user_regset *regset,
unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
compat_ulong_t tls = (compat_ulong_t)target->thread.uw.tp_value; return membuf_store(&to, (compat_ulong_t)target->thread.uw.tp_value);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
} }
static int compat_tls_set(struct task_struct *target, static int compat_tls_set(struct task_struct *target,
...@@ -1449,7 +1335,7 @@ static const struct user_regset aarch32_regsets[] = { ...@@ -1449,7 +1335,7 @@ static const struct user_regset aarch32_regsets[] = {
.n = COMPAT_ELF_NGREG, .n = COMPAT_ELF_NGREG,
.size = sizeof(compat_elf_greg_t), .size = sizeof(compat_elf_greg_t),
.align = sizeof(compat_elf_greg_t), .align = sizeof(compat_elf_greg_t),
.get = compat_gpr_get, .regset_get = compat_gpr_get,
.set = compat_gpr_set .set = compat_gpr_set
}, },
[REGSET_COMPAT_VFP] = { [REGSET_COMPAT_VFP] = {
...@@ -1458,7 +1344,7 @@ static const struct user_regset aarch32_regsets[] = { ...@@ -1458,7 +1344,7 @@ static const struct user_regset aarch32_regsets[] = {
.size = sizeof(compat_ulong_t), .size = sizeof(compat_ulong_t),
.align = sizeof(compat_ulong_t), .align = sizeof(compat_ulong_t),
.active = fpr_active, .active = fpr_active,
.get = compat_vfp_get, .regset_get = compat_vfp_get,
.set = compat_vfp_set .set = compat_vfp_set
}, },
}; };
...@@ -1474,7 +1360,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = { ...@@ -1474,7 +1360,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
.n = COMPAT_ELF_NGREG, .n = COMPAT_ELF_NGREG,
.size = sizeof(compat_elf_greg_t), .size = sizeof(compat_elf_greg_t),
.align = sizeof(compat_elf_greg_t), .align = sizeof(compat_elf_greg_t),
.get = compat_gpr_get, .regset_get = compat_gpr_get,
.set = compat_gpr_set .set = compat_gpr_set
}, },
[REGSET_FPR] = { [REGSET_FPR] = {
...@@ -1482,7 +1368,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = { ...@@ -1482,7 +1368,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
.n = VFP_STATE_SIZE / sizeof(compat_ulong_t), .n = VFP_STATE_SIZE / sizeof(compat_ulong_t),
.size = sizeof(compat_ulong_t), .size = sizeof(compat_ulong_t),
.align = sizeof(compat_ulong_t), .align = sizeof(compat_ulong_t),
.get = compat_vfp_get, .regset_get = compat_vfp_get,
.set = compat_vfp_set .set = compat_vfp_set
}, },
[REGSET_TLS] = { [REGSET_TLS] = {
...@@ -1490,7 +1376,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = { ...@@ -1490,7 +1376,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
.n = 1, .n = 1,
.size = sizeof(compat_ulong_t), .size = sizeof(compat_ulong_t),
.align = sizeof(compat_ulong_t), .align = sizeof(compat_ulong_t),
.get = compat_tls_get, .regset_get = compat_tls_get,
.set = compat_tls_set, .set = compat_tls_set,
}, },
#ifdef CONFIG_HAVE_HW_BREAKPOINT #ifdef CONFIG_HAVE_HW_BREAKPOINT
...@@ -1499,7 +1385,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = { ...@@ -1499,7 +1385,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
.n = sizeof(struct user_hwdebug_state) / sizeof(u32), .n = sizeof(struct user_hwdebug_state) / sizeof(u32),
.size = sizeof(u32), .size = sizeof(u32),
.align = sizeof(u32), .align = sizeof(u32),
.get = hw_break_get, .regset_get = hw_break_get,
.set = hw_break_set, .set = hw_break_set,
}, },
[REGSET_HW_WATCH] = { [REGSET_HW_WATCH] = {
...@@ -1507,7 +1393,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = { ...@@ -1507,7 +1393,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
.n = sizeof(struct user_hwdebug_state) / sizeof(u32), .n = sizeof(struct user_hwdebug_state) / sizeof(u32),
.size = sizeof(u32), .size = sizeof(u32),
.align = sizeof(u32), .align = sizeof(u32),
.get = hw_break_get, .regset_get = hw_break_get,
.set = hw_break_set, .set = hw_break_set,
}, },
#endif #endif
...@@ -1516,7 +1402,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = { ...@@ -1516,7 +1402,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
.n = 1, .n = 1,
.size = sizeof(int), .size = sizeof(int),
.align = sizeof(int), .align = sizeof(int),
.get = system_call_get, .regset_get = system_call_get,
.set = system_call_set, .set = system_call_set,
}, },
}; };
...@@ -1541,9 +1427,7 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off, ...@@ -1541,9 +1427,7 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
else if (off == COMPAT_PT_TEXT_END_ADDR) else if (off == COMPAT_PT_TEXT_END_ADDR)
tmp = tsk->mm->end_code; tmp = tsk->mm->end_code;
else if (off < sizeof(compat_elf_gregset_t)) else if (off < sizeof(compat_elf_gregset_t))
return copy_regset_to_user(tsk, &user_aarch32_view, tmp = compat_get_user_reg(tsk, off >> 2);
REGSET_COMPAT_GPR, off,
sizeof(compat_ulong_t), ret);
else if (off >= COMPAT_USER_SZ) else if (off >= COMPAT_USER_SZ)
return -EIO; return -EIO;
else else
...@@ -1555,8 +1439,8 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off, ...@@ -1555,8 +1439,8 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off, static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
compat_ulong_t val) compat_ulong_t val)
{ {
int ret; struct pt_regs newregs = *task_pt_regs(tsk);
mm_segment_t old_fs = get_fs(); unsigned int idx = off / 4;
if (off & 3 || off >= COMPAT_USER_SZ) if (off & 3 || off >= COMPAT_USER_SZ)
return -EIO; return -EIO;
...@@ -1564,14 +1448,25 @@ static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off, ...@@ -1564,14 +1448,25 @@ static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
if (off >= sizeof(compat_elf_gregset_t)) if (off >= sizeof(compat_elf_gregset_t))
return 0; return 0;
set_fs(KERNEL_DS); switch (idx) {
ret = copy_regset_from_user(tsk, &user_aarch32_view, case 15:
REGSET_COMPAT_GPR, off, newregs.pc = val;
sizeof(compat_ulong_t), break;
&val); case 16:
set_fs(old_fs); newregs.pstate = compat_psr_to_pstate(val);
break;
case 17:
newregs.orig_x0 = val;
break;
default:
newregs.regs[idx] = val;
}
return ret; if (!valid_user_regs(&newregs.user_regs, tsk))
return -EINVAL;
*task_pt_regs(tsk) = newregs;
return 0;
} }
#ifdef CONFIG_HAVE_HW_BREAKPOINT #ifdef CONFIG_HAVE_HW_BREAKPOINT
......
...@@ -57,14 +57,9 @@ static inline int put_reg(struct task_struct *task, ...@@ -57,14 +57,9 @@ static inline int put_reg(struct task_struct *task,
static int gpr_get(struct task_struct *target, static int gpr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct pt_regs *regs = task_pt_regs(target); return membuf_write(&to, task_pt_regs(target), sizeof(struct pt_regs));
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
regs,
0, sizeof(*regs));
} }
enum c6x_regset { enum c6x_regset {
...@@ -77,7 +72,7 @@ static const struct user_regset c6x_regsets[] = { ...@@ -77,7 +72,7 @@ static const struct user_regset c6x_regsets[] = {
.n = ELF_NGREG, .n = ELF_NGREG,
.size = sizeof(u32), .size = sizeof(u32),
.align = sizeof(u32), .align = sizeof(u32),
.get = gpr_get, .regset_get = gpr_get,
}, },
}; };
......
...@@ -76,17 +76,14 @@ enum csky_regset { ...@@ -76,17 +76,14 @@ enum csky_regset {
static int gpr_get(struct task_struct *target, static int gpr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct pt_regs *regs; struct pt_regs *regs = task_pt_regs(target);
regs = task_pt_regs(target);
/* Abiv1 regs->tls is fake and we need sync here. */ /* Abiv1 regs->tls is fake and we need sync here. */
regs->tls = task_thread_info(target)->tp_value; regs->tls = task_thread_info(target)->tp_value;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, -1); return membuf_write(&to, regs, sizeof(regs));
} }
static int gpr_set(struct task_struct *target, static int gpr_set(struct task_struct *target,
...@@ -114,8 +111,7 @@ static int gpr_set(struct task_struct *target, ...@@ -114,8 +111,7 @@ static int gpr_set(struct task_struct *target,
static int fpr_get(struct task_struct *target, static int fpr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct user_fp *regs = (struct user_fp *)&target->thread.user_fp; struct user_fp *regs = (struct user_fp *)&target->thread.user_fp;
...@@ -131,9 +127,9 @@ static int fpr_get(struct task_struct *target, ...@@ -131,9 +127,9 @@ static int fpr_get(struct task_struct *target,
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
tmp.vr[64 + i] = regs->vr[32 + i]; tmp.vr[64 + i] = regs->vr[32 + i];
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tmp, 0, -1); return membuf_write(&to, &tmp, sizeof(tmp));
#else #else
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, -1); return membuf_write(&to, regs, sizeof(*regs));
#endif #endif
} }
...@@ -173,16 +169,16 @@ static const struct user_regset csky_regsets[] = { ...@@ -173,16 +169,16 @@ static const struct user_regset csky_regsets[] = {
.n = sizeof(struct pt_regs) / sizeof(u32), .n = sizeof(struct pt_regs) / sizeof(u32),
.size = sizeof(u32), .size = sizeof(u32),
.align = sizeof(u32), .align = sizeof(u32),
.get = &gpr_get, .regset_get = gpr_get,
.set = &gpr_set, .set = gpr_set,
}, },
[REGSET_FPR] = { [REGSET_FPR] = {
.core_note_type = NT_PRFPREG, .core_note_type = NT_PRFPREG,
.n = sizeof(struct user_fp) / sizeof(u32), .n = sizeof(struct user_fp) / sizeof(u32),
.size = sizeof(u32), .size = sizeof(u32),
.align = sizeof(u32), .align = sizeof(u32),
.get = &fpr_get, .regset_get = fpr_get,
.set = &fpr_set, .set = fpr_set,
}, },
}; };
......
...@@ -87,20 +87,15 @@ int h8300_put_reg(struct task_struct *task, int regno, unsigned long data) ...@@ -87,20 +87,15 @@ int h8300_put_reg(struct task_struct *task, int regno, unsigned long data)
static int regs_get(struct task_struct *target, static int regs_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
int r; int r;
struct user_regs_struct regs;
long *reg = (long *)&regs;
/* build user regs in buffer */ BUILD_BUG_ON(sizeof(struct user_regs_struct) % sizeof(long) != 0);
BUILD_BUG_ON(sizeof(regs) % sizeof(long) != 0); for (r = 0; r < ELF_NGREG; r++)
for (r = 0; r < sizeof(regs) / sizeof(long); r++) membuf_store(&to, h8300_get_reg(target, r));
*reg++ = h8300_get_reg(target, r);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return 0;
&regs, 0, sizeof(regs));
} }
static int regs_set(struct task_struct *target, static int regs_set(struct task_struct *target,
...@@ -139,7 +134,7 @@ static const struct user_regset h8300_regsets[] = { ...@@ -139,7 +134,7 @@ static const struct user_regset h8300_regsets[] = {
.n = ELF_NGREG, .n = ELF_NGREG,
.size = sizeof(long), .size = sizeof(long),
.align = sizeof(long), .align = sizeof(long),
.get = regs_get, .regset_get = regs_get,
.set = regs_set, .set = regs_set,
}, },
}; };
......
...@@ -35,58 +35,38 @@ void user_disable_single_step(struct task_struct *child) ...@@ -35,58 +35,38 @@ void user_disable_single_step(struct task_struct *child)
static int genregs_get(struct task_struct *target, static int genregs_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, srtuct membuf to)
void *kbuf, void __user *ubuf)
{ {
int ret;
unsigned int dummy;
struct pt_regs *regs = task_pt_regs(target); struct pt_regs *regs = task_pt_regs(target);
if (!regs)
return -EIO;
/* The general idea here is that the copyout must happen in /* The general idea here is that the copyout must happen in
* exactly the same order in which the userspace expects these * exactly the same order in which the userspace expects these
* regs. Now, the sequence in userspace does not match the * regs. Now, the sequence in userspace does not match the
* sequence in the kernel, so everything past the 32 gprs * sequence in the kernel, so everything past the 32 gprs
* happens one at a time. * happens one at a time.
*/ */
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_write(&to, &regs->r00, 32*sizeof(unsigned long));
&regs->r00, 0, 32*sizeof(unsigned long));
#define ONEXT(KPT_REG, USR_REG) \
if (!ret) \
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, \
KPT_REG, offsetof(struct user_regs_struct, USR_REG), \
offsetof(struct user_regs_struct, USR_REG) + \
sizeof(unsigned long));
/* Must be exactly same sequence as struct user_regs_struct */ /* Must be exactly same sequence as struct user_regs_struct */
ONEXT(&regs->sa0, sa0); membuf_store(&to, regs->sa0);
ONEXT(&regs->lc0, lc0); membuf_store(&to, regs->lc0);
ONEXT(&regs->sa1, sa1); membuf_store(&to, regs->sa1);
ONEXT(&regs->lc1, lc1); membuf_store(&to, regs->lc1);
ONEXT(&regs->m0, m0); membuf_store(&to, regs->m0);
ONEXT(&regs->m1, m1); membuf_store(&to, regs->m1);
ONEXT(&regs->usr, usr); membuf_store(&to, regs->usr);
ONEXT(&regs->preds, p3_0); membuf_store(&to, regs->p3_0);
ONEXT(&regs->gp, gp); membuf_store(&to, regs->gp);
ONEXT(&regs->ugp, ugp); membuf_store(&to, regs->ugp);
ONEXT(&pt_elr(regs), pc); membuf_store(&to, pt_elr(regs)); // pc
dummy = pt_cause(regs); membuf_store(&to, (unsigned long)pt_cause(regs)); // cause
ONEXT(&dummy, cause); membuf_store(&to, pt_badva(regs)); // badva
ONEXT(&pt_badva(regs), badva);
#if CONFIG_HEXAGON_ARCH_VERSION >=4 #if CONFIG_HEXAGON_ARCH_VERSION >=4
ONEXT(&regs->cs0, cs0); membuf_store(&to, regs->cs0);
ONEXT(&regs->cs1, cs1); membuf_store(&to, regs->cs1);
return membuf_zero(&to, sizeof(unsigned long));
#else
return membuf_zero(&to, 3 * sizeof(unsigned long));
#endif #endif
/* Pad the rest with zeros, if needed */
if (!ret)
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
offsetof(struct user_regs_struct, pad1), -1);
return ret;
} }
static int genregs_set(struct task_struct *target, static int genregs_set(struct task_struct *target,
...@@ -159,7 +139,7 @@ static const struct user_regset hexagon_regsets[] = { ...@@ -159,7 +139,7 @@ static const struct user_regset hexagon_regsets[] = {
.n = ELF_NGREG, .n = ELF_NGREG,
.size = sizeof(unsigned long), .size = sizeof(unsigned long),
.align = sizeof(unsigned long), .align = sizeof(unsigned long),
.get = genregs_get, .regset_get = genregs_get,
.set = genregs_set, .set = genregs_set,
}, },
}; };
......
...@@ -1273,52 +1273,43 @@ struct regset_getset { ...@@ -1273,52 +1273,43 @@ struct regset_getset {
int ret; int ret;
}; };
static const ptrdiff_t pt_offsets[32] =
{
#define R(n) offsetof(struct pt_regs, r##n)
[0] = -1, R(1), R(2), R(3),
[4] = -1, [5] = -1, [6] = -1, [7] = -1,
R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15),
R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
#undef R
};
static int static int
access_elf_gpreg(struct task_struct *target, struct unw_frame_info *info, access_elf_gpreg(struct task_struct *target, struct unw_frame_info *info,
unsigned long addr, unsigned long *data, int write_access) unsigned long addr, unsigned long *data, int write_access)
{ {
struct pt_regs *pt; struct pt_regs *pt = task_pt_regs(target);
unsigned long *ptr = NULL; unsigned reg = addr / sizeof(unsigned long);
int ret; ptrdiff_t d = pt_offsets[reg];
char nat = 0;
pt = task_pt_regs(target); if (d >= 0) {
switch (addr) { unsigned long *ptr = (void *)pt + d;
case ELF_GR_OFFSET(1): if (write_access)
ptr = &pt->r1; *ptr = *data;
break; else
case ELF_GR_OFFSET(2): *data = *ptr;
case ELF_GR_OFFSET(3): return 0;
ptr = (void *)&pt->r2 + (addr - ELF_GR_OFFSET(2)); } else {
break; char nat = 0;
case ELF_GR_OFFSET(4) ... ELF_GR_OFFSET(7):
if (write_access) { if (write_access) {
/* read NaT bit first: */ /* read NaT bit first: */
unsigned long dummy; unsigned long dummy;
int ret = unw_get_gr(info, reg, &dummy, &nat);
ret = unw_get_gr(info, addr/8, &dummy, &nat);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
return unw_access_gr(info, addr/8, data, &nat, write_access); return unw_access_gr(info, reg, data, &nat, write_access);
case ELF_GR_OFFSET(8) ... ELF_GR_OFFSET(11):
ptr = (void *)&pt->r8 + addr - ELF_GR_OFFSET(8);
break;
case ELF_GR_OFFSET(12):
case ELF_GR_OFFSET(13):
ptr = (void *)&pt->r12 + addr - ELF_GR_OFFSET(12);
break;
case ELF_GR_OFFSET(14):
ptr = &pt->r14;
break;
case ELF_GR_OFFSET(15):
ptr = &pt->r15;
} }
if (write_access)
*ptr = *data;
else
*data = *ptr;
return 0;
} }
static int static int
...@@ -1490,7 +1481,7 @@ static int ...@@ -1490,7 +1481,7 @@ static int
access_elf_reg(struct task_struct *target, struct unw_frame_info *info, access_elf_reg(struct task_struct *target, struct unw_frame_info *info,
unsigned long addr, unsigned long *data, int write_access) unsigned long addr, unsigned long *data, int write_access)
{ {
if (addr >= ELF_GR_OFFSET(1) && addr <= ELF_GR_OFFSET(15)) if (addr >= ELF_GR_OFFSET(1) && addr <= ELF_GR_OFFSET(31))
return access_elf_gpreg(target, info, addr, data, write_access); return access_elf_gpreg(target, info, addr, data, write_access);
else if (addr >= ELF_BR_OFFSET(0) && addr <= ELF_BR_OFFSET(7)) else if (addr >= ELF_BR_OFFSET(0) && addr <= ELF_BR_OFFSET(7))
return access_elf_breg(target, info, addr, data, write_access); return access_elf_breg(target, info, addr, data, write_access);
...@@ -1498,12 +1489,17 @@ access_elf_reg(struct task_struct *target, struct unw_frame_info *info, ...@@ -1498,12 +1489,17 @@ access_elf_reg(struct task_struct *target, struct unw_frame_info *info,
return access_elf_areg(target, info, addr, data, write_access); return access_elf_areg(target, info, addr, data, write_access);
} }
struct regset_membuf {
struct membuf to;
int ret;
};
void do_gpregs_get(struct unw_frame_info *info, void *arg) void do_gpregs_get(struct unw_frame_info *info, void *arg)
{ {
struct pt_regs *pt; struct regset_membuf *dst = arg;
struct regset_getset *dst = arg; struct membuf to = dst->to;
elf_greg_t tmp[16]; unsigned int n;
unsigned int i, index, min_copy; elf_greg_t reg;
if (unw_unwind_to_user(info) < 0) if (unw_unwind_to_user(info) < 0)
return; return;
...@@ -1521,165 +1517,53 @@ void do_gpregs_get(struct unw_frame_info *info, void *arg) ...@@ -1521,165 +1517,53 @@ void do_gpregs_get(struct unw_frame_info *info, void *arg)
/* Skip r0 */ /* Skip r0 */
if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) { membuf_zero(&to, 8);
dst->ret = user_regset_copyout_zero(&dst->pos, &dst->count, for (n = 8; to.left && n < ELF_AR_END_OFFSET; n += 8) {
&dst->u.get.kbuf, if (access_elf_reg(info->task, info, n, &reg, 0) < 0) {
&dst->u.get.ubuf, dst->ret = -EIO;
0, ELF_GR_OFFSET(1));
if (dst->ret || dst->count == 0)
return; return;
} }
membuf_store(&to, reg);
/* gr1 - gr15 */
if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) {
index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t);
min_copy = ELF_GR_OFFSET(16) > (dst->pos + dst->count) ?
(dst->pos + dst->count) : ELF_GR_OFFSET(16);
for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t),
index++)
if (access_elf_reg(dst->target, info, i,
&tmp[index], 0) < 0) {
dst->ret = -EIO;
return;
}
dst->ret = user_regset_copyout(&dst->pos, &dst->count,
&dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
ELF_GR_OFFSET(1), ELF_GR_OFFSET(16));
if (dst->ret || dst->count == 0)
return;
}
/* r16-r31 */
if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) {
pt = task_pt_regs(dst->target);
dst->ret = user_regset_copyout(&dst->pos, &dst->count,
&dst->u.get.kbuf, &dst->u.get.ubuf, &pt->r16,
ELF_GR_OFFSET(16), ELF_NAT_OFFSET);
if (dst->ret || dst->count == 0)
return;
}
/* nat, pr, b0 - b7 */
if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) {
index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t);
min_copy = ELF_CR_IIP_OFFSET > (dst->pos + dst->count) ?
(dst->pos + dst->count) : ELF_CR_IIP_OFFSET;
for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t),
index++)
if (access_elf_reg(dst->target, info, i,
&tmp[index], 0) < 0) {
dst->ret = -EIO;
return;
}
dst->ret = user_regset_copyout(&dst->pos, &dst->count,
&dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET);
if (dst->ret || dst->count == 0)
return;
}
/* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat
* ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd
*/
if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) {
index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t);
min_copy = ELF_AR_END_OFFSET > (dst->pos + dst->count) ?
(dst->pos + dst->count) : ELF_AR_END_OFFSET;
for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t),
index++)
if (access_elf_reg(dst->target, info, i,
&tmp[index], 0) < 0) {
dst->ret = -EIO;
return;
}
dst->ret = user_regset_copyout(&dst->pos, &dst->count,
&dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET);
} }
} }
void do_gpregs_set(struct unw_frame_info *info, void *arg) void do_gpregs_set(struct unw_frame_info *info, void *arg)
{ {
struct pt_regs *pt;
struct regset_getset *dst = arg; struct regset_getset *dst = arg;
elf_greg_t tmp[16];
unsigned int i, index;
if (unw_unwind_to_user(info) < 0) if (unw_unwind_to_user(info) < 0)
return; return;
if (!dst->count)
return;
/* Skip r0 */ /* Skip r0 */
if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) { if (dst->pos < ELF_GR_OFFSET(1)) {
dst->ret = user_regset_copyin_ignore(&dst->pos, &dst->count, dst->ret = user_regset_copyin_ignore(&dst->pos, &dst->count,
&dst->u.set.kbuf, &dst->u.set.kbuf,
&dst->u.set.ubuf, &dst->u.set.ubuf,
0, ELF_GR_OFFSET(1)); 0, ELF_GR_OFFSET(1));
if (dst->ret || dst->count == 0)
return;
}
/* gr1-gr15 */
if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) {
i = dst->pos;
index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t);
dst->ret = user_regset_copyin(&dst->pos, &dst->count,
&dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
ELF_GR_OFFSET(1), ELF_GR_OFFSET(16));
if (dst->ret) if (dst->ret)
return; return;
for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++)
if (access_elf_reg(dst->target, info, i,
&tmp[index], 1) < 0) {
dst->ret = -EIO;
return;
}
if (dst->count == 0)
return;
}
/* gr16-gr31 */
if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) {
pt = task_pt_regs(dst->target);
dst->ret = user_regset_copyin(&dst->pos, &dst->count,
&dst->u.set.kbuf, &dst->u.set.ubuf, &pt->r16,
ELF_GR_OFFSET(16), ELF_NAT_OFFSET);
if (dst->ret || dst->count == 0)
return;
} }
/* nat, pr, b0 - b7 */ while (dst->count && dst->pos < ELF_AR_END_OFFSET) {
if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) { unsigned int n, from, to;
i = dst->pos; elf_greg_t tmp[16];
index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t);
dst->ret = user_regset_copyin(&dst->pos, &dst->count,
&dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET);
if (dst->ret)
return;
for (; i < dst->pos; i += sizeof(elf_greg_t), index++)
if (access_elf_reg(dst->target, info, i,
&tmp[index], 1) < 0) {
dst->ret = -EIO;
return;
}
if (dst->count == 0)
return;
}
/* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat from = dst->pos;
* ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd to = from + sizeof(tmp);
*/ if (to > ELF_AR_END_OFFSET)
if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) { to = ELF_AR_END_OFFSET;
i = dst->pos; /* get up to 16 values */
index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t);
dst->ret = user_regset_copyin(&dst->pos, &dst->count, dst->ret = user_regset_copyin(&dst->pos, &dst->count,
&dst->u.set.kbuf, &dst->u.set.ubuf, tmp, &dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET); from, to);
if (dst->ret) if (dst->ret)
return; return;
for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++) /* now copy them into registers */
if (access_elf_reg(dst->target, info, i, for (n = 0; from < dst->pos; from += sizeof(elf_greg_t), n++)
&tmp[index], 1) < 0) { if (access_elf_reg(dst->target, info, from,
&tmp[n], 1) < 0) {
dst->ret = -EIO; dst->ret = -EIO;
return; return;
} }
...@@ -1690,60 +1574,36 @@ void do_gpregs_set(struct unw_frame_info *info, void *arg) ...@@ -1690,60 +1574,36 @@ void do_gpregs_set(struct unw_frame_info *info, void *arg)
void do_fpregs_get(struct unw_frame_info *info, void *arg) void do_fpregs_get(struct unw_frame_info *info, void *arg)
{ {
struct regset_getset *dst = arg; struct task_struct *task = info->task;
struct task_struct *task = dst->target; struct regset_membuf *dst = arg;
elf_fpreg_t tmp[30]; struct membuf to = dst->to;
int index, min_copy, i; elf_fpreg_t reg;
unsigned int n;
if (unw_unwind_to_user(info) < 0) if (unw_unwind_to_user(info) < 0)
return; return;
/* Skip pos 0 and 1 */ /* Skip pos 0 and 1 */
if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(2)) { membuf_zero(&to, 2 * sizeof(elf_fpreg_t));
dst->ret = user_regset_copyout_zero(&dst->pos, &dst->count,
&dst->u.get.kbuf,
&dst->u.get.ubuf,
0, ELF_FP_OFFSET(2));
if (dst->count == 0 || dst->ret)
return;
}
/* fr2-fr31 */ /* fr2-fr31 */
if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(32)) { for (n = 2; to.left && n < 32; n++) {
index = (dst->pos - ELF_FP_OFFSET(2)) / sizeof(elf_fpreg_t); if (unw_get_fr(info, n, &reg)) {
dst->ret = -EIO;
min_copy = min(((unsigned int)ELF_FP_OFFSET(32)),
dst->pos + dst->count);
for (i = dst->pos; i < min_copy; i += sizeof(elf_fpreg_t),
index++)
if (unw_get_fr(info, i / sizeof(elf_fpreg_t),
&tmp[index])) {
dst->ret = -EIO;
return;
}
dst->ret = user_regset_copyout(&dst->pos, &dst->count,
&dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
ELF_FP_OFFSET(2), ELF_FP_OFFSET(32));
if (dst->count == 0 || dst->ret)
return; return;
}
membuf_write(&to, &reg, sizeof(reg));
} }
/* fph */ /* fph */
if (dst->count > 0) { if (!to.left)
ia64_flush_fph(dst->target); return;
if (task->thread.flags & IA64_THREAD_FPH_VALID)
dst->ret = user_regset_copyout( ia64_flush_fph(task);
&dst->pos, &dst->count, if (task->thread.flags & IA64_THREAD_FPH_VALID)
&dst->u.get.kbuf, &dst->u.get.ubuf, membuf_write(&to, &task->thread.fph, 96 * sizeof(reg));
&dst->target->thread.fph, else
ELF_FP_OFFSET(32), -1); membuf_zero(&to, 96 * sizeof(reg));
else
/* Zero fill instead. */
dst->ret = user_regset_copyout_zero(
&dst->pos, &dst->count,
&dst->u.get.kbuf, &dst->u.get.ubuf,
ELF_FP_OFFSET(32), -1);
}
} }
void do_fpregs_set(struct unw_frame_info *info, void *arg) void do_fpregs_set(struct unw_frame_info *info, void *arg)
...@@ -1819,6 +1679,20 @@ void do_fpregs_set(struct unw_frame_info *info, void *arg) ...@@ -1819,6 +1679,20 @@ void do_fpregs_set(struct unw_frame_info *info, void *arg)
} }
} }
static void
unwind_and_call(void (*call)(struct unw_frame_info *, void *),
struct task_struct *target, void *data)
{
if (target == current)
unw_init_running(call, data);
else {
struct unw_frame_info info;
memset(&info, 0, sizeof(info));
unw_init_from_blocked_task(&info, target);
(*call)(&info, data);
}
}
static int static int
do_regset_call(void (*call)(struct unw_frame_info *, void *), do_regset_call(void (*call)(struct unw_frame_info *, void *),
struct task_struct *target, struct task_struct *target,
...@@ -1830,27 +1704,18 @@ do_regset_call(void (*call)(struct unw_frame_info *, void *), ...@@ -1830,27 +1704,18 @@ do_regset_call(void (*call)(struct unw_frame_info *, void *),
.pos = pos, .count = count, .pos = pos, .count = count,
.u.set = { .kbuf = kbuf, .ubuf = ubuf }, .u.set = { .kbuf = kbuf, .ubuf = ubuf },
.ret = 0 }; .ret = 0 };
unwind_and_call(call, target, &info);
if (target == current)
unw_init_running(call, &info);
else {
struct unw_frame_info ufi;
memset(&ufi, 0, sizeof(ufi));
unw_init_from_blocked_task(&ufi, target);
(*call)(&ufi, &info);
}
return info.ret; return info.ret;
} }
static int static int
gpregs_get(struct task_struct *target, gpregs_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
return do_regset_call(do_gpregs_get, target, regset, pos, count, struct regset_membuf info = {.to = to};
kbuf, ubuf); unwind_and_call(do_gpregs_get, target, &info);
return info.ret;
} }
static int gpregs_set(struct task_struct *target, static int gpregs_set(struct task_struct *target,
...@@ -1892,11 +1757,11 @@ fpregs_active(struct task_struct *target, const struct user_regset *regset) ...@@ -1892,11 +1757,11 @@ fpregs_active(struct task_struct *target, const struct user_regset *regset)
static int fpregs_get(struct task_struct *target, static int fpregs_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
return do_regset_call(do_fpregs_get, target, regset, pos, count, struct regset_membuf info = {.to = to};
kbuf, ubuf); unwind_and_call(do_fpregs_get, target, &info);
return info.ret;
} }
static int fpregs_set(struct task_struct *target, static int fpregs_set(struct task_struct *target,
...@@ -1913,7 +1778,6 @@ access_uarea(struct task_struct *child, unsigned long addr, ...@@ -1913,7 +1778,6 @@ access_uarea(struct task_struct *child, unsigned long addr,
unsigned long *data, int write_access) unsigned long *data, int write_access)
{ {
unsigned int pos = -1; /* an invalid value */ unsigned int pos = -1; /* an invalid value */
int ret;
unsigned long *ptr, regnum; unsigned long *ptr, regnum;
if ((addr & 0x7) != 0) { if ((addr & 0x7) != 0) {
...@@ -1945,14 +1809,39 @@ access_uarea(struct task_struct *child, unsigned long addr, ...@@ -1945,14 +1809,39 @@ access_uarea(struct task_struct *child, unsigned long addr,
} }
if (pos != -1) { if (pos != -1) {
if (write_access) unsigned reg = pos / sizeof(elf_fpreg_t);
ret = fpregs_set(child, NULL, pos, int which_half = (pos / sizeof(unsigned long)) & 1;
sizeof(unsigned long), data, NULL);
else if (reg < 32) { /* fr2-fr31 */
ret = fpregs_get(child, NULL, pos, struct unw_frame_info info;
sizeof(unsigned long), data, NULL); elf_fpreg_t fpreg;
if (ret != 0)
return -1; memset(&info, 0, sizeof(info));
unw_init_from_blocked_task(&info, child);
if (unw_unwind_to_user(&info) < 0)
return 0;
if (unw_get_fr(&info, reg, &fpreg))
return -1;
if (write_access) {
fpreg.u.bits[which_half] = *data;
if (unw_set_fr(&info, reg, fpreg))
return -1;
} else {
*data = fpreg.u.bits[which_half];
}
} else { /* fph */
elf_fpreg_t *p = &child->thread.fph[reg - 32];
unsigned long *bits = &p->u.bits[which_half];
ia64_sync_fph(child);
if (write_access)
*bits = *data;
else if (child->thread.flags & IA64_THREAD_FPH_VALID)
*data = *bits;
else
*data = 0;
}
return 0; return 0;
} }
...@@ -2038,15 +1927,14 @@ access_uarea(struct task_struct *child, unsigned long addr, ...@@ -2038,15 +1927,14 @@ access_uarea(struct task_struct *child, unsigned long addr,
} }
if (pos != -1) { if (pos != -1) {
if (write_access) struct unw_frame_info info;
ret = gpregs_set(child, NULL, pos,
sizeof(unsigned long), data, NULL); memset(&info, 0, sizeof(info));
else unw_init_from_blocked_task(&info, child);
ret = gpregs_get(child, NULL, pos, if (unw_unwind_to_user(&info) < 0)
sizeof(unsigned long), data, NULL); return 0;
if (ret != 0)
return -1; return access_elf_reg(child, &info, pos, data, write_access);
return 0;
} }
/* access debug registers */ /* access debug registers */
...@@ -2112,14 +2000,14 @@ static const struct user_regset native_regsets[] = { ...@@ -2112,14 +2000,14 @@ static const struct user_regset native_regsets[] = {
.core_note_type = NT_PRSTATUS, .core_note_type = NT_PRSTATUS,
.n = ELF_NGREG, .n = ELF_NGREG,
.size = sizeof(elf_greg_t), .align = sizeof(elf_greg_t), .size = sizeof(elf_greg_t), .align = sizeof(elf_greg_t),
.get = gpregs_get, .set = gpregs_set, .regset_get = gpregs_get, .set = gpregs_set,
.writeback = gpregs_writeback .writeback = gpregs_writeback
}, },
{ {
.core_note_type = NT_PRFPREG, .core_note_type = NT_PRFPREG,
.n = ELF_NFPREG, .n = ELF_NFPREG,
.size = sizeof(elf_fpreg_t), .align = sizeof(elf_fpreg_t), .size = sizeof(elf_fpreg_t), .align = sizeof(elf_fpreg_t),
.get = fpregs_get, .set = fpregs_set, .active = fpregs_active .regset_get = fpregs_get, .set = fpregs_set, .active = fpregs_active
}, },
}; };
......
...@@ -210,15 +210,13 @@ int ptrace_set_watch_regs(struct task_struct *child, ...@@ -210,15 +210,13 @@ int ptrace_set_watch_regs(struct task_struct *child,
static int gpr32_get(struct task_struct *target, static int gpr32_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct pt_regs *regs = task_pt_regs(target); struct pt_regs *regs = task_pt_regs(target);
u32 uregs[ELF_NGREG] = {}; u32 uregs[ELF_NGREG] = {};
mips_dump_regs32(uregs, regs); mips_dump_regs32(uregs, regs);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, return membuf_write(&to, uregs, sizeof(uregs));
sizeof(uregs));
} }
static int gpr32_set(struct task_struct *target, static int gpr32_set(struct task_struct *target,
...@@ -277,15 +275,13 @@ static int gpr32_set(struct task_struct *target, ...@@ -277,15 +275,13 @@ static int gpr32_set(struct task_struct *target,
static int gpr64_get(struct task_struct *target, static int gpr64_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct pt_regs *regs = task_pt_regs(target); struct pt_regs *regs = task_pt_regs(target);
u64 uregs[ELF_NGREG] = {}; u64 uregs[ELF_NGREG] = {};
mips_dump_regs64(uregs, regs); mips_dump_regs64(uregs, regs);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, return membuf_write(&to, uregs, sizeof(uregs));
sizeof(uregs));
} }
static int gpr64_set(struct task_struct *target, static int gpr64_set(struct task_struct *target,
...@@ -408,13 +404,11 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) ...@@ -408,13 +404,11 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
* !CONFIG_CPU_HAS_MSA variant. FP context's general register slots * !CONFIG_CPU_HAS_MSA variant. FP context's general register slots
* correspond 1:1 to buffer slots. Only general registers are copied. * correspond 1:1 to buffer slots. Only general registers are copied.
*/ */
static int fpr_get_fpa(struct task_struct *target, static void fpr_get_fpa(struct task_struct *target,
unsigned int *pos, unsigned int *count, struct membuf *to)
void **kbuf, void __user **ubuf)
{ {
return user_regset_copyout(pos, count, kbuf, ubuf, membuf_write(to, &target->thread.fpu,
&target->thread.fpu, NUM_FPU_REGS * sizeof(elf_fpreg_t));
0, NUM_FPU_REGS * sizeof(elf_fpreg_t));
} }
/* /*
...@@ -423,25 +417,13 @@ static int fpr_get_fpa(struct task_struct *target, ...@@ -423,25 +417,13 @@ static int fpr_get_fpa(struct task_struct *target,
* general register slots are copied to buffer slots. Only general * general register slots are copied to buffer slots. Only general
* registers are copied. * registers are copied.
*/ */
static int fpr_get_msa(struct task_struct *target, static void fpr_get_msa(struct task_struct *target, struct membuf *to)
unsigned int *pos, unsigned int *count,
void **kbuf, void __user **ubuf)
{ {
unsigned int i; unsigned int i;
u64 fpr_val;
int err;
BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t));
for (i = 0; i < NUM_FPU_REGS; i++) {
fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0);
err = user_regset_copyout(pos, count, kbuf, ubuf,
&fpr_val, i * sizeof(elf_fpreg_t),
(i + 1) * sizeof(elf_fpreg_t));
if (err)
return err;
}
return 0; BUILD_BUG_ON(sizeof(u64) != sizeof(elf_fpreg_t));
for (i = 0; i < NUM_FPU_REGS; i++)
membuf_store(to, get_fpr64(&target->thread.fpu.fpr[i], 0));
} }
/* /*
...@@ -451,31 +433,16 @@ static int fpr_get_msa(struct task_struct *target, ...@@ -451,31 +433,16 @@ static int fpr_get_msa(struct task_struct *target,
*/ */
static int fpr_get(struct task_struct *target, static int fpr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t);
const int fir_pos = fcr31_pos + sizeof(u32);
int err;
if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t))
err = fpr_get_fpa(target, &pos, &count, &kbuf, &ubuf); fpr_get_fpa(target, &to);
else else
err = fpr_get_msa(target, &pos, &count, &kbuf, &ubuf); fpr_get_msa(target, &to);
if (err)
return err;
err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.fpu.fcr31,
fcr31_pos, fcr31_pos + sizeof(u32));
if (err)
return err;
err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_write(&to, &target->thread.fpu.fcr31, sizeof(u32));
&boot_cpu_data.fpu_id, membuf_write(&to, &boot_cpu_data.fpu_id, sizeof(u32));
fir_pos, fir_pos + sizeof(u32)); return 0;
return err;
} }
/* /*
...@@ -576,14 +543,9 @@ static int fpr_set(struct task_struct *target, ...@@ -576,14 +543,9 @@ static int fpr_set(struct task_struct *target,
/* Copy the FP mode setting to the supplied NT_MIPS_FP_MODE buffer. */ /* Copy the FP mode setting to the supplied NT_MIPS_FP_MODE buffer. */
static int fp_mode_get(struct task_struct *target, static int fp_mode_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
int fp_mode; return membuf_store(&to, (int)mips_get_process_fp_mode(target));
fp_mode = mips_get_process_fp_mode(target);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &fp_mode, 0,
sizeof(fp_mode));
} }
/* /*
...@@ -630,13 +592,12 @@ struct msa_control_regs { ...@@ -630,13 +592,12 @@ struct msa_control_regs {
unsigned int msacsr; unsigned int msacsr;
}; };
static int copy_pad_fprs(struct task_struct *target, static void copy_pad_fprs(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int *ppos, unsigned int *pcount, struct membuf *to,
void **pkbuf, void __user **pubuf,
unsigned int live_sz) unsigned int live_sz)
{ {
int i, j, start, start_pad, err; int i, j;
unsigned long long fill = ~0ull; unsigned long long fill = ~0ull;
unsigned int cp_sz, pad_sz; unsigned int cp_sz, pad_sz;
...@@ -644,28 +605,16 @@ static int copy_pad_fprs(struct task_struct *target, ...@@ -644,28 +605,16 @@ static int copy_pad_fprs(struct task_struct *target,
pad_sz = regset->size - cp_sz; pad_sz = regset->size - cp_sz;
WARN_ON(pad_sz % sizeof(fill)); WARN_ON(pad_sz % sizeof(fill));
i = start = err = 0; for (i = 0; i < NUM_FPU_REGS; i++) {
for (; i < NUM_FPU_REGS; i++, start += regset->size) { membuf_write(to, &target->thread.fpu.fpr[i], cp_sz);
err |= user_regset_copyout(ppos, pcount, pkbuf, pubuf, for (j = 0; j < (pad_sz / sizeof(fill)); j++)
&target->thread.fpu.fpr[i], membuf_store(to, fill);
start, start + cp_sz);
start_pad = start + cp_sz;
for (j = 0; j < (pad_sz / sizeof(fill)); j++) {
err |= user_regset_copyout(ppos, pcount, pkbuf, pubuf,
&fill, start_pad,
start_pad + sizeof(fill));
start_pad += sizeof(fill);
}
} }
return err;
} }
static int msa_get(struct task_struct *target, static int msa_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
const unsigned int wr_size = NUM_FPU_REGS * regset->size; const unsigned int wr_size = NUM_FPU_REGS * regset->size;
const struct msa_control_regs ctrl_regs = { const struct msa_control_regs ctrl_regs = {
...@@ -674,32 +623,23 @@ static int msa_get(struct task_struct *target, ...@@ -674,32 +623,23 @@ static int msa_get(struct task_struct *target,
.msair = boot_cpu_data.msa_id, .msair = boot_cpu_data.msa_id,
.msacsr = target->thread.fpu.msacsr, .msacsr = target->thread.fpu.msacsr,
}; };
int err;
if (!tsk_used_math(target)) { if (!tsk_used_math(target)) {
/* The task hasn't used FP or MSA, fill with 0xff */ /* The task hasn't used FP or MSA, fill with 0xff */
err = copy_pad_fprs(target, regset, &pos, &count, copy_pad_fprs(target, regset, &to, 0);
&kbuf, &ubuf, 0);
} else if (!test_tsk_thread_flag(target, TIF_MSA_CTX_LIVE)) { } else if (!test_tsk_thread_flag(target, TIF_MSA_CTX_LIVE)) {
/* Copy scalar FP context, fill the rest with 0xff */ /* Copy scalar FP context, fill the rest with 0xff */
err = copy_pad_fprs(target, regset, &pos, &count, copy_pad_fprs(target, regset, &to, 8);
&kbuf, &ubuf, 8);
} else if (sizeof(target->thread.fpu.fpr[0]) == regset->size) { } else if (sizeof(target->thread.fpu.fpr[0]) == regset->size) {
/* Trivially copy the vector registers */ /* Trivially copy the vector registers */
err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_write(&to, &target->thread.fpu.fpr, wr_size);
&target->thread.fpu.fpr,
0, wr_size);
} else { } else {
/* Copy as much context as possible, fill the rest with 0xff */ /* Copy as much context as possible, fill the rest with 0xff */
err = copy_pad_fprs(target, regset, &pos, &count, copy_pad_fprs(target, regset, &to,
&kbuf, &ubuf, sizeof(target->thread.fpu.fpr[0]));
sizeof(target->thread.fpu.fpr[0]));
} }
err |= user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, &ctrl_regs, sizeof(ctrl_regs));
&ctrl_regs, wr_size,
wr_size + sizeof(ctrl_regs));
return err;
} }
static int msa_set(struct task_struct *target, static int msa_set(struct task_struct *target,
...@@ -752,34 +692,20 @@ static int msa_set(struct task_struct *target, ...@@ -752,34 +692,20 @@ static int msa_set(struct task_struct *target,
*/ */
static int dsp32_get(struct task_struct *target, static int dsp32_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
unsigned int start, num_regs, i;
u32 dspregs[NUM_DSP_REGS + 1]; u32 dspregs[NUM_DSP_REGS + 1];
unsigned int i;
BUG_ON(count % sizeof(u32)); BUG_ON(to.left % sizeof(u32));
if (!cpu_has_dsp) if (!cpu_has_dsp)
return -EIO; return -EIO;
start = pos / sizeof(u32); for (i = 0; i < NUM_DSP_REGS; i++)
num_regs = count / sizeof(u32); dspregs[i] = target->thread.dsp.dspr[i];
dspregs[NUM_DSP_REGS] = target->thread.dsp.dspcontrol;
if (start + num_regs > NUM_DSP_REGS + 1) return membuf_write(&to, dspregs, sizeof(dspregs));
return -EIO;
for (i = start; i < num_regs; i++)
switch (i) {
case 0 ... NUM_DSP_REGS - 1:
dspregs[i] = target->thread.dsp.dspr[i];
break;
case NUM_DSP_REGS:
dspregs[i] = target->thread.dsp.dspcontrol;
break;
}
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, dspregs, 0,
sizeof(dspregs));
} }
/* /*
...@@ -832,34 +758,20 @@ static int dsp32_set(struct task_struct *target, ...@@ -832,34 +758,20 @@ static int dsp32_set(struct task_struct *target,
*/ */
static int dsp64_get(struct task_struct *target, static int dsp64_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
unsigned int start, num_regs, i;
u64 dspregs[NUM_DSP_REGS + 1]; u64 dspregs[NUM_DSP_REGS + 1];
unsigned int i;
BUG_ON(count % sizeof(u64)); BUG_ON(to.left % sizeof(u64));
if (!cpu_has_dsp) if (!cpu_has_dsp)
return -EIO; return -EIO;
start = pos / sizeof(u64); for (i = 0; i < NUM_DSP_REGS; i++)
num_regs = count / sizeof(u64); dspregs[i] = target->thread.dsp.dspr[i];
dspregs[NUM_DSP_REGS] = target->thread.dsp.dspcontrol;
if (start + num_regs > NUM_DSP_REGS + 1) return membuf_write(&to, dspregs, sizeof(dspregs));
return -EIO;
for (i = start; i < num_regs; i++)
switch (i) {
case 0 ... NUM_DSP_REGS - 1:
dspregs[i] = target->thread.dsp.dspr[i];
break;
case NUM_DSP_REGS:
dspregs[i] = target->thread.dsp.dspcontrol;
break;
}
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, dspregs, 0,
sizeof(dspregs));
} }
/* /*
...@@ -1018,7 +930,7 @@ static const struct user_regset mips_regsets[] = { ...@@ -1018,7 +930,7 @@ static const struct user_regset mips_regsets[] = {
.n = ELF_NGREG, .n = ELF_NGREG,
.size = sizeof(unsigned int), .size = sizeof(unsigned int),
.align = sizeof(unsigned int), .align = sizeof(unsigned int),
.get = gpr32_get, .regset_get = gpr32_get,
.set = gpr32_set, .set = gpr32_set,
}, },
[REGSET_DSP] = { [REGSET_DSP] = {
...@@ -1026,7 +938,7 @@ static const struct user_regset mips_regsets[] = { ...@@ -1026,7 +938,7 @@ static const struct user_regset mips_regsets[] = {
.n = NUM_DSP_REGS + 1, .n = NUM_DSP_REGS + 1,
.size = sizeof(u32), .size = sizeof(u32),
.align = sizeof(u32), .align = sizeof(u32),
.get = dsp32_get, .regset_get = dsp32_get,
.set = dsp32_set, .set = dsp32_set,
.active = dsp_active, .active = dsp_active,
}, },
...@@ -1036,7 +948,7 @@ static const struct user_regset mips_regsets[] = { ...@@ -1036,7 +948,7 @@ static const struct user_regset mips_regsets[] = {
.n = ELF_NFPREG, .n = ELF_NFPREG,
.size = sizeof(elf_fpreg_t), .size = sizeof(elf_fpreg_t),
.align = sizeof(elf_fpreg_t), .align = sizeof(elf_fpreg_t),
.get = fpr_get, .regset_get = fpr_get,
.set = fpr_set, .set = fpr_set,
}, },
[REGSET_FP_MODE] = { [REGSET_FP_MODE] = {
...@@ -1044,7 +956,7 @@ static const struct user_regset mips_regsets[] = { ...@@ -1044,7 +956,7 @@ static const struct user_regset mips_regsets[] = {
.n = 1, .n = 1,
.size = sizeof(int), .size = sizeof(int),
.align = sizeof(int), .align = sizeof(int),
.get = fp_mode_get, .regset_get = fp_mode_get,
.set = fp_mode_set, .set = fp_mode_set,
}, },
#endif #endif
...@@ -1054,7 +966,7 @@ static const struct user_regset mips_regsets[] = { ...@@ -1054,7 +966,7 @@ static const struct user_regset mips_regsets[] = {
.n = NUM_FPU_REGS + 1, .n = NUM_FPU_REGS + 1,
.size = 16, .size = 16,
.align = 16, .align = 16,
.get = msa_get, .regset_get = msa_get,
.set = msa_set, .set = msa_set,
}, },
#endif #endif
...@@ -1078,7 +990,7 @@ static const struct user_regset mips64_regsets[] = { ...@@ -1078,7 +990,7 @@ static const struct user_regset mips64_regsets[] = {
.n = ELF_NGREG, .n = ELF_NGREG,
.size = sizeof(unsigned long), .size = sizeof(unsigned long),
.align = sizeof(unsigned long), .align = sizeof(unsigned long),
.get = gpr64_get, .regset_get = gpr64_get,
.set = gpr64_set, .set = gpr64_set,
}, },
[REGSET_DSP] = { [REGSET_DSP] = {
...@@ -1086,7 +998,7 @@ static const struct user_regset mips64_regsets[] = { ...@@ -1086,7 +998,7 @@ static const struct user_regset mips64_regsets[] = {
.n = NUM_DSP_REGS + 1, .n = NUM_DSP_REGS + 1,
.size = sizeof(u64), .size = sizeof(u64),
.align = sizeof(u64), .align = sizeof(u64),
.get = dsp64_get, .regset_get = dsp64_get,
.set = dsp64_set, .set = dsp64_set,
.active = dsp_active, .active = dsp_active,
}, },
...@@ -1096,7 +1008,7 @@ static const struct user_regset mips64_regsets[] = { ...@@ -1096,7 +1008,7 @@ static const struct user_regset mips64_regsets[] = {
.n = 1, .n = 1,
.size = sizeof(int), .size = sizeof(int),
.align = sizeof(int), .align = sizeof(int),
.get = fp_mode_get, .regset_get = fp_mode_get,
.set = fp_mode_set, .set = fp_mode_set,
}, },
[REGSET_FPR] = { [REGSET_FPR] = {
...@@ -1104,7 +1016,7 @@ static const struct user_regset mips64_regsets[] = { ...@@ -1104,7 +1016,7 @@ static const struct user_regset mips64_regsets[] = {
.n = ELF_NFPREG, .n = ELF_NFPREG,
.size = sizeof(elf_fpreg_t), .size = sizeof(elf_fpreg_t),
.align = sizeof(elf_fpreg_t), .align = sizeof(elf_fpreg_t),
.get = fpr_get, .regset_get = fpr_get,
.set = fpr_set, .set = fpr_set,
}, },
#endif #endif
...@@ -1114,7 +1026,7 @@ static const struct user_regset mips64_regsets[] = { ...@@ -1114,7 +1026,7 @@ static const struct user_regset mips64_regsets[] = {
.n = NUM_FPU_REGS + 1, .n = NUM_FPU_REGS + 1,
.size = 16, .size = 16,
.align = 16, .align = 16,
.get = msa_get, .regset_get = msa_get,
.set = msa_set, .set = msa_set,
}, },
#endif #endif
......
...@@ -13,11 +13,10 @@ enum nds32_regset { ...@@ -13,11 +13,10 @@ enum nds32_regset {
static int gpr_get(struct task_struct *target, static int gpr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user * ubuf)
{ {
struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs; return membuf_write(&to, &task_pt_regs(target)->user_regs,
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1); sizeof(struct user_pt_regs));
} }
static int gpr_set(struct task_struct *target, const struct user_regset *regset, static int gpr_set(struct task_struct *target, const struct user_regset *regset,
...@@ -41,7 +40,7 @@ static const struct user_regset nds32_regsets[] = { ...@@ -41,7 +40,7 @@ static const struct user_regset nds32_regsets[] = {
.n = sizeof(struct user_pt_regs) / sizeof(u32), .n = sizeof(struct user_pt_regs) / sizeof(u32),
.size = sizeof(elf_greg_t), .size = sizeof(elf_greg_t),
.align = sizeof(elf_greg_t), .align = sizeof(elf_greg_t),
.get = gpr_get, .regset_get = gpr_get,
.set = gpr_set} .set = gpr_set}
}; };
......
...@@ -21,45 +21,24 @@ ...@@ -21,45 +21,24 @@
static int genregs_get(struct task_struct *target, static int genregs_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
const struct pt_regs *regs = task_pt_regs(target); const struct pt_regs *regs = task_pt_regs(target);
const struct switch_stack *sw = (struct switch_stack *)regs - 1; const struct switch_stack *sw = (struct switch_stack *)regs - 1;
int ret = 0;
#define REG_O_ZERO_RANGE(START, END) \
if (!ret) \
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \
START * 4, (END * 4) + 4);
#define REG_O_ONE(PTR, LOC) \
if (!ret) \
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
LOC * 4, (LOC * 4) + 4);
#define REG_O_RANGE(PTR, START, END) \ membuf_zero(&to, 4); // R0
if (!ret) \ membuf_write(&to, &regs->r1, 7 * 4); // R1..R7
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \ membuf_write(&to, &regs->r8, 8 * 4); // R8..R15
START * 4, (END * 4) + 4); membuf_write(&to, sw, 8 * 4); // R16..R23
membuf_zero(&to, 2 * 4); /* et and bt */
REG_O_ZERO_RANGE(PTR_R0, PTR_R0); membuf_store(&to, regs->gp);
REG_O_RANGE(&regs->r1, PTR_R1, PTR_R7); membuf_store(&to, regs->sp);
REG_O_RANGE(&regs->r8, PTR_R8, PTR_R15); membuf_store(&to, regs->fp);
REG_O_RANGE(sw, PTR_R16, PTR_R23); membuf_store(&to, regs->ea);
REG_O_ZERO_RANGE(PTR_R24, PTR_R25); /* et and bt */ membuf_zero(&to, 4); // PTR_BA
REG_O_ONE(&regs->gp, PTR_GP); membuf_store(&to, regs->ra);
REG_O_ONE(&regs->sp, PTR_SP); membuf_store(&to, regs->ea); /* use ea for PC */
REG_O_ONE(&regs->fp, PTR_FP); return membuf_zero(&to, (NUM_PTRACE_REG - PTR_PC) * 4);
REG_O_ONE(&regs->ea, PTR_EA);
REG_O_ZERO_RANGE(PTR_BA, PTR_BA);
REG_O_ONE(&regs->ra, PTR_RA);
REG_O_ONE(&regs->ea, PTR_PC); /* use ea for PC */
if (!ret)
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
PTR_STATUS * 4, -1);
return ret;
} }
/* /*
...@@ -121,7 +100,7 @@ static const struct user_regset nios2_regsets[] = { ...@@ -121,7 +100,7 @@ static const struct user_regset nios2_regsets[] = {
.n = NUM_PTRACE_REG, .n = NUM_PTRACE_REG,
.size = sizeof(unsigned long), .size = sizeof(unsigned long),
.align = sizeof(unsigned long), .align = sizeof(unsigned long),
.get = genregs_get, .regset_get = genregs_get,
.set = genregs_set, .set = genregs_set,
} }
}; };
......
...@@ -44,29 +44,15 @@ ...@@ -44,29 +44,15 @@
*/ */
static int genregs_get(struct task_struct *target, static int genregs_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user * ubuf)
{ {
const struct pt_regs *regs = task_pt_regs(target); const struct pt_regs *regs = task_pt_regs(target);
int ret;
/* r0 */ /* r0 */
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 0, 4); membuf_zero(&to, 4);
membuf_write(&to, regs->gpr + 1, 31 * 4);
if (!ret) membuf_store(&to, regs->pc);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_store(&to, regs->sr);
regs->gpr+1, 4, 4*32);
if (!ret)
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&regs->pc, 4*32, 4*33);
if (!ret)
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&regs->sr, 4*33, 4*34);
if (!ret)
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
4*34, -1);
return ret;
} }
/* /*
...@@ -114,7 +100,7 @@ static const struct user_regset or1k_regsets[] = { ...@@ -114,7 +100,7 @@ static const struct user_regset or1k_regsets[] = {
.n = ELF_NGREG, .n = ELF_NGREG,
.size = sizeof(long), .size = sizeof(long),
.align = sizeof(long), .align = sizeof(long),
.get = genregs_get, .regset_get = genregs_get,
.set = genregs_set, .set = genregs_set,
}, },
}; };
......
...@@ -391,31 +391,11 @@ void do_syscall_trace_exit(struct pt_regs *regs) ...@@ -391,31 +391,11 @@ void do_syscall_trace_exit(struct pt_regs *regs)
static int fpr_get(struct task_struct *target, static int fpr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct pt_regs *regs = task_regs(target); struct pt_regs *regs = task_regs(target);
__u64 *k = kbuf;
__u64 __user *u = ubuf;
__u64 reg;
pos /= sizeof(reg);
count /= sizeof(reg);
if (kbuf)
for (; count > 0 && pos < ELF_NFPREG; --count)
*k++ = regs->fr[pos++];
else
for (; count > 0 && pos < ELF_NFPREG; --count)
if (__put_user(regs->fr[pos++], u++))
return -EFAULT;
kbuf = k; return membuf_write(&to, regs->fr, ELF_NFPREG * sizeof(__u64));
ubuf = u;
pos *= sizeof(reg);
count *= sizeof(reg);
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
ELF_NFPREG * sizeof(reg), -1);
} }
static int fpr_set(struct task_struct *target, static int fpr_set(struct task_struct *target,
...@@ -527,30 +507,14 @@ static void set_reg(struct pt_regs *regs, int num, unsigned long val) ...@@ -527,30 +507,14 @@ static void set_reg(struct pt_regs *regs, int num, unsigned long val)
static int gpr_get(struct task_struct *target, static int gpr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct pt_regs *regs = task_regs(target); struct pt_regs *regs = task_regs(target);
unsigned long *k = kbuf; unsigned int pos;
unsigned long __user *u = ubuf;
unsigned long reg;
pos /= sizeof(reg); for (pos = 0; pos < ELF_NGREG; pos++)
count /= sizeof(reg); membuf_store(&to, get_reg(regs, pos));
return 0;
if (kbuf)
for (; count > 0 && pos < ELF_NGREG; --count)
*k++ = get_reg(regs, pos++);
else
for (; count > 0 && pos < ELF_NGREG; --count)
if (__put_user(get_reg(regs, pos++), u++))
return -EFAULT;
kbuf = k;
ubuf = u;
pos *= sizeof(reg);
count *= sizeof(reg);
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
ELF_NGREG * sizeof(reg), -1);
} }
static int gpr_set(struct task_struct *target, static int gpr_set(struct task_struct *target,
...@@ -588,12 +552,12 @@ static const struct user_regset native_regsets[] = { ...@@ -588,12 +552,12 @@ static const struct user_regset native_regsets[] = {
[REGSET_GENERAL] = { [REGSET_GENERAL] = {
.core_note_type = NT_PRSTATUS, .n = ELF_NGREG, .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
.size = sizeof(long), .align = sizeof(long), .size = sizeof(long), .align = sizeof(long),
.get = gpr_get, .set = gpr_set .regset_get = gpr_get, .set = gpr_set
}, },
[REGSET_FP] = { [REGSET_FP] = {
.core_note_type = NT_PRFPREG, .n = ELF_NFPREG, .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
.size = sizeof(__u64), .align = sizeof(__u64), .size = sizeof(__u64), .align = sizeof(__u64),
.get = fpr_get, .set = fpr_set .regset_get = fpr_get, .set = fpr_set
} }
}; };
...@@ -607,31 +571,15 @@ static const struct user_regset_view user_parisc_native_view = { ...@@ -607,31 +571,15 @@ static const struct user_regset_view user_parisc_native_view = {
static int gpr32_get(struct task_struct *target, static int gpr32_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct pt_regs *regs = task_regs(target); struct pt_regs *regs = task_regs(target);
compat_ulong_t *k = kbuf; unsigned int pos;
compat_ulong_t __user *u = ubuf;
compat_ulong_t reg;
pos /= sizeof(reg); for (pos = 0; pos < ELF_NGREG; pos++)
count /= sizeof(reg); membuf_store(&to, (compat_ulong_t)get_reg(regs, pos));
if (kbuf) return 0;
for (; count > 0 && pos < ELF_NGREG; --count)
*k++ = get_reg(regs, pos++);
else
for (; count > 0 && pos < ELF_NGREG; --count)
if (__put_user((compat_ulong_t) get_reg(regs, pos++), u++))
return -EFAULT;
kbuf = k;
ubuf = u;
pos *= sizeof(reg);
count *= sizeof(reg);
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
ELF_NGREG * sizeof(reg), -1);
} }
static int gpr32_set(struct task_struct *target, static int gpr32_set(struct task_struct *target,
...@@ -672,12 +620,12 @@ static const struct user_regset compat_regsets[] = { ...@@ -672,12 +620,12 @@ static const struct user_regset compat_regsets[] = {
[REGSET_GENERAL] = { [REGSET_GENERAL] = {
.core_note_type = NT_PRSTATUS, .n = ELF_NGREG, .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
.size = sizeof(compat_long_t), .align = sizeof(compat_long_t), .size = sizeof(compat_long_t), .align = sizeof(compat_long_t),
.get = gpr32_get, .set = gpr32_set .regset_get = gpr32_get, .set = gpr32_set
}, },
[REGSET_FP] = { [REGSET_FP] = {
.core_note_type = NT_PRFPREG, .n = ELF_NFPREG, .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
.size = sizeof(__u64), .align = sizeof(__u64), .size = sizeof(__u64), .align = sizeof(__u64),
.get = fpr_get, .set = fpr_set .regset_get = fpr_get, .set = fpr_set
} }
}; };
......
...@@ -41,38 +41,25 @@ int vr_active(struct task_struct *target, const struct user_regset *regset) ...@@ -41,38 +41,25 @@ int vr_active(struct task_struct *target, const struct user_regset *regset)
* }; * };
*/ */
int vr_get(struct task_struct *target, const struct user_regset *regset, int vr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
int ret; union {
elf_vrreg_t reg;
u32 word;
} vrsave;
flush_altivec_to_thread(target); flush_altivec_to_thread(target);
BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) != BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
offsetof(struct thread_vr_state, vr[32])); offsetof(struct thread_vr_state, vr[32]));
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_write(&to, &target->thread.vr_state, 33 * sizeof(vector128));
&target->thread.vr_state, 0, /*
33 * sizeof(vector128)); * Copy out only the low-order word of vrsave.
if (!ret) { */
/* memset(&vrsave, 0, sizeof(vrsave));
* Copy out only the low-order word of vrsave. vrsave.word = target->thread.vrsave;
*/ return membuf_write(&to, &vrsave, sizeof(vrsave));
int start, end;
union {
elf_vrreg_t reg;
u32 word;
} vrsave;
memset(&vrsave, 0, sizeof(vrsave));
vrsave.word = target->thread.vrsave;
start = 33 * sizeof(vector128);
end = start + sizeof(vrsave);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
start, end);
}
return ret;
} }
/* /*
......
...@@ -63,8 +63,7 @@ enum powerpc_regset { ...@@ -63,8 +63,7 @@ enum powerpc_regset {
/* ptrace-(no)vsx */ /* ptrace-(no)vsx */
int fpr_get(struct task_struct *target, const struct user_regset *regset, user_regset_get2_fn fpr_get;
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
int fpr_set(struct task_struct *target, const struct user_regset *regset, int fpr_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf); const void *kbuf, const void __user *ubuf);
...@@ -72,8 +71,7 @@ int fpr_set(struct task_struct *target, const struct user_regset *regset, ...@@ -72,8 +71,7 @@ int fpr_set(struct task_struct *target, const struct user_regset *regset,
/* ptrace-vsx */ /* ptrace-vsx */
int vsr_active(struct task_struct *target, const struct user_regset *regset); int vsr_active(struct task_struct *target, const struct user_regset *regset);
int vsr_get(struct task_struct *target, const struct user_regset *regset, user_regset_get2_fn vsr_get;
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
int vsr_set(struct task_struct *target, const struct user_regset *regset, int vsr_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf); const void *kbuf, const void __user *ubuf);
...@@ -81,8 +79,7 @@ int vsr_set(struct task_struct *target, const struct user_regset *regset, ...@@ -81,8 +79,7 @@ int vsr_set(struct task_struct *target, const struct user_regset *regset,
/* ptrace-altivec */ /* ptrace-altivec */
int vr_active(struct task_struct *target, const struct user_regset *regset); int vr_active(struct task_struct *target, const struct user_regset *regset);
int vr_get(struct task_struct *target, const struct user_regset *regset, user_regset_get2_fn vr_get;
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
int vr_set(struct task_struct *target, const struct user_regset *regset, int vr_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf); const void *kbuf, const void __user *ubuf);
...@@ -90,8 +87,7 @@ int vr_set(struct task_struct *target, const struct user_regset *regset, ...@@ -90,8 +87,7 @@ int vr_set(struct task_struct *target, const struct user_regset *regset,
/* ptrace-spe */ /* ptrace-spe */
int evr_active(struct task_struct *target, const struct user_regset *regset); int evr_active(struct task_struct *target, const struct user_regset *regset);
int evr_get(struct task_struct *target, const struct user_regset *regset, user_regset_get2_fn evr_get;
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
int evr_set(struct task_struct *target, const struct user_regset *regset, int evr_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf); const void *kbuf, const void __user *ubuf);
...@@ -100,9 +96,8 @@ int evr_set(struct task_struct *target, const struct user_regset *regset, ...@@ -100,9 +96,8 @@ int evr_set(struct task_struct *target, const struct user_regset *regset,
int gpr32_get_common(struct task_struct *target, int gpr32_get_common(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to,
void *kbuf, void __user *ubuf, unsigned long *regs);
unsigned long *regs);
int gpr32_set_common(struct task_struct *target, int gpr32_set_common(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
...@@ -118,55 +113,46 @@ static inline void flush_tmregs_to_thread(struct task_struct *tsk) { } ...@@ -118,55 +113,46 @@ static inline void flush_tmregs_to_thread(struct task_struct *tsk) { }
#endif #endif
int tm_cgpr_active(struct task_struct *target, const struct user_regset *regset); int tm_cgpr_active(struct task_struct *target, const struct user_regset *regset);
int tm_cgpr_get(struct task_struct *target, const struct user_regset *regset, user_regset_get2_fn tm_cgpr_get;
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
int tm_cgpr_set(struct task_struct *target, const struct user_regset *regset, int tm_cgpr_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf); const void *kbuf, const void __user *ubuf);
int tm_cfpr_active(struct task_struct *target, const struct user_regset *regset); int tm_cfpr_active(struct task_struct *target, const struct user_regset *regset);
int tm_cfpr_get(struct task_struct *target, const struct user_regset *regset, user_regset_get2_fn tm_cfpr_get;
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
int tm_cfpr_set(struct task_struct *target, const struct user_regset *regset, int tm_cfpr_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf); const void *kbuf, const void __user *ubuf);
int tm_cvmx_active(struct task_struct *target, const struct user_regset *regset); int tm_cvmx_active(struct task_struct *target, const struct user_regset *regset);
int tm_cvmx_get(struct task_struct *target, const struct user_regset *regset, user_regset_get2_fn tm_cvmx_get;
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
int tm_cvmx_set(struct task_struct *target, const struct user_regset *regset, int tm_cvmx_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf); const void *kbuf, const void __user *ubuf);
int tm_cvsx_active(struct task_struct *target, const struct user_regset *regset); int tm_cvsx_active(struct task_struct *target, const struct user_regset *regset);
int tm_cvsx_get(struct task_struct *target, const struct user_regset *regset, user_regset_get2_fn tm_cvsx_get;
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
int tm_cvsx_set(struct task_struct *target, const struct user_regset *regset, int tm_cvsx_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf); const void *kbuf, const void __user *ubuf);
int tm_spr_active(struct task_struct *target, const struct user_regset *regset); int tm_spr_active(struct task_struct *target, const struct user_regset *regset);
int tm_spr_get(struct task_struct *target, const struct user_regset *regset, user_regset_get2_fn tm_spr_get;
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
int tm_spr_set(struct task_struct *target, const struct user_regset *regset, int tm_spr_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf); const void *kbuf, const void __user *ubuf);
int tm_tar_active(struct task_struct *target, const struct user_regset *regset); int tm_tar_active(struct task_struct *target, const struct user_regset *regset);
int tm_tar_get(struct task_struct *target, const struct user_regset *regset, user_regset_get2_fn tm_tar_get;
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
int tm_tar_set(struct task_struct *target, const struct user_regset *regset, int tm_tar_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf); const void *kbuf, const void __user *ubuf);
int tm_ppr_active(struct task_struct *target, const struct user_regset *regset); int tm_ppr_active(struct task_struct *target, const struct user_regset *regset);
int tm_ppr_get(struct task_struct *target, const struct user_regset *regset, user_regset_get2_fn tm_ppr_get;
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
int tm_ppr_set(struct task_struct *target, const struct user_regset *regset, int tm_ppr_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf); const void *kbuf, const void __user *ubuf);
int tm_dscr_active(struct task_struct *target, const struct user_regset *regset); int tm_dscr_active(struct task_struct *target, const struct user_regset *regset);
int tm_dscr_get(struct task_struct *target, const struct user_regset *regset, user_regset_get2_fn tm_dscr_get;
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
int tm_dscr_set(struct task_struct *target, const struct user_regset *regset, int tm_dscr_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf); const void *kbuf, const void __user *ubuf);
int tm_cgpr32_get(struct task_struct *target, const struct user_regset *regset, user_regset_get2_fn tm_cgpr32_get;
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
int tm_cgpr32_set(struct task_struct *target, const struct user_regset *regset, int tm_cgpr32_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf); const void *kbuf, const void __user *ubuf);
......
...@@ -19,15 +19,14 @@ ...@@ -19,15 +19,14 @@
* }; * };
*/ */
int fpr_get(struct task_struct *target, const struct user_regset *regset, int fpr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) != BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
offsetof(struct thread_fp_state, fpr[32])); offsetof(struct thread_fp_state, fpr[32]));
flush_fp_to_thread(target); flush_fp_to_thread(target);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, &target->thread.fp_state, 33 * sizeof(u64));
&target->thread.fp_state, 0, -1);
} }
/* /*
......
...@@ -23,25 +23,17 @@ int evr_active(struct task_struct *target, const struct user_regset *regset) ...@@ -23,25 +23,17 @@ int evr_active(struct task_struct *target, const struct user_regset *regset)
} }
int evr_get(struct task_struct *target, const struct user_regset *regset, int evr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
int ret;
flush_spe_to_thread(target); flush_spe_to_thread(target);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_write(&to, &target->thread.evr, sizeof(target->thread.evr));
&target->thread.evr,
0, sizeof(target->thread.evr));
BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) != BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) !=
offsetof(struct thread_struct, spefscr)); offsetof(struct thread_struct, spefscr));
if (!ret) return membuf_write(&to, &target->thread.acc,
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, sizeof(u64) + sizeof(u32));
&target->thread.acc,
sizeof(target->thread.evr), -1);
return ret;
} }
int evr_set(struct task_struct *target, const struct user_regset *regset, int evr_set(struct task_struct *target, const struct user_regset *regset,
......
...@@ -70,10 +70,7 @@ int tm_cgpr_active(struct task_struct *target, const struct user_regset *regset) ...@@ -70,10 +70,7 @@ int tm_cgpr_active(struct task_struct *target, const struct user_regset *regset)
* tm_cgpr_get - get CGPR registers * tm_cgpr_get - get CGPR registers
* @target: The target task. * @target: The target task.
* @regset: The user regset structure. * @regset: The user regset structure.
* @pos: The buffer position. * @to: Destination of copy.
* @count: Number of bytes to copy.
* @kbuf: Kernel buffer to copy from.
* @ubuf: User buffer to copy into.
* *
* This function gets transaction checkpointed GPR registers. * This function gets transaction checkpointed GPR registers.
* *
...@@ -87,10 +84,8 @@ int tm_cgpr_active(struct task_struct *target, const struct user_regset *regset) ...@@ -87,10 +84,8 @@ int tm_cgpr_active(struct task_struct *target, const struct user_regset *regset)
* }; * };
*/ */
int tm_cgpr_get(struct task_struct *target, const struct user_regset *regset, int tm_cgpr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
int ret;
if (!cpu_has_feature(CPU_FTR_TM)) if (!cpu_has_feature(CPU_FTR_TM))
return -ENODEV; return -ENODEV;
...@@ -101,31 +96,18 @@ int tm_cgpr_get(struct task_struct *target, const struct user_regset *regset, ...@@ -101,31 +96,18 @@ int tm_cgpr_get(struct task_struct *target, const struct user_regset *regset,
flush_fp_to_thread(target); flush_fp_to_thread(target);
flush_altivec_to_thread(target); flush_altivec_to_thread(target);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_write(&to, &target->thread.ckpt_regs,
&target->thread.ckpt_regs, offsetof(struct pt_regs, msr));
0, offsetof(struct pt_regs, msr)); membuf_store(&to, get_user_ckpt_msr(target));
if (!ret) {
unsigned long msr = get_user_ckpt_msr(target);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &msr,
offsetof(struct pt_regs, msr),
offsetof(struct pt_regs, msr) +
sizeof(msr));
}
BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) != BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
offsetof(struct pt_regs, msr) + sizeof(long)); offsetof(struct pt_regs, msr) + sizeof(long));
if (!ret) membuf_write(&to, &target->thread.ckpt_regs.orig_gpr3,
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, sizeof(struct user_pt_regs) -
&target->thread.ckpt_regs.orig_gpr3, offsetof(struct pt_regs, orig_gpr3));
offsetof(struct pt_regs, orig_gpr3), return membuf_zero(&to, ELF_NGREG * sizeof(unsigned long) -
sizeof(struct user_pt_regs)); sizeof(struct user_pt_regs));
if (!ret)
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
sizeof(struct user_pt_regs), -1);
return ret;
} }
/* /*
...@@ -229,10 +211,7 @@ int tm_cfpr_active(struct task_struct *target, const struct user_regset *regset) ...@@ -229,10 +211,7 @@ int tm_cfpr_active(struct task_struct *target, const struct user_regset *regset)
* tm_cfpr_get - get CFPR registers * tm_cfpr_get - get CFPR registers
* @target: The target task. * @target: The target task.
* @regset: The user regset structure. * @regset: The user regset structure.
* @pos: The buffer position. * @to: Destination of copy.
* @count: Number of bytes to copy.
* @kbuf: Kernel buffer to copy from.
* @ubuf: User buffer to copy into.
* *
* This function gets in transaction checkpointed FPR registers. * This function gets in transaction checkpointed FPR registers.
* *
...@@ -247,7 +226,7 @@ int tm_cfpr_active(struct task_struct *target, const struct user_regset *regset) ...@@ -247,7 +226,7 @@ int tm_cfpr_active(struct task_struct *target, const struct user_regset *regset)
*}; *};
*/ */
int tm_cfpr_get(struct task_struct *target, const struct user_regset *regset, int tm_cfpr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
u64 buf[33]; u64 buf[33];
int i; int i;
...@@ -266,7 +245,7 @@ int tm_cfpr_get(struct task_struct *target, const struct user_regset *regset, ...@@ -266,7 +245,7 @@ int tm_cfpr_get(struct task_struct *target, const struct user_regset *regset,
for (i = 0; i < 32 ; i++) for (i = 0; i < 32 ; i++)
buf[i] = target->thread.TS_CKFPR(i); buf[i] = target->thread.TS_CKFPR(i);
buf[32] = target->thread.ckfp_state.fpscr; buf[32] = target->thread.ckfp_state.fpscr;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1); return membuf_write(&to, buf, sizeof(buf));
} }
/** /**
...@@ -344,10 +323,7 @@ int tm_cvmx_active(struct task_struct *target, const struct user_regset *regset) ...@@ -344,10 +323,7 @@ int tm_cvmx_active(struct task_struct *target, const struct user_regset *regset)
* tm_cvmx_get - get CMVX registers * tm_cvmx_get - get CMVX registers
* @target: The target task. * @target: The target task.
* @regset: The user regset structure. * @regset: The user regset structure.
* @pos: The buffer position. * @to: Destination of copy.
* @count: Number of bytes to copy.
* @kbuf: Kernel buffer to copy from.
* @ubuf: User buffer to copy into.
* *
* This function gets in transaction checkpointed VMX registers. * This function gets in transaction checkpointed VMX registers.
* *
...@@ -363,10 +339,12 @@ int tm_cvmx_active(struct task_struct *target, const struct user_regset *regset) ...@@ -363,10 +339,12 @@ int tm_cvmx_active(struct task_struct *target, const struct user_regset *regset)
*}; *};
*/ */
int tm_cvmx_get(struct task_struct *target, const struct user_regset *regset, int tm_cvmx_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
int ret; union {
elf_vrreg_t reg;
u32 word;
} vrsave;
BUILD_BUG_ON(TVSO(vscr) != TVSO(vr[32])); BUILD_BUG_ON(TVSO(vscr) != TVSO(vr[32]));
if (!cpu_has_feature(CPU_FTR_TM)) if (!cpu_has_feature(CPU_FTR_TM))
...@@ -380,23 +358,13 @@ int tm_cvmx_get(struct task_struct *target, const struct user_regset *regset, ...@@ -380,23 +358,13 @@ int tm_cvmx_get(struct task_struct *target, const struct user_regset *regset,
flush_fp_to_thread(target); flush_fp_to_thread(target);
flush_altivec_to_thread(target); flush_altivec_to_thread(target);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.ckvr_state, membuf_write(&to, &target->thread.ckvr_state, 33 * sizeof(vector128));
0, 33 * sizeof(vector128)); /*
if (!ret) { * Copy out only the low-order word of vrsave.
/* */
* Copy out only the low-order word of vrsave. memset(&vrsave, 0, sizeof(vrsave));
*/ vrsave.word = target->thread.ckvrsave;
union { return membuf_write(&to, &vrsave, sizeof(vrsave));
elf_vrreg_t reg;
u32 word;
} vrsave;
memset(&vrsave, 0, sizeof(vrsave));
vrsave.word = target->thread.ckvrsave;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
33 * sizeof(vector128), -1);
}
return ret;
} }
/** /**
...@@ -484,10 +452,7 @@ int tm_cvsx_active(struct task_struct *target, const struct user_regset *regset) ...@@ -484,10 +452,7 @@ int tm_cvsx_active(struct task_struct *target, const struct user_regset *regset)
* tm_cvsx_get - get CVSX registers * tm_cvsx_get - get CVSX registers
* @target: The target task. * @target: The target task.
* @regset: The user regset structure. * @regset: The user regset structure.
* @pos: The buffer position. * @to: Destination of copy.
* @count: Number of bytes to copy.
* @kbuf: Kernel buffer to copy from.
* @ubuf: User buffer to copy into.
* *
* This function gets in transaction checkpointed VSX registers. * This function gets in transaction checkpointed VSX registers.
* *
...@@ -501,10 +466,10 @@ int tm_cvsx_active(struct task_struct *target, const struct user_regset *regset) ...@@ -501,10 +466,10 @@ int tm_cvsx_active(struct task_struct *target, const struct user_regset *regset)
*}; *};
*/ */
int tm_cvsx_get(struct task_struct *target, const struct user_regset *regset, int tm_cvsx_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
u64 buf[32]; u64 buf[32];
int ret, i; int i;
if (!cpu_has_feature(CPU_FTR_TM)) if (!cpu_has_feature(CPU_FTR_TM))
return -ENODEV; return -ENODEV;
...@@ -520,10 +485,7 @@ int tm_cvsx_get(struct task_struct *target, const struct user_regset *regset, ...@@ -520,10 +485,7 @@ int tm_cvsx_get(struct task_struct *target, const struct user_regset *regset,
for (i = 0; i < 32 ; i++) for (i = 0; i < 32 ; i++)
buf[i] = target->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET]; buf[i] = target->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET];
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, buf, 32 * sizeof(double));
buf, 0, 32 * sizeof(double));
return ret;
} }
/** /**
...@@ -597,10 +559,7 @@ int tm_spr_active(struct task_struct *target, const struct user_regset *regset) ...@@ -597,10 +559,7 @@ int tm_spr_active(struct task_struct *target, const struct user_regset *regset)
* tm_spr_get - get the TM related SPR registers * tm_spr_get - get the TM related SPR registers
* @target: The target task. * @target: The target task.
* @regset: The user regset structure. * @regset: The user regset structure.
* @pos: The buffer position. * @to: Destination of copy.
* @count: Number of bytes to copy.
* @kbuf: Kernel buffer to copy from.
* @ubuf: User buffer to copy into.
* *
* This function gets transactional memory related SPR registers. * This function gets transactional memory related SPR registers.
* The userspace interface buffer layout is as follows. * The userspace interface buffer layout is as follows.
...@@ -612,10 +571,8 @@ int tm_spr_active(struct task_struct *target, const struct user_regset *regset) ...@@ -612,10 +571,8 @@ int tm_spr_active(struct task_struct *target, const struct user_regset *regset)
* }; * };
*/ */
int tm_spr_get(struct task_struct *target, const struct user_regset *regset, int tm_spr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
int ret;
/* Build tests */ /* Build tests */
BUILD_BUG_ON(TSO(tm_tfhar) + sizeof(u64) != TSO(tm_texasr)); BUILD_BUG_ON(TSO(tm_tfhar) + sizeof(u64) != TSO(tm_texasr));
BUILD_BUG_ON(TSO(tm_texasr) + sizeof(u64) != TSO(tm_tfiar)); BUILD_BUG_ON(TSO(tm_texasr) + sizeof(u64) != TSO(tm_tfiar));
...@@ -630,21 +587,11 @@ int tm_spr_get(struct task_struct *target, const struct user_regset *regset, ...@@ -630,21 +587,11 @@ int tm_spr_get(struct task_struct *target, const struct user_regset *regset,
flush_altivec_to_thread(target); flush_altivec_to_thread(target);
/* TFHAR register */ /* TFHAR register */
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_write(&to, &target->thread.tm_tfhar, sizeof(u64));
&target->thread.tm_tfhar, 0, sizeof(u64));
/* TEXASR register */ /* TEXASR register */
if (!ret) membuf_write(&to, &target->thread.tm_texasr, sizeof(u64));
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.tm_texasr, sizeof(u64),
2 * sizeof(u64));
/* TFIAR register */ /* TFIAR register */
if (!ret) return membuf_write(&to, &target->thread.tm_tfiar, sizeof(u64));
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.tm_tfiar,
2 * sizeof(u64), 3 * sizeof(u64));
return ret;
} }
/** /**
...@@ -714,19 +661,15 @@ int tm_tar_active(struct task_struct *target, const struct user_regset *regset) ...@@ -714,19 +661,15 @@ int tm_tar_active(struct task_struct *target, const struct user_regset *regset)
} }
int tm_tar_get(struct task_struct *target, const struct user_regset *regset, int tm_tar_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
int ret;
if (!cpu_has_feature(CPU_FTR_TM)) if (!cpu_has_feature(CPU_FTR_TM))
return -ENODEV; return -ENODEV;
if (!MSR_TM_ACTIVE(target->thread.regs->msr)) if (!MSR_TM_ACTIVE(target->thread.regs->msr))
return -ENODATA; return -ENODATA;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, &target->thread.tm_tar, sizeof(u64));
&target->thread.tm_tar, 0, sizeof(u64));
return ret;
} }
int tm_tar_set(struct task_struct *target, const struct user_regset *regset, int tm_tar_set(struct task_struct *target, const struct user_regset *regset,
...@@ -759,19 +702,15 @@ int tm_ppr_active(struct task_struct *target, const struct user_regset *regset) ...@@ -759,19 +702,15 @@ int tm_ppr_active(struct task_struct *target, const struct user_regset *regset)
int tm_ppr_get(struct task_struct *target, const struct user_regset *regset, int tm_ppr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
int ret;
if (!cpu_has_feature(CPU_FTR_TM)) if (!cpu_has_feature(CPU_FTR_TM))
return -ENODEV; return -ENODEV;
if (!MSR_TM_ACTIVE(target->thread.regs->msr)) if (!MSR_TM_ACTIVE(target->thread.regs->msr))
return -ENODATA; return -ENODATA;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, &target->thread.tm_ppr, sizeof(u64));
&target->thread.tm_ppr, 0, sizeof(u64));
return ret;
} }
int tm_ppr_set(struct task_struct *target, const struct user_regset *regset, int tm_ppr_set(struct task_struct *target, const struct user_regset *regset,
...@@ -803,19 +742,15 @@ int tm_dscr_active(struct task_struct *target, const struct user_regset *regset) ...@@ -803,19 +742,15 @@ int tm_dscr_active(struct task_struct *target, const struct user_regset *regset)
} }
int tm_dscr_get(struct task_struct *target, const struct user_regset *regset, int tm_dscr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
int ret;
if (!cpu_has_feature(CPU_FTR_TM)) if (!cpu_has_feature(CPU_FTR_TM))
return -ENODEV; return -ENODEV;
if (!MSR_TM_ACTIVE(target->thread.regs->msr)) if (!MSR_TM_ACTIVE(target->thread.regs->msr))
return -ENODATA; return -ENODATA;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, &target->thread.tm_dscr, sizeof(u64));
&target->thread.tm_dscr, 0, sizeof(u64));
return ret;
} }
int tm_dscr_set(struct task_struct *target, const struct user_regset *regset, int tm_dscr_set(struct task_struct *target, const struct user_regset *regset,
...@@ -836,10 +771,11 @@ int tm_dscr_set(struct task_struct *target, const struct user_regset *regset, ...@@ -836,10 +771,11 @@ int tm_dscr_set(struct task_struct *target, const struct user_regset *regset,
} }
int tm_cgpr32_get(struct task_struct *target, const struct user_regset *regset, int tm_cgpr32_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
return gpr32_get_common(target, regset, pos, count, kbuf, ubuf, gpr32_get_common(target, regset, to,
&target->thread.ckpt_regs.gpr[0]); &target->thread.ckpt_regs.gpr[0]);
return membuf_zero(&to, ELF_NGREG * sizeof(u32));
} }
int tm_cgpr32_set(struct task_struct *target, const struct user_regset *regset, int tm_cgpr32_set(struct task_struct *target, const struct user_regset *regset,
......
...@@ -215,9 +215,9 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data) ...@@ -215,9 +215,9 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
} }
static int gpr_get(struct task_struct *target, const struct user_regset *regset, 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 membuf to)
{ {
int i, ret; int i;
if (target->thread.regs == NULL) if (target->thread.regs == NULL)
return -EIO; return -EIO;
...@@ -228,30 +228,17 @@ static int gpr_get(struct task_struct *target, const struct user_regset *regset, ...@@ -228,30 +228,17 @@ static int gpr_get(struct task_struct *target, const struct user_regset *regset,
target->thread.regs->gpr[i] = NV_REG_POISON; target->thread.regs->gpr[i] = NV_REG_POISON;
} }
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_write(&to, target->thread.regs, offsetof(struct pt_regs, msr));
target->thread.regs, membuf_store(&to, get_user_msr(target));
0, offsetof(struct pt_regs, msr));
if (!ret) {
unsigned long msr = get_user_msr(target);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &msr,
offsetof(struct pt_regs, msr),
offsetof(struct pt_regs, msr) +
sizeof(msr));
}
BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) != BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
offsetof(struct pt_regs, msr) + sizeof(long)); offsetof(struct pt_regs, msr) + sizeof(long));
if (!ret) membuf_write(&to, &target->thread.regs->orig_gpr3,
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, sizeof(struct user_pt_regs) -
&target->thread.regs->orig_gpr3, offsetof(struct pt_regs, orig_gpr3));
offsetof(struct pt_regs, orig_gpr3), return membuf_zero(&to, ELF_NGREG * sizeof(unsigned long) -
sizeof(struct user_pt_regs)); sizeof(struct user_pt_regs));
if (!ret)
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
sizeof(struct user_pt_regs), -1);
return ret;
} }
static int gpr_set(struct task_struct *target, const struct user_regset *regset, static int gpr_set(struct task_struct *target, const struct user_regset *regset,
...@@ -309,10 +296,9 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset, ...@@ -309,10 +296,9 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
static int ppr_get(struct task_struct *target, const struct user_regset *regset, static int ppr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, &target->thread.regs->ppr, sizeof(u64));
&target->thread.regs->ppr, 0, sizeof(u64));
} }
static int ppr_set(struct task_struct *target, const struct user_regset *regset, static int ppr_set(struct task_struct *target, const struct user_regset *regset,
...@@ -324,10 +310,9 @@ static int ppr_set(struct task_struct *target, const struct user_regset *regset, ...@@ -324,10 +310,9 @@ static int ppr_set(struct task_struct *target, const struct user_regset *regset,
} }
static int dscr_get(struct task_struct *target, const struct user_regset *regset, static int dscr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, &target->thread.dscr, sizeof(u64));
&target->thread.dscr, 0, sizeof(u64));
} }
static int dscr_set(struct task_struct *target, const struct user_regset *regset, static int dscr_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, const void *kbuf, unsigned int pos, unsigned int count, const void *kbuf,
...@@ -339,10 +324,9 @@ static int dscr_set(struct task_struct *target, const struct user_regset *regset ...@@ -339,10 +324,9 @@ static int dscr_set(struct task_struct *target, const struct user_regset *regset
#endif #endif
#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_PPC_BOOK3S_64
static int tar_get(struct task_struct *target, const struct user_regset *regset, static int tar_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, &target->thread.tar, sizeof(u64));
&target->thread.tar, 0, sizeof(u64));
} }
static int tar_set(struct task_struct *target, const struct user_regset *regset, static int tar_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, const void *kbuf, unsigned int pos, unsigned int count, const void *kbuf,
...@@ -364,7 +348,7 @@ static int ebb_active(struct task_struct *target, const struct user_regset *regs ...@@ -364,7 +348,7 @@ static int ebb_active(struct task_struct *target, const struct user_regset *regs
} }
static int ebb_get(struct task_struct *target, const struct user_regset *regset, static int ebb_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
/* Build tests */ /* Build tests */
BUILD_BUG_ON(TSO(ebbrr) + sizeof(unsigned long) != TSO(ebbhr)); BUILD_BUG_ON(TSO(ebbrr) + sizeof(unsigned long) != TSO(ebbhr));
...@@ -376,8 +360,7 @@ static int ebb_get(struct task_struct *target, const struct user_regset *regset, ...@@ -376,8 +360,7 @@ static int ebb_get(struct task_struct *target, const struct user_regset *regset,
if (!target->thread.used_ebb) if (!target->thread.used_ebb)
return -ENODATA; return -ENODATA;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.ebbrr, return membuf_write(&to, &target->thread.ebbrr, 3 * sizeof(unsigned long));
0, 3 * sizeof(unsigned long));
} }
static int ebb_set(struct task_struct *target, const struct user_regset *regset, static int ebb_set(struct task_struct *target, const struct user_regset *regset,
...@@ -420,7 +403,7 @@ static int pmu_active(struct task_struct *target, const struct user_regset *regs ...@@ -420,7 +403,7 @@ static int pmu_active(struct task_struct *target, const struct user_regset *regs
} }
static int pmu_get(struct task_struct *target, const struct user_regset *regset, static int pmu_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
/* Build tests */ /* Build tests */
BUILD_BUG_ON(TSO(siar) + sizeof(unsigned long) != TSO(sdar)); BUILD_BUG_ON(TSO(siar) + sizeof(unsigned long) != TSO(sdar));
...@@ -431,8 +414,7 @@ static int pmu_get(struct task_struct *target, const struct user_regset *regset, ...@@ -431,8 +414,7 @@ static int pmu_get(struct task_struct *target, const struct user_regset *regset,
if (!cpu_has_feature(CPU_FTR_ARCH_207S)) if (!cpu_has_feature(CPU_FTR_ARCH_207S))
return -ENODEV; return -ENODEV;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.siar, return membuf_write(&to, &target->thread.siar, 5 * sizeof(unsigned long));
0, 5 * sizeof(unsigned long));
} }
static int pmu_set(struct task_struct *target, const struct user_regset *regset, static int pmu_set(struct task_struct *target, const struct user_regset *regset,
...@@ -486,7 +468,7 @@ static int pkey_active(struct task_struct *target, const struct user_regset *reg ...@@ -486,7 +468,7 @@ static int pkey_active(struct task_struct *target, const struct user_regset *reg
} }
static int pkey_get(struct task_struct *target, const struct user_regset *regset, static int pkey_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
BUILD_BUG_ON(TSO(amr) + sizeof(unsigned long) != TSO(iamr)); BUILD_BUG_ON(TSO(amr) + sizeof(unsigned long) != TSO(iamr));
BUILD_BUG_ON(TSO(iamr) + sizeof(unsigned long) != TSO(uamor)); BUILD_BUG_ON(TSO(iamr) + sizeof(unsigned long) != TSO(uamor));
...@@ -494,8 +476,7 @@ static int pkey_get(struct task_struct *target, const struct user_regset *regset ...@@ -494,8 +476,7 @@ static int pkey_get(struct task_struct *target, const struct user_regset *regset
if (!arch_pkeys_enabled()) if (!arch_pkeys_enabled())
return -ENODEV; return -ENODEV;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.amr, return membuf_write(&to, &target->thread.amr, ELF_NPKEY * sizeof(unsigned long));
0, ELF_NPKEY * sizeof(unsigned long));
} }
static int pkey_set(struct task_struct *target, const struct user_regset *regset, static int pkey_set(struct task_struct *target, const struct user_regset *regset,
...@@ -529,110 +510,110 @@ static const struct user_regset native_regsets[] = { ...@@ -529,110 +510,110 @@ static const struct user_regset native_regsets[] = {
[REGSET_GPR] = { [REGSET_GPR] = {
.core_note_type = NT_PRSTATUS, .n = ELF_NGREG, .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
.size = sizeof(long), .align = sizeof(long), .size = sizeof(long), .align = sizeof(long),
.get = gpr_get, .set = gpr_set .regset_get = gpr_get, .set = gpr_set
}, },
[REGSET_FPR] = { [REGSET_FPR] = {
.core_note_type = NT_PRFPREG, .n = ELF_NFPREG, .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
.size = sizeof(double), .align = sizeof(double), .size = sizeof(double), .align = sizeof(double),
.get = fpr_get, .set = fpr_set .regset_get = fpr_get, .set = fpr_set
}, },
#ifdef CONFIG_ALTIVEC #ifdef CONFIG_ALTIVEC
[REGSET_VMX] = { [REGSET_VMX] = {
.core_note_type = NT_PPC_VMX, .n = 34, .core_note_type = NT_PPC_VMX, .n = 34,
.size = sizeof(vector128), .align = sizeof(vector128), .size = sizeof(vector128), .align = sizeof(vector128),
.active = vr_active, .get = vr_get, .set = vr_set .active = vr_active, .regset_get = vr_get, .set = vr_set
}, },
#endif #endif
#ifdef CONFIG_VSX #ifdef CONFIG_VSX
[REGSET_VSX] = { [REGSET_VSX] = {
.core_note_type = NT_PPC_VSX, .n = 32, .core_note_type = NT_PPC_VSX, .n = 32,
.size = sizeof(double), .align = sizeof(double), .size = sizeof(double), .align = sizeof(double),
.active = vsr_active, .get = vsr_get, .set = vsr_set .active = vsr_active, .regset_get = vsr_get, .set = vsr_set
}, },
#endif #endif
#ifdef CONFIG_SPE #ifdef CONFIG_SPE
[REGSET_SPE] = { [REGSET_SPE] = {
.core_note_type = NT_PPC_SPE, .n = 35, .core_note_type = NT_PPC_SPE, .n = 35,
.size = sizeof(u32), .align = sizeof(u32), .size = sizeof(u32), .align = sizeof(u32),
.active = evr_active, .get = evr_get, .set = evr_set .active = evr_active, .regset_get = evr_get, .set = evr_set
}, },
#endif #endif
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
[REGSET_TM_CGPR] = { [REGSET_TM_CGPR] = {
.core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG, .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG,
.size = sizeof(long), .align = sizeof(long), .size = sizeof(long), .align = sizeof(long),
.active = tm_cgpr_active, .get = tm_cgpr_get, .set = tm_cgpr_set .active = tm_cgpr_active, .regset_get = tm_cgpr_get, .set = tm_cgpr_set
}, },
[REGSET_TM_CFPR] = { [REGSET_TM_CFPR] = {
.core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG, .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,
.size = sizeof(double), .align = sizeof(double), .size = sizeof(double), .align = sizeof(double),
.active = tm_cfpr_active, .get = tm_cfpr_get, .set = tm_cfpr_set .active = tm_cfpr_active, .regset_get = tm_cfpr_get, .set = tm_cfpr_set
}, },
[REGSET_TM_CVMX] = { [REGSET_TM_CVMX] = {
.core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX, .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX,
.size = sizeof(vector128), .align = sizeof(vector128), .size = sizeof(vector128), .align = sizeof(vector128),
.active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set .active = tm_cvmx_active, .regset_get = tm_cvmx_get, .set = tm_cvmx_set
}, },
[REGSET_TM_CVSX] = { [REGSET_TM_CVSX] = {
.core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX, .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX,
.size = sizeof(double), .align = sizeof(double), .size = sizeof(double), .align = sizeof(double),
.active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set .active = tm_cvsx_active, .regset_get = tm_cvsx_get, .set = tm_cvsx_set
}, },
[REGSET_TM_SPR] = { [REGSET_TM_SPR] = {
.core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG, .core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.active = tm_spr_active, .get = tm_spr_get, .set = tm_spr_set .active = tm_spr_active, .regset_get = tm_spr_get, .set = tm_spr_set
}, },
[REGSET_TM_CTAR] = { [REGSET_TM_CTAR] = {
.core_note_type = NT_PPC_TM_CTAR, .n = 1, .core_note_type = NT_PPC_TM_CTAR, .n = 1,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.active = tm_tar_active, .get = tm_tar_get, .set = tm_tar_set .active = tm_tar_active, .regset_get = tm_tar_get, .set = tm_tar_set
}, },
[REGSET_TM_CPPR] = { [REGSET_TM_CPPR] = {
.core_note_type = NT_PPC_TM_CPPR, .n = 1, .core_note_type = NT_PPC_TM_CPPR, .n = 1,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.active = tm_ppr_active, .get = tm_ppr_get, .set = tm_ppr_set .active = tm_ppr_active, .regset_get = tm_ppr_get, .set = tm_ppr_set
}, },
[REGSET_TM_CDSCR] = { [REGSET_TM_CDSCR] = {
.core_note_type = NT_PPC_TM_CDSCR, .n = 1, .core_note_type = NT_PPC_TM_CDSCR, .n = 1,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.active = tm_dscr_active, .get = tm_dscr_get, .set = tm_dscr_set .active = tm_dscr_active, .regset_get = tm_dscr_get, .set = tm_dscr_set
}, },
#endif #endif
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
[REGSET_PPR] = { [REGSET_PPR] = {
.core_note_type = NT_PPC_PPR, .n = 1, .core_note_type = NT_PPC_PPR, .n = 1,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.get = ppr_get, .set = ppr_set .regset_get = ppr_get, .set = ppr_set
}, },
[REGSET_DSCR] = { [REGSET_DSCR] = {
.core_note_type = NT_PPC_DSCR, .n = 1, .core_note_type = NT_PPC_DSCR, .n = 1,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.get = dscr_get, .set = dscr_set .regset_get = dscr_get, .set = dscr_set
}, },
#endif #endif
#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_PPC_BOOK3S_64
[REGSET_TAR] = { [REGSET_TAR] = {
.core_note_type = NT_PPC_TAR, .n = 1, .core_note_type = NT_PPC_TAR, .n = 1,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.get = tar_get, .set = tar_set .regset_get = tar_get, .set = tar_set
}, },
[REGSET_EBB] = { [REGSET_EBB] = {
.core_note_type = NT_PPC_EBB, .n = ELF_NEBB, .core_note_type = NT_PPC_EBB, .n = ELF_NEBB,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.active = ebb_active, .get = ebb_get, .set = ebb_set .active = ebb_active, .regset_get = ebb_get, .set = ebb_set
}, },
[REGSET_PMR] = { [REGSET_PMR] = {
.core_note_type = NT_PPC_PMU, .n = ELF_NPMU, .core_note_type = NT_PPC_PMU, .n = ELF_NPMU,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.active = pmu_active, .get = pmu_get, .set = pmu_set .active = pmu_active, .regset_get = pmu_get, .set = pmu_set
}, },
#endif #endif
#ifdef CONFIG_PPC_MEM_KEYS #ifdef CONFIG_PPC_MEM_KEYS
[REGSET_PKEY] = { [REGSET_PKEY] = {
.core_note_type = NT_PPC_PKEY, .n = ELF_NPKEY, .core_note_type = NT_PPC_PKEY, .n = ELF_NPKEY,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.active = pkey_active, .get = pkey_get, .set = pkey_set .active = pkey_active, .regset_get = pkey_get, .set = pkey_set
}, },
#endif #endif
}; };
...@@ -646,49 +627,16 @@ const struct user_regset_view user_ppc_native_view = { ...@@ -646,49 +627,16 @@ const struct user_regset_view user_ppc_native_view = {
int gpr32_get_common(struct task_struct *target, int gpr32_get_common(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to, unsigned long *regs)
void *kbuf, void __user *ubuf,
unsigned long *regs)
{ {
compat_ulong_t *k = kbuf; int i;
compat_ulong_t __user *u = ubuf;
compat_ulong_t reg;
pos /= sizeof(reg);
count /= sizeof(reg);
if (kbuf)
for (; count > 0 && pos < PT_MSR; --count)
*k++ = regs[pos++];
else
for (; count > 0 && pos < PT_MSR; --count)
if (__put_user((compat_ulong_t)regs[pos++], u++))
return -EFAULT;
if (count > 0 && pos == PT_MSR) {
reg = get_user_msr(target);
if (kbuf)
*k++ = reg;
else if (__put_user(reg, u++))
return -EFAULT;
++pos;
--count;
}
if (kbuf)
for (; count > 0 && pos < PT_REGS_COUNT; --count)
*k++ = regs[pos++];
else
for (; count > 0 && pos < PT_REGS_COUNT; --count)
if (__put_user((compat_ulong_t)regs[pos++], u++))
return -EFAULT;
kbuf = k; for (i = 0; i < PT_MSR; i++)
ubuf = u; membuf_store(&to, (u32)regs[i]);
pos *= sizeof(reg); membuf_store(&to, (u32)get_user_msr(target));
count *= sizeof(reg); for (i++ ; i < PT_REGS_COUNT; i++)
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, membuf_store(&to, (u32)regs[i]);
PT_REGS_COUNT * sizeof(reg), -1); return membuf_zero(&to, (ELF_NGREG - PT_REGS_COUNT) * sizeof(u32));
} }
int gpr32_set_common(struct task_struct *target, int gpr32_set_common(struct task_struct *target,
...@@ -761,8 +709,7 @@ int gpr32_set_common(struct task_struct *target, ...@@ -761,8 +709,7 @@ int gpr32_set_common(struct task_struct *target,
static int gpr32_get(struct task_struct *target, static int gpr32_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
int i; int i;
...@@ -777,7 +724,7 @@ static int gpr32_get(struct task_struct *target, ...@@ -777,7 +724,7 @@ static int gpr32_get(struct task_struct *target,
for (i = 14; i < 32; i++) for (i = 14; i < 32; i++)
target->thread.regs->gpr[i] = NV_REG_POISON; target->thread.regs->gpr[i] = NV_REG_POISON;
} }
return gpr32_get_common(target, regset, pos, count, kbuf, ubuf, return gpr32_get_common(target, regset, to,
&target->thread.regs->gpr[0]); &target->thread.regs->gpr[0]);
} }
...@@ -801,25 +748,25 @@ static const struct user_regset compat_regsets[] = { ...@@ -801,25 +748,25 @@ static const struct user_regset compat_regsets[] = {
[REGSET_GPR] = { [REGSET_GPR] = {
.core_note_type = NT_PRSTATUS, .n = ELF_NGREG, .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
.size = sizeof(compat_long_t), .align = sizeof(compat_long_t), .size = sizeof(compat_long_t), .align = sizeof(compat_long_t),
.get = gpr32_get, .set = gpr32_set .regset_get = gpr32_get, .set = gpr32_set
}, },
[REGSET_FPR] = { [REGSET_FPR] = {
.core_note_type = NT_PRFPREG, .n = ELF_NFPREG, .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
.size = sizeof(double), .align = sizeof(double), .size = sizeof(double), .align = sizeof(double),
.get = fpr_get, .set = fpr_set .regset_get = fpr_get, .set = fpr_set
}, },
#ifdef CONFIG_ALTIVEC #ifdef CONFIG_ALTIVEC
[REGSET_VMX] = { [REGSET_VMX] = {
.core_note_type = NT_PPC_VMX, .n = 34, .core_note_type = NT_PPC_VMX, .n = 34,
.size = sizeof(vector128), .align = sizeof(vector128), .size = sizeof(vector128), .align = sizeof(vector128),
.active = vr_active, .get = vr_get, .set = vr_set .active = vr_active, .regset_get = vr_get, .set = vr_set
}, },
#endif #endif
#ifdef CONFIG_SPE #ifdef CONFIG_SPE
[REGSET_SPE] = { [REGSET_SPE] = {
.core_note_type = NT_PPC_SPE, .n = 35, .core_note_type = NT_PPC_SPE, .n = 35,
.size = sizeof(u32), .align = sizeof(u32), .size = sizeof(u32), .align = sizeof(u32),
.active = evr_active, .get = evr_get, .set = evr_set .active = evr_active, .regset_get = evr_get, .set = evr_set
}, },
#endif #endif
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
...@@ -827,66 +774,66 @@ static const struct user_regset compat_regsets[] = { ...@@ -827,66 +774,66 @@ static const struct user_regset compat_regsets[] = {
.core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG, .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG,
.size = sizeof(long), .align = sizeof(long), .size = sizeof(long), .align = sizeof(long),
.active = tm_cgpr_active, .active = tm_cgpr_active,
.get = tm_cgpr32_get, .set = tm_cgpr32_set .regset_get = tm_cgpr32_get, .set = tm_cgpr32_set
}, },
[REGSET_TM_CFPR] = { [REGSET_TM_CFPR] = {
.core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG, .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,
.size = sizeof(double), .align = sizeof(double), .size = sizeof(double), .align = sizeof(double),
.active = tm_cfpr_active, .get = tm_cfpr_get, .set = tm_cfpr_set .active = tm_cfpr_active, .regset_get = tm_cfpr_get, .set = tm_cfpr_set
}, },
[REGSET_TM_CVMX] = { [REGSET_TM_CVMX] = {
.core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX, .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX,
.size = sizeof(vector128), .align = sizeof(vector128), .size = sizeof(vector128), .align = sizeof(vector128),
.active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set .active = tm_cvmx_active, .regset_get = tm_cvmx_get, .set = tm_cvmx_set
}, },
[REGSET_TM_CVSX] = { [REGSET_TM_CVSX] = {
.core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX, .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX,
.size = sizeof(double), .align = sizeof(double), .size = sizeof(double), .align = sizeof(double),
.active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set .active = tm_cvsx_active, .regset_get = tm_cvsx_get, .set = tm_cvsx_set
}, },
[REGSET_TM_SPR] = { [REGSET_TM_SPR] = {
.core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG, .core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.active = tm_spr_active, .get = tm_spr_get, .set = tm_spr_set .active = tm_spr_active, .regset_get = tm_spr_get, .set = tm_spr_set
}, },
[REGSET_TM_CTAR] = { [REGSET_TM_CTAR] = {
.core_note_type = NT_PPC_TM_CTAR, .n = 1, .core_note_type = NT_PPC_TM_CTAR, .n = 1,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.active = tm_tar_active, .get = tm_tar_get, .set = tm_tar_set .active = tm_tar_active, .regset_get = tm_tar_get, .set = tm_tar_set
}, },
[REGSET_TM_CPPR] = { [REGSET_TM_CPPR] = {
.core_note_type = NT_PPC_TM_CPPR, .n = 1, .core_note_type = NT_PPC_TM_CPPR, .n = 1,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.active = tm_ppr_active, .get = tm_ppr_get, .set = tm_ppr_set .active = tm_ppr_active, .regset_get = tm_ppr_get, .set = tm_ppr_set
}, },
[REGSET_TM_CDSCR] = { [REGSET_TM_CDSCR] = {
.core_note_type = NT_PPC_TM_CDSCR, .n = 1, .core_note_type = NT_PPC_TM_CDSCR, .n = 1,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.active = tm_dscr_active, .get = tm_dscr_get, .set = tm_dscr_set .active = tm_dscr_active, .regset_get = tm_dscr_get, .set = tm_dscr_set
}, },
#endif #endif
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
[REGSET_PPR] = { [REGSET_PPR] = {
.core_note_type = NT_PPC_PPR, .n = 1, .core_note_type = NT_PPC_PPR, .n = 1,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.get = ppr_get, .set = ppr_set .regset_get = ppr_get, .set = ppr_set
}, },
[REGSET_DSCR] = { [REGSET_DSCR] = {
.core_note_type = NT_PPC_DSCR, .n = 1, .core_note_type = NT_PPC_DSCR, .n = 1,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.get = dscr_get, .set = dscr_set .regset_get = dscr_get, .set = dscr_set
}, },
#endif #endif
#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_PPC_BOOK3S_64
[REGSET_TAR] = { [REGSET_TAR] = {
.core_note_type = NT_PPC_TAR, .n = 1, .core_note_type = NT_PPC_TAR, .n = 1,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.get = tar_get, .set = tar_set .regset_get = tar_get, .set = tar_set
}, },
[REGSET_EBB] = { [REGSET_EBB] = {
.core_note_type = NT_PPC_EBB, .n = ELF_NEBB, .core_note_type = NT_PPC_EBB, .n = ELF_NEBB,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.active = ebb_active, .get = ebb_get, .set = ebb_set .active = ebb_active, .regset_get = ebb_get, .set = ebb_set
}, },
#endif #endif
}; };
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
* }; * };
*/ */
int fpr_get(struct task_struct *target, const struct user_regset *regset, int fpr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
u64 buf[33]; u64 buf[33];
int i; int i;
...@@ -30,7 +30,7 @@ int fpr_get(struct task_struct *target, const struct user_regset *regset, ...@@ -30,7 +30,7 @@ int fpr_get(struct task_struct *target, const struct user_regset *regset,
for (i = 0; i < 32 ; i++) for (i = 0; i < 32 ; i++)
buf[i] = target->thread.TS_FPR(i); buf[i] = target->thread.TS_FPR(i);
buf[32] = target->thread.fp_state.fpscr; buf[32] = target->thread.fp_state.fpscr;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1); return membuf_write(&to, buf, 33 * sizeof(u64));
} }
/* /*
...@@ -95,10 +95,10 @@ int vsr_active(struct task_struct *target, const struct user_regset *regset) ...@@ -95,10 +95,10 @@ int vsr_active(struct task_struct *target, const struct user_regset *regset)
* }; * };
*/ */
int vsr_get(struct task_struct *target, const struct user_regset *regset, int vsr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
u64 buf[32]; u64 buf[32];
int ret, i; int i;
flush_tmregs_to_thread(target); flush_tmregs_to_thread(target);
flush_fp_to_thread(target); flush_fp_to_thread(target);
...@@ -108,10 +108,7 @@ int vsr_get(struct task_struct *target, const struct user_regset *regset, ...@@ -108,10 +108,7 @@ int vsr_get(struct task_struct *target, const struct user_regset *regset,
for (i = 0; i < 32 ; i++) for (i = 0; i < 32 ; i++)
buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET]; buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET];
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, buf, 32 * sizeof(double));
buf, 0, 32 * sizeof(double));
return ret;
} }
/* /*
......
...@@ -30,13 +30,10 @@ enum riscv_regset { ...@@ -30,13 +30,10 @@ enum riscv_regset {
static int riscv_gpr_get(struct task_struct *target, static int riscv_gpr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct pt_regs *regs; return membuf_write(&to, task_pt_regs(target),
sizeof(struct user_regs_struct));
regs = task_pt_regs(target);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
} }
static int riscv_gpr_set(struct task_struct *target, static int riscv_gpr_set(struct task_struct *target,
...@@ -55,21 +52,13 @@ static int riscv_gpr_set(struct task_struct *target, ...@@ -55,21 +52,13 @@ static int riscv_gpr_set(struct task_struct *target,
#ifdef CONFIG_FPU #ifdef CONFIG_FPU
static int riscv_fpr_get(struct task_struct *target, static int riscv_fpr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
int ret;
struct __riscv_d_ext_state *fstate = &target->thread.fstate; struct __riscv_d_ext_state *fstate = &target->thread.fstate;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, fstate, 0, membuf_write(&to, fstate, offsetof(struct __riscv_d_ext_state, fcsr));
offsetof(struct __riscv_d_ext_state, fcsr)); membuf_store(&to, fstate->fcsr);
if (!ret) { return membuf_zero(&to, 4); // explicitly pad
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, fstate, 0,
offsetof(struct __riscv_d_ext_state, fcsr) +
sizeof(fstate->fcsr));
}
return ret;
} }
static int riscv_fpr_set(struct task_struct *target, static int riscv_fpr_set(struct task_struct *target,
...@@ -98,8 +87,8 @@ static const struct user_regset riscv_user_regset[] = { ...@@ -98,8 +87,8 @@ static const struct user_regset riscv_user_regset[] = {
.n = ELF_NGREG, .n = ELF_NGREG,
.size = sizeof(elf_greg_t), .size = sizeof(elf_greg_t),
.align = sizeof(elf_greg_t), .align = sizeof(elf_greg_t),
.get = &riscv_gpr_get, .regset_get = riscv_gpr_get,
.set = &riscv_gpr_set, .set = riscv_gpr_set,
}, },
#ifdef CONFIG_FPU #ifdef CONFIG_FPU
[REGSET_F] = { [REGSET_F] = {
...@@ -107,8 +96,8 @@ static const struct user_regset riscv_user_regset[] = { ...@@ -107,8 +96,8 @@ static const struct user_regset riscv_user_regset[] = {
.n = ELF_NFPREG, .n = ELF_NFPREG,
.size = sizeof(elf_fpreg_t), .size = sizeof(elf_fpreg_t),
.align = sizeof(elf_fpreg_t), .align = sizeof(elf_fpreg_t),
.get = &riscv_fpr_get, .regset_get = riscv_fpr_get,
.set = &riscv_fpr_set, .set = riscv_fpr_set,
}, },
#endif #endif
}; };
......
...@@ -945,28 +945,14 @@ asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) ...@@ -945,28 +945,14 @@ asmlinkage void do_syscall_trace_exit(struct pt_regs *regs)
static int s390_regs_get(struct task_struct *target, static int s390_regs_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
unsigned pos;
if (target == current) if (target == current)
save_access_regs(target->thread.acrs); save_access_regs(target->thread.acrs);
if (kbuf) { for (pos = 0; pos < sizeof(s390_regs); pos += sizeof(long))
unsigned long *k = kbuf; membuf_store(&to, __peek_user(target, pos));
while (count > 0) {
*k++ = __peek_user(target, pos);
count -= sizeof(*k);
pos += sizeof(*k);
}
} else {
unsigned long __user *u = ubuf;
while (count > 0) {
if (__put_user(__peek_user(target, pos), u++))
return -EFAULT;
count -= sizeof(*u);
pos += sizeof(*u);
}
}
return 0; return 0;
} }
...@@ -1007,8 +993,8 @@ static int s390_regs_set(struct task_struct *target, ...@@ -1007,8 +993,8 @@ static int s390_regs_set(struct task_struct *target,
} }
static int s390_fpregs_get(struct task_struct *target, static int s390_fpregs_get(struct task_struct *target,
const struct user_regset *regset, unsigned int pos, const struct user_regset *regset,
unsigned int count, void *kbuf, void __user *ubuf) struct membuf to)
{ {
_s390_fp_regs fp_regs; _s390_fp_regs fp_regs;
...@@ -1018,8 +1004,7 @@ static int s390_fpregs_get(struct task_struct *target, ...@@ -1018,8 +1004,7 @@ static int s390_fpregs_get(struct task_struct *target,
fp_regs.fpc = target->thread.fpu.fpc; fp_regs.fpc = target->thread.fpu.fpc;
fpregs_store(&fp_regs, &target->thread.fpu); fpregs_store(&fp_regs, &target->thread.fpu);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, &fp_regs, sizeof(fp_regs));
&fp_regs, 0, -1);
} }
static int s390_fpregs_set(struct task_struct *target, static int s390_fpregs_set(struct task_struct *target,
...@@ -1066,20 +1051,9 @@ static int s390_fpregs_set(struct task_struct *target, ...@@ -1066,20 +1051,9 @@ static int s390_fpregs_set(struct task_struct *target,
static int s390_last_break_get(struct task_struct *target, static int s390_last_break_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
if (count > 0) { return membuf_store(&to, target->thread.last_break);
if (kbuf) {
unsigned long *k = kbuf;
*k = target->thread.last_break;
} else {
unsigned long __user *u = ubuf;
if (__put_user(target->thread.last_break, u))
return -EFAULT;
}
}
return 0;
} }
static int s390_last_break_set(struct task_struct *target, static int s390_last_break_set(struct task_struct *target,
...@@ -1092,16 +1066,13 @@ static int s390_last_break_set(struct task_struct *target, ...@@ -1092,16 +1066,13 @@ static int s390_last_break_set(struct task_struct *target,
static int s390_tdb_get(struct task_struct *target, static int s390_tdb_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct pt_regs *regs = task_pt_regs(target); struct pt_regs *regs = task_pt_regs(target);
unsigned char *data;
if (!(regs->int_code & 0x200)) if (!(regs->int_code & 0x200))
return -ENODATA; return -ENODATA;
data = target->thread.trap_tdb; return membuf_write(&to, target->thread.trap_tdb, 256);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, data, 0, 256);
} }
static int s390_tdb_set(struct task_struct *target, static int s390_tdb_set(struct task_struct *target,
...@@ -1114,8 +1085,7 @@ static int s390_tdb_set(struct task_struct *target, ...@@ -1114,8 +1085,7 @@ static int s390_tdb_set(struct task_struct *target,
static int s390_vxrs_low_get(struct task_struct *target, static int s390_vxrs_low_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
__u64 vxrs[__NUM_VXRS_LOW]; __u64 vxrs[__NUM_VXRS_LOW];
int i; int i;
...@@ -1126,7 +1096,7 @@ static int s390_vxrs_low_get(struct task_struct *target, ...@@ -1126,7 +1096,7 @@ static int s390_vxrs_low_get(struct task_struct *target,
save_fpu_regs(); save_fpu_regs();
for (i = 0; i < __NUM_VXRS_LOW; i++) for (i = 0; i < __NUM_VXRS_LOW; i++)
vxrs[i] = *((__u64 *)(target->thread.fpu.vxrs + i) + 1); vxrs[i] = *((__u64 *)(target->thread.fpu.vxrs + i) + 1);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1); return membuf_write(&to, vxrs, sizeof(vxrs));
} }
static int s390_vxrs_low_set(struct task_struct *target, static int s390_vxrs_low_set(struct task_struct *target,
...@@ -1155,18 +1125,14 @@ static int s390_vxrs_low_set(struct task_struct *target, ...@@ -1155,18 +1125,14 @@ static int s390_vxrs_low_set(struct task_struct *target,
static int s390_vxrs_high_get(struct task_struct *target, static int s390_vxrs_high_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
__vector128 vxrs[__NUM_VXRS_HIGH];
if (!MACHINE_HAS_VX) if (!MACHINE_HAS_VX)
return -ENODEV; return -ENODEV;
if (target == current) if (target == current)
save_fpu_regs(); save_fpu_regs();
memcpy(vxrs, target->thread.fpu.vxrs + __NUM_VXRS_LOW, sizeof(vxrs)); return membuf_write(&to, target->thread.fpu.vxrs + __NUM_VXRS_LOW,
__NUM_VXRS_HIGH * sizeof(__vector128));
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1);
} }
static int s390_vxrs_high_set(struct task_struct *target, static int s390_vxrs_high_set(struct task_struct *target,
...@@ -1188,12 +1154,9 @@ static int s390_vxrs_high_set(struct task_struct *target, ...@@ -1188,12 +1154,9 @@ static int s390_vxrs_high_set(struct task_struct *target,
static int s390_system_call_get(struct task_struct *target, static int s390_system_call_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
unsigned int *data = &target->thread.system_call; return membuf_store(&to, target->thread.system_call);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
data, 0, sizeof(unsigned int));
} }
static int s390_system_call_set(struct task_struct *target, static int s390_system_call_set(struct task_struct *target,
...@@ -1208,8 +1171,7 @@ static int s390_system_call_set(struct task_struct *target, ...@@ -1208,8 +1171,7 @@ static int s390_system_call_set(struct task_struct *target,
static int s390_gs_cb_get(struct task_struct *target, static int s390_gs_cb_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct gs_cb *data = target->thread.gs_cb; struct gs_cb *data = target->thread.gs_cb;
...@@ -1219,8 +1181,7 @@ static int s390_gs_cb_get(struct task_struct *target, ...@@ -1219,8 +1181,7 @@ static int s390_gs_cb_get(struct task_struct *target,
return -ENODATA; return -ENODATA;
if (target == current) if (target == current)
save_gs_cb(data); save_gs_cb(data);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, data, sizeof(struct gs_cb));
data, 0, sizeof(struct gs_cb));
} }
static int s390_gs_cb_set(struct task_struct *target, static int s390_gs_cb_set(struct task_struct *target,
...@@ -1264,8 +1225,7 @@ static int s390_gs_cb_set(struct task_struct *target, ...@@ -1264,8 +1225,7 @@ static int s390_gs_cb_set(struct task_struct *target,
static int s390_gs_bc_get(struct task_struct *target, static int s390_gs_bc_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct gs_cb *data = target->thread.gs_bc_cb; struct gs_cb *data = target->thread.gs_bc_cb;
...@@ -1273,8 +1233,7 @@ static int s390_gs_bc_get(struct task_struct *target, ...@@ -1273,8 +1233,7 @@ static int s390_gs_bc_get(struct task_struct *target,
return -ENODEV; return -ENODEV;
if (!data) if (!data)
return -ENODATA; return -ENODATA;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, data, sizeof(struct gs_cb));
data, 0, sizeof(struct gs_cb));
} }
static int s390_gs_bc_set(struct task_struct *target, static int s390_gs_bc_set(struct task_struct *target,
...@@ -1325,8 +1284,7 @@ static bool is_ri_cb_valid(struct runtime_instr_cb *cb) ...@@ -1325,8 +1284,7 @@ static bool is_ri_cb_valid(struct runtime_instr_cb *cb)
static int s390_runtime_instr_get(struct task_struct *target, static int s390_runtime_instr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct runtime_instr_cb *data = target->thread.ri_cb; struct runtime_instr_cb *data = target->thread.ri_cb;
...@@ -1335,8 +1293,7 @@ static int s390_runtime_instr_get(struct task_struct *target, ...@@ -1335,8 +1293,7 @@ static int s390_runtime_instr_get(struct task_struct *target,
if (!data) if (!data)
return -ENODATA; return -ENODATA;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, data, sizeof(struct runtime_instr_cb));
data, 0, sizeof(struct runtime_instr_cb));
} }
static int s390_runtime_instr_set(struct task_struct *target, static int s390_runtime_instr_set(struct task_struct *target,
...@@ -1392,7 +1349,7 @@ static const struct user_regset s390_regsets[] = { ...@@ -1392,7 +1349,7 @@ static const struct user_regset s390_regsets[] = {
.n = sizeof(s390_regs) / sizeof(long), .n = sizeof(s390_regs) / sizeof(long),
.size = sizeof(long), .size = sizeof(long),
.align = sizeof(long), .align = sizeof(long),
.get = s390_regs_get, .regset_get = s390_regs_get,
.set = s390_regs_set, .set = s390_regs_set,
}, },
{ {
...@@ -1400,7 +1357,7 @@ static const struct user_regset s390_regsets[] = { ...@@ -1400,7 +1357,7 @@ static const struct user_regset s390_regsets[] = {
.n = sizeof(s390_fp_regs) / sizeof(long), .n = sizeof(s390_fp_regs) / sizeof(long),
.size = sizeof(long), .size = sizeof(long),
.align = sizeof(long), .align = sizeof(long),
.get = s390_fpregs_get, .regset_get = s390_fpregs_get,
.set = s390_fpregs_set, .set = s390_fpregs_set,
}, },
{ {
...@@ -1408,7 +1365,7 @@ static const struct user_regset s390_regsets[] = { ...@@ -1408,7 +1365,7 @@ static const struct user_regset s390_regsets[] = {
.n = 1, .n = 1,
.size = sizeof(unsigned int), .size = sizeof(unsigned int),
.align = sizeof(unsigned int), .align = sizeof(unsigned int),
.get = s390_system_call_get, .regset_get = s390_system_call_get,
.set = s390_system_call_set, .set = s390_system_call_set,
}, },
{ {
...@@ -1416,7 +1373,7 @@ static const struct user_regset s390_regsets[] = { ...@@ -1416,7 +1373,7 @@ static const struct user_regset s390_regsets[] = {
.n = 1, .n = 1,
.size = sizeof(long), .size = sizeof(long),
.align = sizeof(long), .align = sizeof(long),
.get = s390_last_break_get, .regset_get = s390_last_break_get,
.set = s390_last_break_set, .set = s390_last_break_set,
}, },
{ {
...@@ -1424,7 +1381,7 @@ static const struct user_regset s390_regsets[] = { ...@@ -1424,7 +1381,7 @@ static const struct user_regset s390_regsets[] = {
.n = 1, .n = 1,
.size = 256, .size = 256,
.align = 1, .align = 1,
.get = s390_tdb_get, .regset_get = s390_tdb_get,
.set = s390_tdb_set, .set = s390_tdb_set,
}, },
{ {
...@@ -1432,7 +1389,7 @@ static const struct user_regset s390_regsets[] = { ...@@ -1432,7 +1389,7 @@ static const struct user_regset s390_regsets[] = {
.n = __NUM_VXRS_LOW, .n = __NUM_VXRS_LOW,
.size = sizeof(__u64), .size = sizeof(__u64),
.align = sizeof(__u64), .align = sizeof(__u64),
.get = s390_vxrs_low_get, .regset_get = s390_vxrs_low_get,
.set = s390_vxrs_low_set, .set = s390_vxrs_low_set,
}, },
{ {
...@@ -1440,7 +1397,7 @@ static const struct user_regset s390_regsets[] = { ...@@ -1440,7 +1397,7 @@ static const struct user_regset s390_regsets[] = {
.n = __NUM_VXRS_HIGH, .n = __NUM_VXRS_HIGH,
.size = sizeof(__vector128), .size = sizeof(__vector128),
.align = sizeof(__vector128), .align = sizeof(__vector128),
.get = s390_vxrs_high_get, .regset_get = s390_vxrs_high_get,
.set = s390_vxrs_high_set, .set = s390_vxrs_high_set,
}, },
{ {
...@@ -1448,7 +1405,7 @@ static const struct user_regset s390_regsets[] = { ...@@ -1448,7 +1405,7 @@ static const struct user_regset s390_regsets[] = {
.n = sizeof(struct gs_cb) / sizeof(__u64), .n = sizeof(struct gs_cb) / sizeof(__u64),
.size = sizeof(__u64), .size = sizeof(__u64),
.align = sizeof(__u64), .align = sizeof(__u64),
.get = s390_gs_cb_get, .regset_get = s390_gs_cb_get,
.set = s390_gs_cb_set, .set = s390_gs_cb_set,
}, },
{ {
...@@ -1456,7 +1413,7 @@ static const struct user_regset s390_regsets[] = { ...@@ -1456,7 +1413,7 @@ static const struct user_regset s390_regsets[] = {
.n = sizeof(struct gs_cb) / sizeof(__u64), .n = sizeof(struct gs_cb) / sizeof(__u64),
.size = sizeof(__u64), .size = sizeof(__u64),
.align = sizeof(__u64), .align = sizeof(__u64),
.get = s390_gs_bc_get, .regset_get = s390_gs_bc_get,
.set = s390_gs_bc_set, .set = s390_gs_bc_set,
}, },
{ {
...@@ -1464,7 +1421,7 @@ static const struct user_regset s390_regsets[] = { ...@@ -1464,7 +1421,7 @@ static const struct user_regset s390_regsets[] = {
.n = sizeof(struct runtime_instr_cb) / sizeof(__u64), .n = sizeof(struct runtime_instr_cb) / sizeof(__u64),
.size = sizeof(__u64), .size = sizeof(__u64),
.align = sizeof(__u64), .align = sizeof(__u64),
.get = s390_runtime_instr_get, .regset_get = s390_runtime_instr_get,
.set = s390_runtime_instr_set, .set = s390_runtime_instr_set,
}, },
}; };
...@@ -1479,28 +1436,15 @@ static const struct user_regset_view user_s390_view = { ...@@ -1479,28 +1436,15 @@ static const struct user_regset_view user_s390_view = {
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
static int s390_compat_regs_get(struct task_struct *target, static int s390_compat_regs_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
unsigned n;
if (target == current) if (target == current)
save_access_regs(target->thread.acrs); save_access_regs(target->thread.acrs);
if (kbuf) { for (n = 0; n < sizeof(s390_compat_regs); n += sizeof(compat_ulong_t))
compat_ulong_t *k = kbuf; membuf_store(&to, __peek_user_compat(target, n));
while (count > 0) {
*k++ = __peek_user_compat(target, pos);
count -= sizeof(*k);
pos += sizeof(*k);
}
} else {
compat_ulong_t __user *u = ubuf;
while (count > 0) {
if (__put_user(__peek_user_compat(target, pos), u++))
return -EFAULT;
count -= sizeof(*u);
pos += sizeof(*u);
}
}
return 0; return 0;
} }
...@@ -1542,29 +1486,14 @@ static int s390_compat_regs_set(struct task_struct *target, ...@@ -1542,29 +1486,14 @@ static int s390_compat_regs_set(struct task_struct *target,
static int s390_compat_regs_high_get(struct task_struct *target, static int s390_compat_regs_high_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
compat_ulong_t *gprs_high; compat_ulong_t *gprs_high;
int i;
gprs_high = (compat_ulong_t *) gprs_high = (compat_ulong_t *)task_pt_regs(target)->gprs;
&task_pt_regs(target)->gprs[pos / sizeof(compat_ulong_t)]; for (i = 0; i < NUM_GPRS; i++, gprs_high += 2)
if (kbuf) { membuf_store(&to, *gprs_high);
compat_ulong_t *k = kbuf;
while (count > 0) {
*k++ = *gprs_high;
gprs_high += 2;
count -= sizeof(*k);
}
} else {
compat_ulong_t __user *u = ubuf;
while (count > 0) {
if (__put_user(*gprs_high, u++))
return -EFAULT;
gprs_high += 2;
count -= sizeof(*u);
}
}
return 0; return 0;
} }
...@@ -1603,23 +1532,11 @@ static int s390_compat_regs_high_set(struct task_struct *target, ...@@ -1603,23 +1532,11 @@ static int s390_compat_regs_high_set(struct task_struct *target,
static int s390_compat_last_break_get(struct task_struct *target, static int s390_compat_last_break_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
compat_ulong_t last_break; compat_ulong_t last_break = target->thread.last_break;
if (count > 0) { return membuf_store(&to, (unsigned long)last_break);
last_break = target->thread.last_break;
if (kbuf) {
unsigned long *k = kbuf;
*k = last_break;
} else {
unsigned long __user *u = ubuf;
if (__put_user(last_break, u))
return -EFAULT;
}
}
return 0;
} }
static int s390_compat_last_break_set(struct task_struct *target, static int s390_compat_last_break_set(struct task_struct *target,
...@@ -1636,7 +1553,7 @@ static const struct user_regset s390_compat_regsets[] = { ...@@ -1636,7 +1553,7 @@ static const struct user_regset s390_compat_regsets[] = {
.n = sizeof(s390_compat_regs) / sizeof(compat_long_t), .n = sizeof(s390_compat_regs) / sizeof(compat_long_t),
.size = sizeof(compat_long_t), .size = sizeof(compat_long_t),
.align = sizeof(compat_long_t), .align = sizeof(compat_long_t),
.get = s390_compat_regs_get, .regset_get = s390_compat_regs_get,
.set = s390_compat_regs_set, .set = s390_compat_regs_set,
}, },
{ {
...@@ -1644,7 +1561,7 @@ static const struct user_regset s390_compat_regsets[] = { ...@@ -1644,7 +1561,7 @@ static const struct user_regset s390_compat_regsets[] = {
.n = sizeof(s390_fp_regs) / sizeof(compat_long_t), .n = sizeof(s390_fp_regs) / sizeof(compat_long_t),
.size = sizeof(compat_long_t), .size = sizeof(compat_long_t),
.align = sizeof(compat_long_t), .align = sizeof(compat_long_t),
.get = s390_fpregs_get, .regset_get = s390_fpregs_get,
.set = s390_fpregs_set, .set = s390_fpregs_set,
}, },
{ {
...@@ -1652,7 +1569,7 @@ static const struct user_regset s390_compat_regsets[] = { ...@@ -1652,7 +1569,7 @@ static const struct user_regset s390_compat_regsets[] = {
.n = 1, .n = 1,
.size = sizeof(compat_uint_t), .size = sizeof(compat_uint_t),
.align = sizeof(compat_uint_t), .align = sizeof(compat_uint_t),
.get = s390_system_call_get, .regset_get = s390_system_call_get,
.set = s390_system_call_set, .set = s390_system_call_set,
}, },
{ {
...@@ -1660,7 +1577,7 @@ static const struct user_regset s390_compat_regsets[] = { ...@@ -1660,7 +1577,7 @@ static const struct user_regset s390_compat_regsets[] = {
.n = 1, .n = 1,
.size = sizeof(long), .size = sizeof(long),
.align = sizeof(long), .align = sizeof(long),
.get = s390_compat_last_break_get, .regset_get = s390_compat_last_break_get,
.set = s390_compat_last_break_set, .set = s390_compat_last_break_set,
}, },
{ {
...@@ -1668,7 +1585,7 @@ static const struct user_regset s390_compat_regsets[] = { ...@@ -1668,7 +1585,7 @@ static const struct user_regset s390_compat_regsets[] = {
.n = 1, .n = 1,
.size = 256, .size = 256,
.align = 1, .align = 1,
.get = s390_tdb_get, .regset_get = s390_tdb_get,
.set = s390_tdb_set, .set = s390_tdb_set,
}, },
{ {
...@@ -1676,7 +1593,7 @@ static const struct user_regset s390_compat_regsets[] = { ...@@ -1676,7 +1593,7 @@ static const struct user_regset s390_compat_regsets[] = {
.n = __NUM_VXRS_LOW, .n = __NUM_VXRS_LOW,
.size = sizeof(__u64), .size = sizeof(__u64),
.align = sizeof(__u64), .align = sizeof(__u64),
.get = s390_vxrs_low_get, .regset_get = s390_vxrs_low_get,
.set = s390_vxrs_low_set, .set = s390_vxrs_low_set,
}, },
{ {
...@@ -1684,7 +1601,7 @@ static const struct user_regset s390_compat_regsets[] = { ...@@ -1684,7 +1601,7 @@ static const struct user_regset s390_compat_regsets[] = {
.n = __NUM_VXRS_HIGH, .n = __NUM_VXRS_HIGH,
.size = sizeof(__vector128), .size = sizeof(__vector128),
.align = sizeof(__vector128), .align = sizeof(__vector128),
.get = s390_vxrs_high_get, .regset_get = s390_vxrs_high_get,
.set = s390_vxrs_high_set, .set = s390_vxrs_high_set,
}, },
{ {
...@@ -1692,7 +1609,7 @@ static const struct user_regset s390_compat_regsets[] = { ...@@ -1692,7 +1609,7 @@ static const struct user_regset s390_compat_regsets[] = {
.n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t), .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t),
.size = sizeof(compat_long_t), .size = sizeof(compat_long_t),
.align = sizeof(compat_long_t), .align = sizeof(compat_long_t),
.get = s390_compat_regs_high_get, .regset_get = s390_compat_regs_high_get,
.set = s390_compat_regs_high_set, .set = s390_compat_regs_high_set,
}, },
{ {
...@@ -1700,7 +1617,7 @@ static const struct user_regset s390_compat_regsets[] = { ...@@ -1700,7 +1617,7 @@ static const struct user_regset s390_compat_regsets[] = {
.n = sizeof(struct gs_cb) / sizeof(__u64), .n = sizeof(struct gs_cb) / sizeof(__u64),
.size = sizeof(__u64), .size = sizeof(__u64),
.align = sizeof(__u64), .align = sizeof(__u64),
.get = s390_gs_cb_get, .regset_get = s390_gs_cb_get,
.set = s390_gs_cb_set, .set = s390_gs_cb_set,
}, },
{ {
...@@ -1708,7 +1625,7 @@ static const struct user_regset s390_compat_regsets[] = { ...@@ -1708,7 +1625,7 @@ static const struct user_regset s390_compat_regsets[] = {
.n = sizeof(struct gs_cb) / sizeof(__u64), .n = sizeof(struct gs_cb) / sizeof(__u64),
.size = sizeof(__u64), .size = sizeof(__u64),
.align = sizeof(__u64), .align = sizeof(__u64),
.get = s390_gs_bc_get, .regset_get = s390_gs_bc_get,
.set = s390_gs_bc_set, .set = s390_gs_bc_set,
}, },
{ {
...@@ -1716,7 +1633,7 @@ static const struct user_regset s390_compat_regsets[] = { ...@@ -1716,7 +1633,7 @@ static const struct user_regset s390_compat_regsets[] = {
.n = sizeof(struct runtime_instr_cb) / sizeof(__u64), .n = sizeof(struct runtime_instr_cb) / sizeof(__u64),
.size = sizeof(__u64), .size = sizeof(__u64),
.align = sizeof(__u64), .align = sizeof(__u64),
.get = s390_runtime_instr_get, .regset_get = s390_runtime_instr_get,
.set = s390_runtime_instr_set, .set = s390_runtime_instr_set,
}, },
}; };
......
...@@ -103,9 +103,8 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) ...@@ -103,9 +103,8 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
fpvalid = !!tsk_used_math(tsk); fpvalid = !!tsk_used_math(tsk);
if (fpvalid) if (fpvalid)
fpvalid = !fpregs_get(tsk, NULL, 0, fpvalid = !fpregs_get(tsk, NULL,
sizeof(struct user_fpu_struct), (struct membuf){fpu, sizeof(*fpu)});
fpu, NULL);
#endif #endif
return fpvalid; return fpvalid;
......
...@@ -134,26 +134,11 @@ void ptrace_disable(struct task_struct *child) ...@@ -134,26 +134,11 @@ void ptrace_disable(struct task_struct *child)
static int genregs_get(struct task_struct *target, static int genregs_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
const struct pt_regs *regs = task_pt_regs(target); const struct pt_regs *regs = task_pt_regs(target);
int ret;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, regs, sizeof(struct pt_regs));
regs->regs,
0, 16 * sizeof(unsigned long));
if (!ret)
/* PC, PR, SR, GBR, MACH, MACL, TRA */
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&regs->pc,
offsetof(struct pt_regs, pc),
sizeof(struct pt_regs));
if (!ret)
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
sizeof(struct pt_regs), -1);
return ret;
} }
static int genregs_set(struct task_struct *target, static int genregs_set(struct task_struct *target,
...@@ -182,8 +167,7 @@ static int genregs_set(struct task_struct *target, ...@@ -182,8 +167,7 @@ static int genregs_set(struct task_struct *target,
#ifdef CONFIG_SH_FPU #ifdef CONFIG_SH_FPU
int fpregs_get(struct task_struct *target, int fpregs_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
int ret; int ret;
...@@ -191,12 +175,8 @@ int fpregs_get(struct task_struct *target, ...@@ -191,12 +175,8 @@ int fpregs_get(struct task_struct *target,
if (ret) if (ret)
return ret; return ret;
if ((boot_cpu_data.flags & CPU_HAS_FPU)) return membuf_write(&to, target->thread.xstate,
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, sizeof(struct user_fpu_struct));
&target->thread.xstate->hardfpu, 0, -1);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.xstate->softfpu, 0, -1);
} }
static int fpregs_set(struct task_struct *target, static int fpregs_set(struct task_struct *target,
...@@ -230,20 +210,12 @@ static int fpregs_active(struct task_struct *target, ...@@ -230,20 +210,12 @@ static int fpregs_active(struct task_struct *target,
#ifdef CONFIG_SH_DSP #ifdef CONFIG_SH_DSP
static int dspregs_get(struct task_struct *target, static int dspregs_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
const struct pt_dspregs *regs = const struct pt_dspregs *regs =
(struct pt_dspregs *)&target->thread.dsp_status.dsp_regs; (struct pt_dspregs *)&target->thread.dsp_status.dsp_regs;
int ret;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, return membuf_write(&to, regs, sizeof(struct pt_dspregs));
0, sizeof(struct pt_dspregs));
if (!ret)
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
sizeof(struct pt_dspregs), -1);
return ret;
} }
static int dspregs_set(struct task_struct *target, static int dspregs_set(struct task_struct *target,
...@@ -324,7 +296,7 @@ static const struct user_regset sh_regsets[] = { ...@@ -324,7 +296,7 @@ static const struct user_regset sh_regsets[] = {
.n = ELF_NGREG, .n = ELF_NGREG,
.size = sizeof(long), .size = sizeof(long),
.align = sizeof(long), .align = sizeof(long),
.get = genregs_get, .regset_get = genregs_get,
.set = genregs_set, .set = genregs_set,
}, },
...@@ -334,7 +306,7 @@ static const struct user_regset sh_regsets[] = { ...@@ -334,7 +306,7 @@ static const struct user_regset sh_regsets[] = {
.n = sizeof(struct user_fpu_struct) / sizeof(long), .n = sizeof(struct user_fpu_struct) / sizeof(long),
.size = sizeof(long), .size = sizeof(long),
.align = sizeof(long), .align = sizeof(long),
.get = fpregs_get, .regset_get = fpregs_get,
.set = fpregs_set, .set = fpregs_set,
.active = fpregs_active, .active = fpregs_active,
}, },
...@@ -345,7 +317,7 @@ static const struct user_regset sh_regsets[] = { ...@@ -345,7 +317,7 @@ static const struct user_regset sh_regsets[] = {
.n = sizeof(struct pt_dspregs) / sizeof(long), .n = sizeof(struct pt_dspregs) / sizeof(long),
.size = sizeof(long), .size = sizeof(long),
.align = sizeof(long), .align = sizeof(long),
.get = dspregs_get, .regset_get = dspregs_get,
.set = dspregs_set, .set = dspregs_set,
.active = dspregs_active, .active = dspregs_active,
}, },
......
...@@ -83,41 +83,25 @@ static int regwindow32_set(struct task_struct *target, ...@@ -83,41 +83,25 @@ static int regwindow32_set(struct task_struct *target,
static int genregs32_get(struct task_struct *target, static int genregs32_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
const struct pt_regs *regs = target->thread.kregs; const struct pt_regs *regs = target->thread.kregs;
u32 uregs[16]; u32 uregs[16];
int ret;
if (target == current) if (target == current)
flush_user_windows(); flush_user_windows();
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_write(&to, regs->u_regs, 16 * sizeof(u32));
regs->u_regs, if (!to.left)
0, 16 * sizeof(u32)); return 0;
if (ret || !count) if (regwindow32_get(target, regs, uregs))
return ret; return -EFAULT;
membuf_write(&to, uregs, 16 * sizeof(u32));
if (pos < 32 * sizeof(u32)) { membuf_store(&to, regs->psr);
if (regwindow32_get(target, regs, uregs)) membuf_store(&to, regs->pc);
return -EFAULT; membuf_store(&to, regs->npc);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_store(&to, regs->y);
uregs, return membuf_zero(&to, 2 * sizeof(u32));
16 * sizeof(u32), 32 * sizeof(u32));
if (ret || !count)
return ret;
}
uregs[0] = regs->psr;
uregs[1] = regs->pc;
uregs[2] = regs->npc;
uregs[3] = regs->y;
uregs[4] = 0; /* WIM */
uregs[5] = 0; /* TBR */
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
uregs,
32 * sizeof(u32), 38 * sizeof(u32));
} }
static int genregs32_set(struct task_struct *target, static int genregs32_set(struct task_struct *target,
...@@ -139,19 +123,18 @@ static int genregs32_set(struct task_struct *target, ...@@ -139,19 +123,18 @@ static int genregs32_set(struct task_struct *target,
if (ret || !count) if (ret || !count)
return ret; return ret;
if (pos < 32 * sizeof(u32)) { if (regwindow32_get(target, regs, uregs))
if (regwindow32_get(target, regs, uregs)) return -EFAULT;
return -EFAULT; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs,
uregs, 16 * sizeof(u32), 32 * sizeof(u32));
16 * sizeof(u32), 32 * sizeof(u32)); if (ret)
if (ret) return ret;
return ret; if (regwindow32_set(target, regs, uregs))
if (regwindow32_set(target, regs, uregs)) return -EFAULT;
return -EFAULT; if (!count)
if (!count) return 0;
return 0;
}
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&psr, &psr,
32 * sizeof(u32), 33 * sizeof(u32)); 32 * sizeof(u32), 33 * sizeof(u32));
...@@ -182,46 +165,18 @@ static int genregs32_set(struct task_struct *target, ...@@ -182,46 +165,18 @@ static int genregs32_set(struct task_struct *target,
static int fpregs32_get(struct task_struct *target, static int fpregs32_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
const unsigned long *fpregs = target->thread.float_regs;
int ret = 0;
#if 0 #if 0
if (target == current) if (target == current)
save_and_clear_fpu(); save_and_clear_fpu();
#endif #endif
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_write(&to, target->thread.float_regs, 32 * sizeof(u32));
fpregs, membuf_zero(&to, sizeof(u32));
0, 32 * sizeof(u32)); membuf_write(&to, &target->thread.fsr, sizeof(u32));
membuf_store(&to, (u32)((1 << 8) | (8 << 16)));
if (!ret) return membuf_zero(&to, 64 * sizeof(u32));
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
32 * sizeof(u32),
33 * sizeof(u32));
if (!ret)
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.fsr,
33 * sizeof(u32),
34 * sizeof(u32));
if (!ret) {
unsigned long val;
val = (1 << 8) | (8 << 16);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&val,
34 * sizeof(u32),
35 * sizeof(u32));
}
if (!ret)
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
35 * sizeof(u32), -1);
return ret;
} }
static int fpregs32_set(struct task_struct *target, static int fpregs32_set(struct task_struct *target,
...@@ -243,13 +198,11 @@ static int fpregs32_set(struct task_struct *target, ...@@ -243,13 +198,11 @@ static int fpregs32_set(struct task_struct *target,
user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
32 * sizeof(u32), 32 * sizeof(u32),
33 * sizeof(u32)); 33 * sizeof(u32));
if (!ret && count > 0) { if (!ret)
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&target->thread.fsr, &target->thread.fsr,
33 * sizeof(u32), 33 * sizeof(u32),
34 * sizeof(u32)); 34 * sizeof(u32));
}
if (!ret) if (!ret)
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
34 * sizeof(u32), -1); 34 * sizeof(u32), -1);
...@@ -268,7 +221,7 @@ static const struct user_regset sparc32_regsets[] = { ...@@ -268,7 +221,7 @@ static const struct user_regset sparc32_regsets[] = {
.core_note_type = NT_PRSTATUS, .core_note_type = NT_PRSTATUS,
.n = 38, .n = 38,
.size = sizeof(u32), .align = sizeof(u32), .size = sizeof(u32), .align = sizeof(u32),
.get = genregs32_get, .set = genregs32_set .regset_get = genregs32_get, .set = genregs32_set
}, },
/* Format is: /* Format is:
* F0 --> F31 * F0 --> F31
...@@ -284,10 +237,104 @@ static const struct user_regset sparc32_regsets[] = { ...@@ -284,10 +237,104 @@ static const struct user_regset sparc32_regsets[] = {
.core_note_type = NT_PRFPREG, .core_note_type = NT_PRFPREG,
.n = 99, .n = 99,
.size = sizeof(u32), .align = sizeof(u32), .size = sizeof(u32), .align = sizeof(u32),
.get = fpregs32_get, .set = fpregs32_set .regset_get = fpregs32_get, .set = fpregs32_set
},
};
static int getregs_get(struct task_struct *target,
const struct user_regset *regset,
struct membuf to)
{
const struct pt_regs *regs = target->thread.kregs;
if (target == current)
flush_user_windows();
membuf_store(&to, regs->psr);
membuf_store(&to, regs->pc);
membuf_store(&to, regs->npc);
membuf_store(&to, regs->y);
return membuf_write(&to, regs->u_regs + 1, 15 * sizeof(u32));
}
static int setregs_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
struct pt_regs *regs = target->thread.kregs;
u32 v[4];
int ret;
if (target == current)
flush_user_windows();
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
v,
0, 4 * sizeof(u32));
if (ret)
return ret;
regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) |
(v[0] & (PSR_ICC | PSR_SYSCALL));
regs->pc = v[1];
regs->npc = v[2];
regs->y = v[3];
return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
regs->u_regs + 1,
4 * sizeof(u32) , 19 * sizeof(u32));
}
static int getfpregs_get(struct task_struct *target,
const struct user_regset *regset,
struct membuf to)
{
#if 0
if (target == current)
save_and_clear_fpu();
#endif
membuf_write(&to, &target->thread.float_regs, 32 * sizeof(u32));
membuf_write(&to, &target->thread.fsr, sizeof(u32));
return membuf_zero(&to, 35 * sizeof(u32));
}
static int setfpregs_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
unsigned long *fpregs = target->thread.float_regs;
int ret;
#if 0
if (target == current)
save_and_clear_fpu();
#endif
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
fpregs,
0, 32 * sizeof(u32));
if (ret)
return ret;
return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&target->thread.fsr,
32 * sizeof(u32),
33 * sizeof(u32));
}
static const struct user_regset ptrace32_regsets[] = {
[REGSET_GENERAL] = {
.n = 19, .size = sizeof(u32),
.regset_get = getregs_get, .set = setregs_set,
},
[REGSET_FP] = {
.n = 68, .size = sizeof(u32),
.regset_get = getfpregs_get, .set = setfpregs_set,
}, },
}; };
static const struct user_regset_view ptrace32_view = {
.regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets)
};
static const struct user_regset_view user_sparc32_view = { static const struct user_regset_view user_sparc32_view = {
.name = "sparc", .e_machine = EM_SPARC, .name = "sparc", .e_machine = EM_SPARC,
.regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets) .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
...@@ -315,74 +362,44 @@ long arch_ptrace(struct task_struct *child, long request, ...@@ -315,74 +362,44 @@ long arch_ptrace(struct task_struct *child, long request,
{ {
unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4]; unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
void __user *addr2p; void __user *addr2p;
const struct user_regset_view *view;
struct pt_regs __user *pregs; struct pt_regs __user *pregs;
struct fps __user *fps; struct fps __user *fps;
int ret; int ret;
view = task_user_regset_view(current);
addr2p = (void __user *) addr2; addr2p = (void __user *) addr2;
pregs = (struct pt_regs __user *) addr; pregs = (struct pt_regs __user *) addr;
fps = (struct fps __user *) addr; fps = (struct fps __user *) addr;
switch(request) { switch(request) {
case PTRACE_GETREGS: { case PTRACE_GETREGS: {
ret = copy_regset_to_user(child, view, REGSET_GENERAL, ret = copy_regset_to_user(child, &ptrace32_view,
32 * sizeof(u32), REGSET_GENERAL, 0,
4 * sizeof(u32), 19 * sizeof(u32),
&pregs->psr); pregs);
if (!ret)
copy_regset_to_user(child, view, REGSET_GENERAL,
1 * sizeof(u32),
15 * sizeof(u32),
&pregs->u_regs[0]);
break; break;
} }
case PTRACE_SETREGS: { case PTRACE_SETREGS: {
ret = copy_regset_from_user(child, view, REGSET_GENERAL, ret = copy_regset_from_user(child, &ptrace32_view,
32 * sizeof(u32), REGSET_GENERAL, 0,
4 * sizeof(u32), 19 * sizeof(u32),
&pregs->psr); pregs);
if (!ret)
copy_regset_from_user(child, view, REGSET_GENERAL,
1 * sizeof(u32),
15 * sizeof(u32),
&pregs->u_regs[0]);
break; break;
} }
case PTRACE_GETFPREGS: { case PTRACE_GETFPREGS: {
ret = copy_regset_to_user(child, view, REGSET_FP, ret = copy_regset_to_user(child, &ptrace32_view,
0 * sizeof(u32), REGSET_FP, 0,
32 * sizeof(u32), 68 * sizeof(u32),
&fps->regs[0]); fps);
if (!ret)
ret = copy_regset_to_user(child, view, REGSET_FP,
33 * sizeof(u32),
1 * sizeof(u32),
&fps->fsr);
if (!ret) {
if (__put_user(0, &fps->fpqd) ||
__put_user(0, &fps->flags) ||
__put_user(0, &fps->extra) ||
clear_user(fps->fpq, sizeof(fps->fpq)))
ret = -EFAULT;
}
break; break;
} }
case PTRACE_SETFPREGS: { case PTRACE_SETFPREGS: {
ret = copy_regset_from_user(child, view, REGSET_FP, ret = copy_regset_from_user(child, &ptrace32_view,
0 * sizeof(u32), REGSET_FP, 0,
32 * sizeof(u32), 33 * sizeof(u32),
&fps->regs[0]); fps);
if (!ret)
ret = copy_regset_from_user(child, view, REGSET_FP,
33 * sizeof(u32),
1 * sizeof(u32),
&fps->fsr);
break; break;
} }
......
...@@ -246,52 +246,23 @@ enum sparc_regset { ...@@ -246,52 +246,23 @@ enum sparc_regset {
static int genregs64_get(struct task_struct *target, static int genregs64_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
const struct pt_regs *regs = task_pt_regs(target); const struct pt_regs *regs = task_pt_regs(target);
int ret; struct reg_window window;
if (target == current) if (target == current)
flushw_user(); flushw_user();
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_write(&to, regs->u_regs, 16 * sizeof(u64));
regs->u_regs, if (!to.left)
0, 16 * sizeof(u64)); return 0;
if (!ret && count && pos < (32 * sizeof(u64))) { if (regwindow64_get(target, regs, &window))
struct reg_window window; return -EFAULT;
membuf_write(&to, &window, 16 * sizeof(u64));
if (regwindow64_get(target, regs, &window)) /* TSTATE, TPC, TNPC */
return -EFAULT; membuf_write(&to, &regs->tstate, 3 * sizeof(u64));
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_store(&to, (u64)regs->y);
&window,
16 * sizeof(u64),
32 * sizeof(u64));
}
if (!ret) {
/* TSTATE, TPC, TNPC */
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&regs->tstate,
32 * sizeof(u64),
35 * sizeof(u64));
}
if (!ret) {
unsigned long y = regs->y;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&y,
35 * sizeof(u64),
36 * sizeof(u64));
}
if (!ret) {
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
36 * sizeof(u64), -1);
}
return ret;
} }
static int genregs64_set(struct task_struct *target, static int genregs64_set(struct task_struct *target,
...@@ -370,69 +341,32 @@ static int genregs64_set(struct task_struct *target, ...@@ -370,69 +341,32 @@ static int genregs64_set(struct task_struct *target,
static int fpregs64_get(struct task_struct *target, static int fpregs64_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
const unsigned long *fpregs = task_thread_info(target)->fpregs; struct thread_info *t = task_thread_info(target);
unsigned long fprs, fsr, gsr; unsigned long fprs;
int ret;
if (target == current) if (target == current)
save_and_clear_fpu(); save_and_clear_fpu();
fprs = task_thread_info(target)->fpsaved[0]; fprs = t->fpsaved[0];
if (fprs & FPRS_DL) if (fprs & FPRS_DL)
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, membuf_write(&to, t->fpregs, 16 * sizeof(u64));
fpregs,
0, 16 * sizeof(u64));
else else
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, membuf_zero(&to, 16 * sizeof(u64));
0,
16 * sizeof(u64));
if (!ret) {
if (fprs & FPRS_DU)
ret = user_regset_copyout(&pos, &count,
&kbuf, &ubuf,
fpregs + 16,
16 * sizeof(u64),
32 * sizeof(u64));
else
ret = user_regset_copyout_zero(&pos, &count,
&kbuf, &ubuf,
16 * sizeof(u64),
32 * sizeof(u64));
}
if (fprs & FPRS_DU)
membuf_write(&to, t->fpregs + 16, 16 * sizeof(u64));
else
membuf_zero(&to, 16 * sizeof(u64));
if (fprs & FPRS_FEF) { if (fprs & FPRS_FEF) {
fsr = task_thread_info(target)->xfsr[0]; membuf_store(&to, t->xfsr[0]);
gsr = task_thread_info(target)->gsr[0]; membuf_store(&to, t->gsr[0]);
} else { } else {
fsr = gsr = 0; membuf_zero(&to, 2 * sizeof(u64));
} }
return membuf_store(&to, fprs);
if (!ret)
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&fsr,
32 * sizeof(u64),
33 * sizeof(u64));
if (!ret)
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&gsr,
33 * sizeof(u64),
34 * sizeof(u64));
if (!ret)
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&fprs,
34 * sizeof(u64),
35 * sizeof(u64));
if (!ret)
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
35 * sizeof(u64), -1);
return ret;
} }
static int fpregs64_set(struct task_struct *target, static int fpregs64_set(struct task_struct *target,
...@@ -490,7 +424,7 @@ static const struct user_regset sparc64_regsets[] = { ...@@ -490,7 +424,7 @@ static const struct user_regset sparc64_regsets[] = {
.core_note_type = NT_PRSTATUS, .core_note_type = NT_PRSTATUS,
.n = 36, .n = 36,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.get = genregs64_get, .set = genregs64_set .regset_get = genregs64_get, .set = genregs64_set
}, },
/* Format is: /* Format is:
* F0 --> F63 * F0 --> F63
...@@ -502,10 +436,96 @@ static const struct user_regset sparc64_regsets[] = { ...@@ -502,10 +436,96 @@ static const struct user_regset sparc64_regsets[] = {
.core_note_type = NT_PRFPREG, .core_note_type = NT_PRFPREG,
.n = 35, .n = 35,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.get = fpregs64_get, .set = fpregs64_set .regset_get = fpregs64_get, .set = fpregs64_set
},
};
static int getregs64_get(struct task_struct *target,
const struct user_regset *regset,
struct membuf to)
{
const struct pt_regs *regs = task_pt_regs(target);
if (target == current)
flushw_user();
membuf_write(&to, regs->u_regs + 1, 15 * sizeof(u64));
membuf_store(&to, (u64)0);
membuf_write(&to, &regs->tstate, 3 * sizeof(u64));
return membuf_store(&to, (u64)regs->y);
}
static int setregs64_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
struct pt_regs *regs = task_pt_regs(target);
unsigned long y = regs->y;
unsigned long tstate;
int ret;
if (target == current)
flushw_user();
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
regs->u_regs + 1,
0 * sizeof(u64),
15 * sizeof(u64));
if (ret)
return ret;
ret =user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
15 * sizeof(u64), 16 * sizeof(u64));
if (ret)
return ret;
/* TSTATE */
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&tstate,
16 * sizeof(u64),
17 * sizeof(u64));
if (ret)
return ret;
/* Only the condition codes and the "in syscall"
* state can be modified in the %tstate register.
*/
tstate &= (TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
regs->tstate |= tstate;
/* TPC, TNPC */
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&regs->tpc,
17 * sizeof(u64),
19 * sizeof(u64));
if (ret)
return ret;
/* Y */
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&y,
19 * sizeof(u64),
20 * sizeof(u64));
if (!ret)
regs->y = y;
return ret;
}
static const struct user_regset ptrace64_regsets[] = {
/* Format is:
* G1 --> G7
* O0 --> O7
* 0
* TSTATE, TPC, TNPC, Y
*/
[REGSET_GENERAL] = {
.n = 20, .size = sizeof(u64),
.regset_get = getregs64_get, .set = setregs64_set,
}, },
}; };
static const struct user_regset_view ptrace64_view = {
.regsets = ptrace64_regsets, .n = ARRAY_SIZE(ptrace64_regsets)
};
static const struct user_regset_view user_sparc64_view = { static const struct user_regset_view user_sparc64_view = {
.name = "sparc64", .e_machine = EM_SPARCV9, .name = "sparc64", .e_machine = EM_SPARCV9,
.regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets) .regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets)
...@@ -514,108 +534,28 @@ static const struct user_regset_view user_sparc64_view = { ...@@ -514,108 +534,28 @@ static const struct user_regset_view user_sparc64_view = {
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
static int genregs32_get(struct task_struct *target, static int genregs32_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
const struct pt_regs *regs = task_pt_regs(target); const struct pt_regs *regs = task_pt_regs(target);
compat_ulong_t __user *reg_window; u32 uregs[16];
compat_ulong_t *k = kbuf; int i;
compat_ulong_t __user *u = ubuf;
compat_ulong_t reg;
if (target == current) if (target == current)
flushw_user(); flushw_user();
pos /= sizeof(reg); for (i = 0; i < 16; i++)
count /= sizeof(reg); membuf_store(&to, (u32)regs->u_regs[i]);
if (!to.left)
if (kbuf) { return 0;
for (; count > 0 && pos < 16; count--) if (get_from_target(target, regs->u_regs[UREG_I6],
*k++ = regs->u_regs[pos++]; uregs, sizeof(uregs)))
return -EFAULT;
reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; membuf_write(&to, uregs, 16 * sizeof(u32));
reg_window -= 16; membuf_store(&to, (u32)tstate_to_psr(regs->tstate));
if (target == current) { membuf_store(&to, (u32)(regs->tpc));
for (; count > 0 && pos < 32; count--) { membuf_store(&to, (u32)(regs->tnpc));
if (get_user(*k++, &reg_window[pos++])) membuf_store(&to, (u32)(regs->y));
return -EFAULT; return membuf_zero(&to, 2 * sizeof(u32));
}
} else {
for (; count > 0 && pos < 32; count--) {
if (access_process_vm(target,
(unsigned long)
&reg_window[pos],
k, sizeof(*k),
FOLL_FORCE)
!= sizeof(*k))
return -EFAULT;
k++;
pos++;
}
}
} else {
for (; count > 0 && pos < 16; count--) {
if (put_user((compat_ulong_t) regs->u_regs[pos++], u++))
return -EFAULT;
}
reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
reg_window -= 16;
if (target == current) {
for (; count > 0 && pos < 32; count--) {
if (get_user(reg, &reg_window[pos++]) ||
put_user(reg, u++))
return -EFAULT;
}
} else {
for (; count > 0 && pos < 32; count--) {
if (access_process_vm(target,
(unsigned long)
&reg_window[pos++],
&reg, sizeof(reg),
FOLL_FORCE)
!= sizeof(reg))
return -EFAULT;
if (put_user(reg, u++))
return -EFAULT;
}
}
}
while (count > 0) {
switch (pos) {
case 32: /* PSR */
reg = tstate_to_psr(regs->tstate);
break;
case 33: /* PC */
reg = regs->tpc;
break;
case 34: /* NPC */
reg = regs->tnpc;
break;
case 35: /* Y */
reg = regs->y;
break;
case 36: /* WIM */
case 37: /* TBR */
reg = 0;
break;
default:
goto finish;
}
if (kbuf)
*k++ = reg;
else if (put_user(reg, u++))
return -EFAULT;
pos++;
count--;
}
finish:
pos *= sizeof(reg);
count *= sizeof(reg);
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
38 * sizeof(reg), -1);
} }
static int genregs32_set(struct task_struct *target, static int genregs32_set(struct task_struct *target,
...@@ -737,56 +677,24 @@ static int genregs32_set(struct task_struct *target, ...@@ -737,56 +677,24 @@ static int genregs32_set(struct task_struct *target,
static int fpregs32_get(struct task_struct *target, static int fpregs32_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
const unsigned long *fpregs = task_thread_info(target)->fpregs; struct thread_info *t = task_thread_info(target);
compat_ulong_t enabled; bool enabled;
unsigned long fprs;
compat_ulong_t fsr;
int ret = 0;
if (target == current) if (target == current)
save_and_clear_fpu(); save_and_clear_fpu();
fprs = task_thread_info(target)->fpsaved[0]; enabled = t->fpsaved[0] & FPRS_FEF;
if (fprs & FPRS_FEF) {
fsr = task_thread_info(target)->xfsr[0];
enabled = 1;
} else {
fsr = 0;
enabled = 0;
}
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
fpregs,
0, 32 * sizeof(u32));
if (!ret)
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
32 * sizeof(u32),
33 * sizeof(u32));
if (!ret)
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&fsr,
33 * sizeof(u32),
34 * sizeof(u32));
if (!ret) {
compat_ulong_t val;
val = (enabled << 8) | (8 << 16);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&val,
34 * sizeof(u32),
35 * sizeof(u32));
}
if (!ret) membuf_write(&to, t->fpregs, 32 * sizeof(u32));
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, membuf_zero(&to, sizeof(u32));
35 * sizeof(u32), -1); if (enabled)
membuf_store(&to, (u32)t->xfsr[0]);
return ret; else
membuf_zero(&to, sizeof(u32));
membuf_store(&to, (u32)((enabled << 8) | (8 << 16)));
return membuf_zero(&to, 64 * sizeof(u32));
} }
static int fpregs32_set(struct task_struct *target, static int fpregs32_set(struct task_struct *target,
...@@ -847,7 +755,7 @@ static const struct user_regset sparc32_regsets[] = { ...@@ -847,7 +755,7 @@ static const struct user_regset sparc32_regsets[] = {
.core_note_type = NT_PRSTATUS, .core_note_type = NT_PRSTATUS,
.n = 38, .n = 38,
.size = sizeof(u32), .align = sizeof(u32), .size = sizeof(u32), .align = sizeof(u32),
.get = genregs32_get, .set = genregs32_set .regset_get = genregs32_get, .set = genregs32_set
}, },
/* Format is: /* Format is:
* F0 --> F31 * F0 --> F31
...@@ -863,10 +771,133 @@ static const struct user_regset sparc32_regsets[] = { ...@@ -863,10 +771,133 @@ static const struct user_regset sparc32_regsets[] = {
.core_note_type = NT_PRFPREG, .core_note_type = NT_PRFPREG,
.n = 99, .n = 99,
.size = sizeof(u32), .align = sizeof(u32), .size = sizeof(u32), .align = sizeof(u32),
.get = fpregs32_get, .set = fpregs32_set .regset_get = fpregs32_get, .set = fpregs32_set
}, },
}; };
static int getregs_get(struct task_struct *target,
const struct user_regset *regset,
struct membuf to)
{
const struct pt_regs *regs = task_pt_regs(target);
int i;
if (target == current)
flushw_user();
membuf_store(&to, (u32)tstate_to_psr(regs->tstate));
membuf_store(&to, (u32)(regs->tpc));
membuf_store(&to, (u32)(regs->tnpc));
membuf_store(&to, (u32)(regs->y));
for (i = 1; i < 16; i++)
membuf_store(&to, (u32)regs->u_regs[i]);
return to.left;
}
static int setregs_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
struct pt_regs *regs = task_pt_regs(target);
unsigned long tstate;
u32 uregs[19];
int i, ret;
if (target == current)
flushw_user();
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
uregs,
0, 19 * sizeof(u32));
if (ret)
return ret;
tstate = regs->tstate;
tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
tstate |= psr_to_tstate_icc(uregs[0]);
if (uregs[0] & PSR_SYSCALL)
tstate |= TSTATE_SYSCALL;
regs->tstate = tstate;
regs->tpc = uregs[1];
regs->tnpc = uregs[2];
regs->y = uregs[3];
for (i = 1; i < 15; i++)
regs->u_regs[i] = uregs[3 + i];
return 0;
}
static int getfpregs_get(struct task_struct *target,
const struct user_regset *regset,
struct membuf to)
{
struct thread_info *t = task_thread_info(target);
if (target == current)
save_and_clear_fpu();
membuf_write(&to, t->fpregs, 32 * sizeof(u32));
if (t->fpsaved[0] & FPRS_FEF)
membuf_store(&to, (u32)t->xfsr[0]);
else
membuf_zero(&to, sizeof(u32));
return membuf_zero(&to, 35 * sizeof(u32));
}
static int setfpregs_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
unsigned long *fpregs = task_thread_info(target)->fpregs;
unsigned long fprs;
int ret;
if (target == current)
save_and_clear_fpu();
fprs = task_thread_info(target)->fpsaved[0];
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
fpregs,
0, 32 * sizeof(u32));
if (!ret) {
compat_ulong_t fsr;
unsigned long val;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&fsr,
32 * sizeof(u32),
33 * sizeof(u32));
if (!ret) {
val = task_thread_info(target)->xfsr[0];
val &= 0xffffffff00000000UL;
val |= fsr;
task_thread_info(target)->xfsr[0] = val;
}
}
fprs |= (FPRS_FEF | FPRS_DL);
task_thread_info(target)->fpsaved[0] = fprs;
return ret;
}
static const struct user_regset ptrace32_regsets[] = {
[REGSET_GENERAL] = {
.n = 19, .size = sizeof(u32),
.regset_get = getregs_get, .set = setregs_set,
},
[REGSET_FP] = {
.n = 68, .size = sizeof(u32),
.regset_get = getfpregs_get, .set = setfpregs_set,
},
};
static const struct user_regset_view ptrace32_view = {
.regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets)
};
static const struct user_regset_view user_sparc32_view = { static const struct user_regset_view user_sparc32_view = {
.name = "sparc", .e_machine = EM_SPARC, .name = "sparc", .e_machine = EM_SPARC,
.regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets) .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
...@@ -898,7 +929,6 @@ struct compat_fps { ...@@ -898,7 +929,6 @@ struct compat_fps {
long compat_arch_ptrace(struct task_struct *child, compat_long_t request, long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
compat_ulong_t caddr, compat_ulong_t cdata) compat_ulong_t caddr, compat_ulong_t cdata)
{ {
const struct user_regset_view *view = task_user_regset_view(current);
compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4]; compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4];
struct pt_regs32 __user *pregs; struct pt_regs32 __user *pregs;
struct compat_fps __user *fps; struct compat_fps __user *fps;
...@@ -916,58 +946,31 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, ...@@ -916,58 +946,31 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
break; break;
case PTRACE_GETREGS: case PTRACE_GETREGS:
ret = copy_regset_to_user(child, view, REGSET_GENERAL, ret = copy_regset_to_user(child, &ptrace32_view,
32 * sizeof(u32), REGSET_GENERAL, 0,
4 * sizeof(u32), 19 * sizeof(u32),
&pregs->psr); pregs);
if (!ret)
ret = copy_regset_to_user(child, view, REGSET_GENERAL,
1 * sizeof(u32),
15 * sizeof(u32),
&pregs->u_regs[0]);
break; break;
case PTRACE_SETREGS: case PTRACE_SETREGS:
ret = copy_regset_from_user(child, view, REGSET_GENERAL, ret = copy_regset_from_user(child, &ptrace32_view,
32 * sizeof(u32), REGSET_GENERAL, 0,
4 * sizeof(u32), 19 * sizeof(u32),
&pregs->psr); pregs);
if (!ret)
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
1 * sizeof(u32),
15 * sizeof(u32),
&pregs->u_regs[0]);
break; break;
case PTRACE_GETFPREGS: case PTRACE_GETFPREGS:
ret = copy_regset_to_user(child, view, REGSET_FP, ret = copy_regset_to_user(child, &ptrace32_view,
0 * sizeof(u32), REGSET_FP, 0,
32 * sizeof(u32), 68 * sizeof(u32),
&fps->regs[0]); fps);
if (!ret)
ret = copy_regset_to_user(child, view, REGSET_FP,
33 * sizeof(u32),
1 * sizeof(u32),
&fps->fsr);
if (!ret) {
if (__put_user(0, &fps->flags) ||
__put_user(0, &fps->extra) ||
__put_user(0, &fps->fpqd) ||
clear_user(&fps->fpq[0], 32 * sizeof(unsigned int)))
ret = -EFAULT;
}
break; break;
case PTRACE_SETFPREGS: case PTRACE_SETFPREGS:
ret = copy_regset_from_user(child, view, REGSET_FP, ret = copy_regset_from_user(child, &ptrace32_view,
0 * sizeof(u32), REGSET_FP, 0,
32 * sizeof(u32), 33 * sizeof(u32),
&fps->regs[0]); fps);
if (!ret)
ret = copy_regset_from_user(child, view, REGSET_FP,
33 * sizeof(u32),
1 * sizeof(u32),
&fps->fsr);
break; break;
case PTRACE_READTEXT: case PTRACE_READTEXT:
...@@ -1026,31 +1029,17 @@ long arch_ptrace(struct task_struct *child, long request, ...@@ -1026,31 +1029,17 @@ long arch_ptrace(struct task_struct *child, long request,
break; break;
case PTRACE_GETREGS64: case PTRACE_GETREGS64:
ret = copy_regset_to_user(child, view, REGSET_GENERAL, ret = copy_regset_to_user(child, &ptrace64_view,
1 * sizeof(u64), REGSET_GENERAL, 0,
15 * sizeof(u64), 19 * sizeof(u64),
&pregs->u_regs[0]); pregs);
if (!ret) {
/* XXX doesn't handle 'y' register correctly XXX */
ret = copy_regset_to_user(child, view, REGSET_GENERAL,
32 * sizeof(u64),
4 * sizeof(u64),
&pregs->tstate);
}
break; break;
case PTRACE_SETREGS64: case PTRACE_SETREGS64:
ret = copy_regset_from_user(child, view, REGSET_GENERAL, ret = copy_regset_from_user(child, &ptrace64_view,
1 * sizeof(u64), REGSET_GENERAL, 0,
15 * sizeof(u64), 19 * sizeof(u64),
&pregs->u_regs[0]); pregs);
if (!ret) {
/* XXX doesn't handle 'y' register correctly XXX */
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
32 * sizeof(u64),
4 * sizeof(u64),
&pregs->tstate);
}
break; break;
case PTRACE_GETFPREGS64: case PTRACE_GETFPREGS64:
......
...@@ -34,7 +34,6 @@ extern int fpu__copy(struct task_struct *dst, struct task_struct *src); ...@@ -34,7 +34,6 @@ extern int fpu__copy(struct task_struct *dst, struct task_struct *src);
extern void fpu__clear_user_states(struct fpu *fpu); extern void fpu__clear_user_states(struct fpu *fpu);
extern void fpu__clear_all(struct fpu *fpu); extern void fpu__clear_all(struct fpu *fpu);
extern int fpu__exception_code(struct fpu *fpu, int trap_nr); extern int fpu__exception_code(struct fpu *fpu, int trap_nr);
extern int dump_fpu(struct pt_regs *ptregs, struct user_i387_struct *fpstate);
/* /*
* Boot time FPU initialization functions: * Boot time FPU initialization functions:
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
#include <linux/regset.h> #include <linux/regset.h>
extern user_regset_active_fn regset_fpregs_active, regset_xregset_fpregs_active; extern user_regset_active_fn regset_fpregs_active, regset_xregset_fpregs_active;
extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get, extern user_regset_get2_fn fpregs_get, xfpregs_get, fpregs_soft_get,
xstateregs_get; xstateregs_get;
extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set, extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
xstateregs_set; xstateregs_set;
......
...@@ -104,8 +104,8 @@ void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr); ...@@ -104,8 +104,8 @@ void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr);
const void *get_xsave_field_ptr(int xfeature_nr); const void *get_xsave_field_ptr(int xfeature_nr);
int using_compacted_format(void); int using_compacted_format(void);
int xfeature_size(int xfeature_nr); int xfeature_size(int xfeature_nr);
int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int offset, unsigned int size); struct membuf;
int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned int offset, unsigned int size); void copy_xstate_to_kernel(struct membuf to, struct xregs_state *xsave);
int copy_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf); int copy_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf);
int copy_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf); int copy_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf);
void copy_supervisor_to_kernel(struct xregs_state *xsave); void copy_supervisor_to_kernel(struct xregs_state *xsave);
......
...@@ -27,8 +27,7 @@ int regset_xregset_fpregs_active(struct task_struct *target, const struct user_r ...@@ -27,8 +27,7 @@ int regset_xregset_fpregs_active(struct task_struct *target, const struct user_r
} }
int xfpregs_get(struct task_struct *target, const struct user_regset *regset, int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct fpu *fpu = &target->thread.fpu; struct fpu *fpu = &target->thread.fpu;
...@@ -38,8 +37,7 @@ int xfpregs_get(struct task_struct *target, const struct user_regset *regset, ...@@ -38,8 +37,7 @@ int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
fpu__prepare_read(fpu); fpu__prepare_read(fpu);
fpstate_sanitize_xstate(fpu); fpstate_sanitize_xstate(fpu);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, &fpu->state.fxsave, sizeof(struct fxregs_state));
&fpu->state.fxsave, 0, -1);
} }
int xfpregs_set(struct task_struct *target, const struct user_regset *regset, int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
...@@ -74,12 +72,10 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset, ...@@ -74,12 +72,10 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
} }
int xstateregs_get(struct task_struct *target, const struct user_regset *regset, int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct fpu *fpu = &target->thread.fpu; struct fpu *fpu = &target->thread.fpu;
struct xregs_state *xsave; struct xregs_state *xsave;
int ret;
if (!boot_cpu_has(X86_FEATURE_XSAVE)) if (!boot_cpu_has(X86_FEATURE_XSAVE))
return -ENODEV; return -ENODEV;
...@@ -89,10 +85,8 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset, ...@@ -89,10 +85,8 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
fpu__prepare_read(fpu); fpu__prepare_read(fpu);
if (using_compacted_format()) { if (using_compacted_format()) {
if (kbuf) copy_xstate_to_kernel(to, xsave);
ret = copy_xstate_to_kernel(kbuf, xsave, pos, count); return 0;
else
ret = copy_xstate_to_user(ubuf, xsave, pos, count);
} else { } else {
fpstate_sanitize_xstate(fpu); fpstate_sanitize_xstate(fpu);
/* /*
...@@ -105,9 +99,8 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset, ...@@ -105,9 +99,8 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
/* /*
* Copy the xstate memory layout. * Copy the xstate memory layout.
*/ */
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, xsave, 0, -1); return membuf_write(&to, xsave, fpu_user_xstate_size);
} }
return ret;
} }
int xstateregs_set(struct task_struct *target, const struct user_regset *regset, int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
...@@ -293,8 +286,7 @@ void convert_to_fxsr(struct fxregs_state *fxsave, ...@@ -293,8 +286,7 @@ void convert_to_fxsr(struct fxregs_state *fxsave,
} }
int fpregs_get(struct task_struct *target, const struct user_regset *regset, int fpregs_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct fpu *fpu = &target->thread.fpu; struct fpu *fpu = &target->thread.fpu;
struct user_i387_ia32_struct env; struct user_i387_ia32_struct env;
...@@ -302,23 +294,22 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset, ...@@ -302,23 +294,22 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset,
fpu__prepare_read(fpu); fpu__prepare_read(fpu);
if (!boot_cpu_has(X86_FEATURE_FPU)) if (!boot_cpu_has(X86_FEATURE_FPU))
return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf); return fpregs_soft_get(target, regset, to);
if (!boot_cpu_has(X86_FEATURE_FXSR)) if (!boot_cpu_has(X86_FEATURE_FXSR)) {
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, &fpu->state.fsave,
&fpu->state.fsave, 0, sizeof(struct fregs_state));
-1); }
fpstate_sanitize_xstate(fpu); fpstate_sanitize_xstate(fpu);
if (kbuf && pos == 0 && count == sizeof(env)) { if (to.left == sizeof(env)) {
convert_from_fxsr(kbuf, target); convert_from_fxsr(to.p, target);
return 0; return 0;
} }
convert_from_fxsr(&env, target); convert_from_fxsr(&env, target);
return membuf_write(&to, &env, sizeof(env));
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &env, 0, -1);
} }
int fpregs_set(struct task_struct *target, const struct user_regset *regset, int fpregs_set(struct task_struct *target, const struct user_regset *regset,
...@@ -356,20 +347,4 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, ...@@ -356,20 +347,4 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
return ret; return ret;
} }
/*
* FPU state for core dumps.
* This is only used for a.out dumps now.
* It is declared generically using elf_fpregset_t (which is
* struct user_i387_struct) but is in fact only used for 32-bit
* dumps, so on 64-bit it is really struct user_i387_ia32_struct.
*/
int dump_fpu(struct pt_regs *regs, struct user_i387_struct *ufpu)
{
struct task_struct *tsk = current;
return !fpregs_get(tsk, NULL, 0, sizeof(struct user_i387_ia32_struct),
ufpu, NULL);
}
EXPORT_SYMBOL(dump_fpu);
#endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */ #endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
...@@ -170,14 +170,15 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) ...@@ -170,14 +170,15 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
ia32_fxstate &= (IS_ENABLED(CONFIG_X86_32) || ia32_fxstate &= (IS_ENABLED(CONFIG_X86_32) ||
IS_ENABLED(CONFIG_IA32_EMULATION)); IS_ENABLED(CONFIG_IA32_EMULATION));
if (!static_cpu_has(X86_FEATURE_FPU)) {
struct user_i387_ia32_struct fp;
fpregs_soft_get(current, NULL, (struct membuf){.p = &fp,
.left = sizeof(fp)});
return copy_to_user(buf, &fp, sizeof(fp)) ? -EFAULT : 0;
}
if (!access_ok(buf, size)) if (!access_ok(buf, size))
return -EACCES; return -EACCES;
if (!static_cpu_has(X86_FEATURE_FPU))
return fpregs_soft_get(current, NULL, 0,
sizeof(struct user_i387_ia32_struct), NULL,
(struct _fpstate_32 __user *) buf) ? -1 : 1;
retry: retry:
/* /*
* Load the FPU registers if they are not valid for the current task. * Load the FPU registers if they are not valid for the current task.
......
...@@ -1014,32 +1014,20 @@ static inline bool xfeatures_mxcsr_quirk(u64 xfeatures) ...@@ -1014,32 +1014,20 @@ static inline bool xfeatures_mxcsr_quirk(u64 xfeatures)
return true; return true;
} }
static void fill_gap(unsigned to, void **kbuf, unsigned *pos, unsigned *count) static void fill_gap(struct membuf *to, unsigned *last, unsigned offset)
{ {
if (*pos < to) { if (*last >= offset)
unsigned size = to - *pos; return;
membuf_write(to, (void *)&init_fpstate.xsave + *last, offset - *last);
if (size > *count) *last = offset;
size = *count;
memcpy(*kbuf, (void *)&init_fpstate.xsave + *pos, size);
*kbuf += size;
*pos += size;
*count -= size;
}
} }
static void copy_part(unsigned offset, unsigned size, void *from, static void copy_part(struct membuf *to, unsigned *last, unsigned offset,
void **kbuf, unsigned *pos, unsigned *count) unsigned size, void *from)
{ {
fill_gap(offset, kbuf, pos, count); fill_gap(to, last, offset);
if (size > *count) membuf_write(to, from, size);
size = *count; *last = offset + size;
if (size) {
memcpy(*kbuf, from, size);
*kbuf += size;
*pos += size;
*count -= size;
}
} }
/* /*
...@@ -1049,19 +1037,14 @@ static void copy_part(unsigned offset, unsigned size, void *from, ...@@ -1049,19 +1037,14 @@ static void copy_part(unsigned offset, unsigned size, void *from,
* It supports partial copy but pos always starts from zero. This is called * It supports partial copy but pos always starts from zero. This is called
* from xstateregs_get() and there we check the CPU has XSAVES. * from xstateregs_get() and there we check the CPU has XSAVES.
*/ */
int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int offset_start, unsigned int size_total) void copy_xstate_to_kernel(struct membuf to, struct xregs_state *xsave)
{ {
struct xstate_header header; struct xstate_header header;
const unsigned off_mxcsr = offsetof(struct fxregs_state, mxcsr); const unsigned off_mxcsr = offsetof(struct fxregs_state, mxcsr);
unsigned count = size_total; unsigned size = to.left;
unsigned last = 0;
int i; int i;
/*
* Currently copy_regset_to_user() starts from pos 0:
*/
if (unlikely(offset_start != 0))
return -EFAULT;
/* /*
* The destination is a ptrace buffer; we put in only user xstates: * The destination is a ptrace buffer; we put in only user xstates:
*/ */
...@@ -1070,27 +1053,26 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of ...@@ -1070,27 +1053,26 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of
header.xfeatures &= xfeatures_mask_user(); header.xfeatures &= xfeatures_mask_user();
if (header.xfeatures & XFEATURE_MASK_FP) if (header.xfeatures & XFEATURE_MASK_FP)
copy_part(0, off_mxcsr, copy_part(&to, &last, 0, off_mxcsr, &xsave->i387);
&xsave->i387, &kbuf, &offset_start, &count);
if (header.xfeatures & (XFEATURE_MASK_SSE | XFEATURE_MASK_YMM)) if (header.xfeatures & (XFEATURE_MASK_SSE | XFEATURE_MASK_YMM))
copy_part(off_mxcsr, MXCSR_AND_FLAGS_SIZE, copy_part(&to, &last, off_mxcsr,
&xsave->i387.mxcsr, &kbuf, &offset_start, &count); MXCSR_AND_FLAGS_SIZE, &xsave->i387.mxcsr);
if (header.xfeatures & XFEATURE_MASK_FP) if (header.xfeatures & XFEATURE_MASK_FP)
copy_part(offsetof(struct fxregs_state, st_space), 128, copy_part(&to, &last, offsetof(struct fxregs_state, st_space),
&xsave->i387.st_space, &kbuf, &offset_start, &count); 128, &xsave->i387.st_space);
if (header.xfeatures & XFEATURE_MASK_SSE) if (header.xfeatures & XFEATURE_MASK_SSE)
copy_part(xstate_offsets[XFEATURE_SSE], 256, copy_part(&to, &last, xstate_offsets[XFEATURE_SSE],
&xsave->i387.xmm_space, &kbuf, &offset_start, &count); 256, &xsave->i387.xmm_space);
/* /*
* Fill xsave->i387.sw_reserved value for ptrace frame: * Fill xsave->i387.sw_reserved value for ptrace frame:
*/ */
copy_part(offsetof(struct fxregs_state, sw_reserved), 48, copy_part(&to, &last, offsetof(struct fxregs_state, sw_reserved),
xstate_fx_sw_bytes, &kbuf, &offset_start, &count); 48, xstate_fx_sw_bytes);
/* /*
* Copy xregs_state->header: * Copy xregs_state->header:
*/ */
copy_part(offsetof(struct xregs_state, header), sizeof(header), copy_part(&to, &last, offsetof(struct xregs_state, header),
&header, &kbuf, &offset_start, &count); sizeof(header), &header);
for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) { for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) {
/* /*
...@@ -1099,104 +1081,12 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of ...@@ -1099,104 +1081,12 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of
if ((header.xfeatures >> i) & 1) { if ((header.xfeatures >> i) & 1) {
void *src = __raw_xsave_addr(xsave, i); void *src = __raw_xsave_addr(xsave, i);
copy_part(xstate_offsets[i], xstate_sizes[i], copy_part(&to, &last, xstate_offsets[i],
src, &kbuf, &offset_start, &count); xstate_sizes[i], src);
} }
} }
fill_gap(size_total, &kbuf, &offset_start, &count); fill_gap(&to, &last, size);
return 0;
}
static inline int
__copy_xstate_to_user(void __user *ubuf, const void *data, unsigned int offset, unsigned int size, unsigned int size_total)
{
if (!size)
return 0;
if (offset < size_total) {
unsigned int copy = min(size, size_total - offset);
if (__copy_to_user(ubuf + offset, data, copy))
return -EFAULT;
}
return 0;
}
/*
* Convert from kernel XSAVES compacted format to standard format and copy
* to a user-space buffer. It supports partial copy but pos always starts from
* zero. This is called from xstateregs_get() and there we check the CPU
* has XSAVES.
*/
int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned int offset_start, unsigned int size_total)
{
unsigned int offset, size;
int ret, i;
struct xstate_header header;
/*
* Currently copy_regset_to_user() starts from pos 0:
*/
if (unlikely(offset_start != 0))
return -EFAULT;
/*
* The destination is a ptrace buffer; we put in only user xstates:
*/
memset(&header, 0, sizeof(header));
header.xfeatures = xsave->header.xfeatures;
header.xfeatures &= xfeatures_mask_user();
/*
* Copy xregs_state->header:
*/
offset = offsetof(struct xregs_state, header);
size = sizeof(header);
ret = __copy_xstate_to_user(ubuf, &header, offset, size, size_total);
if (ret)
return ret;
for (i = 0; i < XFEATURE_MAX; i++) {
/*
* Copy only in-use xstates:
*/
if ((header.xfeatures >> i) & 1) {
void *src = __raw_xsave_addr(xsave, i);
offset = xstate_offsets[i];
size = xstate_sizes[i];
/* The next component has to fit fully into the output buffer: */
if (offset + size > size_total)
break;
ret = __copy_xstate_to_user(ubuf, src, offset, size, size_total);
if (ret)
return ret;
}
}
if (xfeatures_mxcsr_quirk(header.xfeatures)) {
offset = offsetof(struct fxregs_state, mxcsr);
size = MXCSR_AND_FLAGS_SIZE;
__copy_xstate_to_user(ubuf, &xsave->i387.mxcsr, offset, size, size_total);
}
/*
* Fill xsave->i387.sw_reserved value for ptrace frame:
*/
offset = offsetof(struct fxregs_state, sw_reserved);
size = sizeof(xstate_fx_sw_bytes);
ret = __copy_xstate_to_user(ubuf, xstate_fx_sw_bytes, offset, size, size_total);
if (ret)
return ret;
return 0;
} }
/* /*
......
...@@ -412,26 +412,12 @@ static unsigned long getreg(struct task_struct *task, unsigned long offset) ...@@ -412,26 +412,12 @@ static unsigned long getreg(struct task_struct *task, unsigned long offset)
static int genregs_get(struct task_struct *target, static int genregs_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
if (kbuf) { int reg;
unsigned long *k = kbuf;
while (count >= sizeof(*k)) {
*k++ = getreg(target, pos);
count -= sizeof(*k);
pos += sizeof(*k);
}
} else {
unsigned long __user *u = ubuf;
while (count >= sizeof(*u)) {
if (__put_user(getreg(target, pos), u++))
return -EFAULT;
count -= sizeof(*u);
pos += sizeof(*u);
}
}
for (reg = 0; to.left; reg++)
membuf_store(&to, getreg(target, reg * sizeof(unsigned long)));
return 0; return 0;
} }
...@@ -695,16 +681,14 @@ static int ioperm_active(struct task_struct *target, ...@@ -695,16 +681,14 @@ static int ioperm_active(struct task_struct *target,
static int ioperm_get(struct task_struct *target, static int ioperm_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct io_bitmap *iobm = target->thread.io_bitmap; struct io_bitmap *iobm = target->thread.io_bitmap;
if (!iobm) if (!iobm)
return -ENXIO; return -ENXIO;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, iobm->bitmap, IO_BITMAP_BYTES);
iobm->bitmap, 0, IO_BITMAP_BYTES);
} }
/* /*
...@@ -1007,28 +991,15 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val) ...@@ -1007,28 +991,15 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
static int genregs32_get(struct task_struct *target, static int genregs32_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
if (kbuf) { int reg;
compat_ulong_t *k = kbuf;
while (count >= sizeof(*k)) {
getreg32(target, pos, k++);
count -= sizeof(*k);
pos += sizeof(*k);
}
} else {
compat_ulong_t __user *u = ubuf;
while (count >= sizeof(*u)) {
compat_ulong_t word;
getreg32(target, pos, &word);
if (__put_user(word, u++))
return -EFAULT;
count -= sizeof(*u);
pos += sizeof(*u);
}
}
for (reg = 0; to.left; reg++) {
u32 val;
getreg32(target, reg * 4, &val);
membuf_store(&to, val);
}
return 0; return 0;
} }
...@@ -1238,25 +1209,25 @@ static struct user_regset x86_64_regsets[] __ro_after_init = { ...@@ -1238,25 +1209,25 @@ static struct user_regset x86_64_regsets[] __ro_after_init = {
.core_note_type = NT_PRSTATUS, .core_note_type = NT_PRSTATUS,
.n = sizeof(struct user_regs_struct) / sizeof(long), .n = sizeof(struct user_regs_struct) / sizeof(long),
.size = sizeof(long), .align = sizeof(long), .size = sizeof(long), .align = sizeof(long),
.get = genregs_get, .set = genregs_set .regset_get = genregs_get, .set = genregs_set
}, },
[REGSET_FP] = { [REGSET_FP] = {
.core_note_type = NT_PRFPREG, .core_note_type = NT_PRFPREG,
.n = sizeof(struct user_i387_struct) / sizeof(long), .n = sizeof(struct user_i387_struct) / sizeof(long),
.size = sizeof(long), .align = sizeof(long), .size = sizeof(long), .align = sizeof(long),
.active = regset_xregset_fpregs_active, .get = xfpregs_get, .set = xfpregs_set .active = regset_xregset_fpregs_active, .regset_get = xfpregs_get, .set = xfpregs_set
}, },
[REGSET_XSTATE] = { [REGSET_XSTATE] = {
.core_note_type = NT_X86_XSTATE, .core_note_type = NT_X86_XSTATE,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.active = xstateregs_active, .get = xstateregs_get, .active = xstateregs_active, .regset_get = xstateregs_get,
.set = xstateregs_set .set = xstateregs_set
}, },
[REGSET_IOPERM64] = { [REGSET_IOPERM64] = {
.core_note_type = NT_386_IOPERM, .core_note_type = NT_386_IOPERM,
.n = IO_BITMAP_LONGS, .n = IO_BITMAP_LONGS,
.size = sizeof(long), .align = sizeof(long), .size = sizeof(long), .align = sizeof(long),
.active = ioperm_active, .get = ioperm_get .active = ioperm_active, .regset_get = ioperm_get
}, },
}; };
...@@ -1279,24 +1250,24 @@ static struct user_regset x86_32_regsets[] __ro_after_init = { ...@@ -1279,24 +1250,24 @@ static struct user_regset x86_32_regsets[] __ro_after_init = {
.core_note_type = NT_PRSTATUS, .core_note_type = NT_PRSTATUS,
.n = sizeof(struct user_regs_struct32) / sizeof(u32), .n = sizeof(struct user_regs_struct32) / sizeof(u32),
.size = sizeof(u32), .align = sizeof(u32), .size = sizeof(u32), .align = sizeof(u32),
.get = genregs32_get, .set = genregs32_set .regset_get = genregs32_get, .set = genregs32_set
}, },
[REGSET_FP] = { [REGSET_FP] = {
.core_note_type = NT_PRFPREG, .core_note_type = NT_PRFPREG,
.n = sizeof(struct user_i387_ia32_struct) / sizeof(u32), .n = sizeof(struct user_i387_ia32_struct) / sizeof(u32),
.size = sizeof(u32), .align = sizeof(u32), .size = sizeof(u32), .align = sizeof(u32),
.active = regset_fpregs_active, .get = fpregs_get, .set = fpregs_set .active = regset_fpregs_active, .regset_get = fpregs_get, .set = fpregs_set
}, },
[REGSET_XFP] = { [REGSET_XFP] = {
.core_note_type = NT_PRXFPREG, .core_note_type = NT_PRXFPREG,
.n = sizeof(struct user32_fxsr_struct) / sizeof(u32), .n = sizeof(struct user32_fxsr_struct) / sizeof(u32),
.size = sizeof(u32), .align = sizeof(u32), .size = sizeof(u32), .align = sizeof(u32),
.active = regset_xregset_fpregs_active, .get = xfpregs_get, .set = xfpregs_set .active = regset_xregset_fpregs_active, .regset_get = xfpregs_get, .set = xfpregs_set
}, },
[REGSET_XSTATE] = { [REGSET_XSTATE] = {
.core_note_type = NT_X86_XSTATE, .core_note_type = NT_X86_XSTATE,
.size = sizeof(u64), .align = sizeof(u64), .size = sizeof(u64), .align = sizeof(u64),
.active = xstateregs_active, .get = xstateregs_get, .active = xstateregs_active, .regset_get = xstateregs_get,
.set = xstateregs_set .set = xstateregs_set
}, },
[REGSET_TLS] = { [REGSET_TLS] = {
...@@ -1305,13 +1276,13 @@ static struct user_regset x86_32_regsets[] __ro_after_init = { ...@@ -1305,13 +1276,13 @@ static struct user_regset x86_32_regsets[] __ro_after_init = {
.size = sizeof(struct user_desc), .size = sizeof(struct user_desc),
.align = sizeof(struct user_desc), .align = sizeof(struct user_desc),
.active = regset_tls_active, .active = regset_tls_active,
.get = regset_tls_get, .set = regset_tls_set .regset_get = regset_tls_get, .set = regset_tls_set
}, },
[REGSET_IOPERM32] = { [REGSET_IOPERM32] = {
.core_note_type = NT_386_IOPERM, .core_note_type = NT_386_IOPERM,
.n = IO_BITMAP_BYTES / sizeof(u32), .n = IO_BITMAP_BYTES / sizeof(u32),
.size = sizeof(u32), .align = sizeof(u32), .size = sizeof(u32), .align = sizeof(u32),
.active = ioperm_active, .get = ioperm_get .active = ioperm_active, .regset_get = ioperm_get
}, },
}; };
......
...@@ -256,36 +256,16 @@ int regset_tls_active(struct task_struct *target, ...@@ -256,36 +256,16 @@ int regset_tls_active(struct task_struct *target,
} }
int regset_tls_get(struct task_struct *target, const struct user_regset *regset, int regset_tls_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
const struct desc_struct *tls; const struct desc_struct *tls;
struct user_desc v;
int pos;
if (pos >= GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) || for (pos = 0, tls = target->thread.tls_array; to.left; pos++, tls++) {
(pos % sizeof(struct user_desc)) != 0 || fill_user_desc(&v, GDT_ENTRY_TLS_MIN + pos, tls);
(count % sizeof(struct user_desc)) != 0) membuf_write(&to, &v, sizeof(v));
return -EINVAL;
pos /= sizeof(struct user_desc);
count /= sizeof(struct user_desc);
tls = &target->thread.tls_array[pos];
if (kbuf) {
struct user_desc *info = kbuf;
while (count-- > 0)
fill_user_desc(info++, GDT_ENTRY_TLS_MIN + pos++,
tls++);
} else {
struct user_desc __user *u_info = ubuf;
while (count-- > 0) {
struct user_desc info;
fill_user_desc(&info, GDT_ENTRY_TLS_MIN + pos++, tls++);
if (__copy_to_user(u_info++, &info, sizeof(info)))
return -EFAULT;
}
} }
return 0; return 0;
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include <linux/regset.h> #include <linux/regset.h>
extern user_regset_active_fn regset_tls_active; extern user_regset_active_fn regset_tls_active;
extern user_regset_get_fn regset_tls_get; extern user_regset_get2_fn regset_tls_get;
extern user_regset_set_fn regset_tls_set; extern user_regset_set_fn regset_tls_set;
#endif /* _ARCH_X86_KERNEL_TLS_H */ #endif /* _ARCH_X86_KERNEL_TLS_H */
...@@ -689,12 +689,10 @@ int fpregs_soft_set(struct task_struct *target, ...@@ -689,12 +689,10 @@ int fpregs_soft_set(struct task_struct *target,
int fpregs_soft_get(struct task_struct *target, int fpregs_soft_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct swregs_state *s387 = &target->thread.fpu.state.soft; struct swregs_state *s387 = &target->thread.fpu.state.soft;
const void *space = s387->st_space; const void *space = s387->st_space;
int ret;
int offset = (S387->ftop & 7) * 10, other = 80 - offset; int offset = (S387->ftop & 7) * 10, other = 80 - offset;
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
...@@ -709,18 +707,11 @@ int fpregs_soft_get(struct task_struct *target, ...@@ -709,18 +707,11 @@ int fpregs_soft_get(struct task_struct *target,
S387->fos |= 0xffff0000; S387->fos |= 0xffff0000;
#endif /* PECULIAR_486 */ #endif /* PECULIAR_486 */
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, s387, 0, membuf_write(&to, s387, offsetof(struct swregs_state, st_space));
offsetof(struct swregs_state, st_space)); membuf_write(&to, space + offset, other);
membuf_write(&to, space, offset);
/* Copy all registers in stack order. */
if (!ret)
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
space + offset, 0, other);
if (!ret)
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
space, 0, offset);
RE_ENTRANT_CHECK_ON; RE_ENTRANT_CHECK_ON;
return ret; return 0;
} }
...@@ -39,8 +39,7 @@ ...@@ -39,8 +39,7 @@
static int gpr_get(struct task_struct *target, static int gpr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
struct pt_regs *regs = task_pt_regs(target); struct pt_regs *regs = task_pt_regs(target);
struct user_pt_regs newregs = { struct user_pt_regs newregs = {
...@@ -63,8 +62,7 @@ static int gpr_get(struct task_struct *target, ...@@ -63,8 +62,7 @@ static int gpr_get(struct task_struct *target,
regs->areg, regs->areg,
(WSBITS - regs->windowbase) * 16); (WSBITS - regs->windowbase) * 16);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return membuf_write(&to, &newregs, sizeof(newregs));
&newregs, 0, -1);
} }
static int gpr_set(struct task_struct *target, static int gpr_set(struct task_struct *target,
...@@ -121,8 +119,7 @@ static int gpr_set(struct task_struct *target, ...@@ -121,8 +119,7 @@ static int gpr_set(struct task_struct *target,
static int tie_get(struct task_struct *target, static int tie_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to)
void *kbuf, void __user *ubuf)
{ {
int ret; int ret;
struct pt_regs *regs = task_pt_regs(target); struct pt_regs *regs = task_pt_regs(target);
...@@ -147,8 +144,7 @@ static int tie_get(struct task_struct *target, ...@@ -147,8 +144,7 @@ static int tie_get(struct task_struct *target,
newregs->cp6 = ti->xtregs_cp.cp6; newregs->cp6 = ti->xtregs_cp.cp6;
newregs->cp7 = ti->xtregs_cp.cp7; newregs->cp7 = ti->xtregs_cp.cp7;
#endif #endif
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, ret = membuf_write(&to, newregs, sizeof(*newregs));
newregs, 0, -1);
kfree(newregs); kfree(newregs);
return ret; return ret;
} }
...@@ -203,7 +199,7 @@ static const struct user_regset xtensa_regsets[] = { ...@@ -203,7 +199,7 @@ static const struct user_regset xtensa_regsets[] = {
.n = sizeof(struct user_pt_regs) / sizeof(u32), .n = sizeof(struct user_pt_regs) / sizeof(u32),
.size = sizeof(u32), .size = sizeof(u32),
.align = sizeof(u32), .align = sizeof(u32),
.get = gpr_get, .regset_get = gpr_get,
.set = gpr_set, .set = gpr_set,
}, },
[REGSET_TIE] = { [REGSET_TIE] = {
...@@ -211,7 +207,7 @@ static const struct user_regset xtensa_regsets[] = { ...@@ -211,7 +207,7 @@ static const struct user_regset xtensa_regsets[] = {
.n = sizeof(elf_xtregs_t) / sizeof(u32), .n = sizeof(elf_xtregs_t) / sizeof(u32),
.size = sizeof(u32), .size = sizeof(u32),
.align = sizeof(u32), .align = sizeof(u32),
.get = tie_get, .regset_get = tie_get,
.set = tie_set, .set = tie_set,
}, },
}; };
......
...@@ -1821,7 +1821,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, ...@@ -1821,7 +1821,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
long signr, size_t *total) long signr, size_t *total)
{ {
unsigned int i; unsigned int i;
unsigned int regset0_size = regset_size(t->task, &view->regsets[0]); int regset0_size;
/* /*
* NT_PRSTATUS is the one special case, because the regset data * NT_PRSTATUS is the one special case, because the regset data
...@@ -1830,8 +1830,10 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, ...@@ -1830,8 +1830,10 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
* We assume that regset 0 is NT_PRSTATUS. * We assume that regset 0 is NT_PRSTATUS.
*/ */
fill_prstatus(&t->prstatus, t->task, signr); fill_prstatus(&t->prstatus, t->task, signr);
(void) view->regsets[0].get(t->task, &view->regsets[0], 0, regset0_size, regset0_size = regset_get(t->task, &view->regsets[0],
&t->prstatus.pr_reg, NULL); sizeof(t->prstatus.pr_reg), &t->prstatus.pr_reg);
if (regset0_size < 0)
return 0;
fill_note(&t->notes[0], "CORE", NT_PRSTATUS, fill_note(&t->notes[0], "CORE", NT_PRSTATUS,
PRSTATUS_SIZE(t->prstatus, regset0_size), &t->prstatus); PRSTATUS_SIZE(t->prstatus, regset0_size), &t->prstatus);
...@@ -1846,32 +1848,28 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, ...@@ -1846,32 +1848,28 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
*/ */
for (i = 1; i < view->n; ++i) { for (i = 1; i < view->n; ++i) {
const struct user_regset *regset = &view->regsets[i]; const struct user_regset *regset = &view->regsets[i];
int note_type = regset->core_note_type;
bool is_fpreg = note_type == NT_PRFPREG;
void *data;
int ret;
do_thread_regset_writeback(t->task, regset); do_thread_regset_writeback(t->task, regset);
if (regset->core_note_type && regset->get && if (!note_type) // not for coredumps
(!regset->active || regset->active(t->task, regset) > 0)) { continue;
int ret; if (regset->active && regset->active(t->task, regset) <= 0)
size_t size = regset_size(t->task, regset); continue;
void *data = kzalloc(size, GFP_KERNEL);
if (unlikely(!data)) ret = regset_get_alloc(t->task, regset, ~0U, &data);
return 0; if (ret < 0)
ret = regset->get(t->task, regset, continue;
0, size, data, NULL);
if (unlikely(ret)) if (is_fpreg)
kfree(data); SET_PR_FPVALID(&t->prstatus, 1, regset0_size);
else {
if (regset->core_note_type != NT_PRFPREG) fill_note(&t->notes[i], is_fpreg ? "CORE" : "LINUX",
fill_note(&t->notes[i], "LINUX", note_type, ret, data);
regset->core_note_type,
size, data); *total += notesize(&t->notes[i]);
else {
SET_PR_FPVALID(&t->prstatus,
1, regset0_size);
fill_note(&t->notes[i], "CORE",
NT_PRFPREG, size, data);
}
*total += notesize(&t->notes[i]);
}
}
} }
return 1; return 1;
......
...@@ -17,6 +17,52 @@ ...@@ -17,6 +17,52 @@
struct task_struct; struct task_struct;
struct user_regset; struct user_regset;
struct membuf {
void *p;
size_t left;
};
static inline int membuf_zero(struct membuf *s, size_t size)
{
if (s->left) {
if (size > s->left)
size = s->left;
memset(s->p, 0, size);
s->p += size;
s->left -= size;
}
return s->left;
}
static inline int membuf_write(struct membuf *s, const void *v, size_t size)
{
if (s->left) {
if (size > s->left)
size = s->left;
memcpy(s->p, v, size);
s->p += size;
s->left -= size;
}
return s->left;
}
/* current s->p must be aligned for v; v must be a scalar */
#define membuf_store(s, v) \
({ \
struct membuf *__s = (s); \
if (__s->left) { \
typeof(v) __v = (v); \
size_t __size = sizeof(__v); \
if (unlikely(__size > __s->left)) { \
__size = __s->left; \
memcpy(__s->p, &__v, __size); \
} else { \
*(typeof(__v + 0) *)__s->p = __v; \
} \
__s->p += __size; \
__s->left -= __size; \
} \
__s->left;})
/** /**
* user_regset_active_fn - type of @active function in &struct user_regset * user_regset_active_fn - type of @active function in &struct user_regset
...@@ -36,26 +82,9 @@ struct user_regset; ...@@ -36,26 +82,9 @@ struct user_regset;
typedef int user_regset_active_fn(struct task_struct *target, typedef int user_regset_active_fn(struct task_struct *target,
const struct user_regset *regset); const struct user_regset *regset);
/** typedef int user_regset_get2_fn(struct task_struct *target,
* user_regset_get_fn - type of @get function in &struct user_regset
* @target: thread being examined
* @regset: regset being examined
* @pos: offset into the regset data to access, in bytes
* @count: amount of data to copy, in bytes
* @kbuf: if not %NULL, a kernel-space pointer to copy into
* @ubuf: if @kbuf is %NULL, a user-space pointer to copy into
*
* Fetch register values. Return %0 on success; -%EIO or -%ENODEV
* are usual failure returns. The @pos and @count values are in
* bytes, but must be properly aligned. If @kbuf is non-null, that
* buffer is used and @ubuf is ignored. If @kbuf is %NULL, then
* ubuf gives a userland pointer to access directly, and an -%EFAULT
* return value is possible.
*/
typedef int user_regset_get_fn(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, struct membuf to);
void *kbuf, void __user *ubuf);
/** /**
* user_regset_set_fn - type of @set function in &struct user_regset * user_regset_set_fn - type of @set function in &struct user_regset
...@@ -103,28 +132,6 @@ typedef int user_regset_writeback_fn(struct task_struct *target, ...@@ -103,28 +132,6 @@ typedef int user_regset_writeback_fn(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
int immediate); int immediate);
/**
* user_regset_get_size_fn - type of @get_size function in &struct user_regset
* @target: thread being examined
* @regset: regset being examined
*
* This call is optional; usually the pointer is %NULL.
*
* When provided, this function must return the current size of regset
* data, as observed by the @get function in &struct user_regset. The
* value returned must be a multiple of @size. The returned size is
* required to be valid only until the next time (if any) @regset is
* modified for @target.
*
* This function is intended for dynamically sized regsets. A regset
* that is statically sized does not need to implement it.
*
* This function should not be called directly: instead, callers should
* call regset_size() to determine the current size of a regset.
*/
typedef unsigned int user_regset_get_size_fn(struct task_struct *target,
const struct user_regset *regset);
/** /**
* struct user_regset - accessible thread CPU state * struct user_regset - accessible thread CPU state
* @n: Number of slots (registers). * @n: Number of slots (registers).
...@@ -136,7 +143,6 @@ typedef unsigned int user_regset_get_size_fn(struct task_struct *target, ...@@ -136,7 +143,6 @@ typedef unsigned int user_regset_get_size_fn(struct task_struct *target,
* @set: Function to store values. * @set: Function to store values.
* @active: Function to report if regset is active, or %NULL. * @active: Function to report if regset is active, or %NULL.
* @writeback: Function to write data back to user memory, or %NULL. * @writeback: Function to write data back to user memory, or %NULL.
* @get_size: Function to return the regset's size, or %NULL.
* *
* This data structure describes a machine resource we call a register set. * This data structure describes a machine resource we call a register set.
* This is part of the state of an individual thread, not necessarily * This is part of the state of an individual thread, not necessarily
...@@ -144,12 +150,7 @@ typedef unsigned int user_regset_get_size_fn(struct task_struct *target, ...@@ -144,12 +150,7 @@ typedef unsigned int user_regset_get_size_fn(struct task_struct *target,
* similar slots, given by @n. Each slot is @size bytes, and aligned to * similar slots, given by @n. Each slot is @size bytes, and aligned to
* @align bytes (which is at least @size). For dynamically-sized * @align bytes (which is at least @size). For dynamically-sized
* regsets, @n must contain the maximum possible number of slots for the * regsets, @n must contain the maximum possible number of slots for the
* regset, and @get_size must point to a function that returns the * regset.
* current regset size.
*
* Callers that need to know only the current size of the regset and do
* not care about its internal structure should call regset_size()
* instead of inspecting @n or calling @get_size.
* *
* For backward compatibility, the @get and @set methods must pad to, or * For backward compatibility, the @get and @set methods must pad to, or
* accept, @n * @size bytes, even if the current regset size is smaller. * accept, @n * @size bytes, even if the current regset size is smaller.
...@@ -185,11 +186,10 @@ typedef unsigned int user_regset_get_size_fn(struct task_struct *target, ...@@ -185,11 +186,10 @@ typedef unsigned int user_regset_get_size_fn(struct task_struct *target,
* omitted when there is an @active function and it returns zero. * omitted when there is an @active function and it returns zero.
*/ */
struct user_regset { struct user_regset {
user_regset_get_fn *get; user_regset_get2_fn *regset_get;
user_regset_set_fn *set; user_regset_set_fn *set;
user_regset_active_fn *active; user_regset_active_fn *active;
user_regset_writeback_fn *writeback; user_regset_writeback_fn *writeback;
user_regset_get_size_fn *get_size;
unsigned int n; unsigned int n;
unsigned int size; unsigned int size;
unsigned int align; unsigned int align;
...@@ -238,44 +238,6 @@ struct user_regset_view { ...@@ -238,44 +238,6 @@ struct user_regset_view {
*/ */
const struct user_regset_view *task_user_regset_view(struct task_struct *tsk); const struct user_regset_view *task_user_regset_view(struct task_struct *tsk);
/*
* These are helpers for writing regset get/set functions in arch code.
* Because @start_pos and @end_pos are always compile-time constants,
* these are inlined into very little code though they look large.
*
* Use one or more calls sequentially for each chunk of regset data stored
* contiguously in memory. Call with constants for @start_pos and @end_pos,
* giving the range of byte positions in the regset that data corresponds
* to; @end_pos can be -1 if this chunk is at the end of the regset layout.
* Each call updates the arguments to point past its chunk.
*/
static inline int user_regset_copyout(unsigned int *pos, unsigned int *count,
void **kbuf,
void __user **ubuf, const void *data,
const int start_pos, const int end_pos)
{
if (*count == 0)
return 0;
BUG_ON(*pos < start_pos);
if (end_pos < 0 || *pos < end_pos) {
unsigned int copy = (end_pos < 0 ? *count
: min(*count, end_pos - *pos));
data += *pos - start_pos;
if (*kbuf) {
memcpy(*kbuf, data, copy);
*kbuf += copy;
} else if (__copy_to_user(*ubuf, data, copy))
return -EFAULT;
else
*ubuf += copy;
*pos += copy;
*count -= copy;
}
return 0;
}
static inline int user_regset_copyin(unsigned int *pos, unsigned int *count, static inline int user_regset_copyin(unsigned int *pos, unsigned int *count,
const void **kbuf, const void **kbuf,
const void __user **ubuf, void *data, const void __user **ubuf, void *data,
...@@ -301,35 +263,6 @@ static inline int user_regset_copyin(unsigned int *pos, unsigned int *count, ...@@ -301,35 +263,6 @@ static inline int user_regset_copyin(unsigned int *pos, unsigned int *count,
return 0; return 0;
} }
/*
* These two parallel the two above, but for portions of a regset layout
* that always read as all-zero or for which writes are ignored.
*/
static inline int user_regset_copyout_zero(unsigned int *pos,
unsigned int *count,
void **kbuf, void __user **ubuf,
const int start_pos,
const int end_pos)
{
if (*count == 0)
return 0;
BUG_ON(*pos < start_pos);
if (end_pos < 0 || *pos < end_pos) {
unsigned int copy = (end_pos < 0 ? *count
: min(*count, end_pos - *pos));
if (*kbuf) {
memset(*kbuf, 0, copy);
*kbuf += copy;
} else if (clear_user(*ubuf, copy))
return -EFAULT;
else
*ubuf += copy;
*pos += copy;
*count -= copy;
}
return 0;
}
static inline int user_regset_copyin_ignore(unsigned int *pos, static inline int user_regset_copyin_ignore(unsigned int *pos,
unsigned int *count, unsigned int *count,
const void **kbuf, const void **kbuf,
...@@ -353,31 +286,19 @@ static inline int user_regset_copyin_ignore(unsigned int *pos, ...@@ -353,31 +286,19 @@ static inline int user_regset_copyin_ignore(unsigned int *pos,
return 0; return 0;
} }
/** extern int regset_get(struct task_struct *target,
* copy_regset_to_user - fetch a thread's user_regset data into user memory const struct user_regset *regset,
* @target: thread to be examined unsigned int size, void *data);
* @view: &struct user_regset_view describing user thread machine state
* @setno: index in @view->regsets
* @offset: offset into the regset data, in bytes
* @size: amount of data to copy, in bytes
* @data: user-mode pointer to copy into
*/
static inline int copy_regset_to_user(struct task_struct *target,
const struct user_regset_view *view,
unsigned int setno,
unsigned int offset, unsigned int size,
void __user *data)
{
const struct user_regset *regset = &view->regsets[setno];
if (!regset->get)
return -EOPNOTSUPP;
if (!access_ok(data, size)) extern int regset_get_alloc(struct task_struct *target,
return -EFAULT; const struct user_regset *regset,
unsigned int size,
void **data);
return regset->get(target, regset, offset, size, NULL, data); extern int copy_regset_to_user(struct task_struct *target,
} const struct user_regset_view *view,
unsigned int setno, unsigned int offset,
unsigned int size, void __user *data);
/** /**
* copy_regset_from_user - store into thread's user_regset data from user memory * copy_regset_from_user - store into thread's user_regset data from user memory
...@@ -405,21 +326,4 @@ static inline int copy_regset_from_user(struct task_struct *target, ...@@ -405,21 +326,4 @@ static inline int copy_regset_from_user(struct task_struct *target,
return regset->set(target, regset, offset, size, NULL, data); return regset->set(target, regset, offset, size, NULL, data);
} }
/**
* regset_size - determine the current size of a regset
* @target: thread to be examined
* @regset: regset to be examined
*
* Note that the returned size is valid only until the next time
* (if any) @regset is modified for @target.
*/
static inline unsigned int regset_size(struct task_struct *target,
const struct user_regset *regset)
{
if (!regset->get_size)
return regset->n * regset->size;
else
return regset->get_size(target, regset);
}
#endif /* <linux/regset.h> */ #endif /* <linux/regset.h> */
...@@ -10,7 +10,7 @@ obj-y = fork.o exec_domain.o panic.o \ ...@@ -10,7 +10,7 @@ obj-y = fork.o exec_domain.o panic.o \
extable.o params.o \ extable.o params.o \
kthread.o sys_ni.o nsproxy.o \ kthread.o sys_ni.o nsproxy.o \
notifier.o ksysfs.o cred.o reboot.o \ notifier.o ksysfs.o cred.o reboot.o \
async.o range.o smpboot.o ucount.o async.o range.o smpboot.o ucount.o regset.o
obj-$(CONFIG_BPFILTER) += usermode_driver.o obj-$(CONFIG_BPFILTER) += usermode_driver.o
obj-$(CONFIG_MODULES) += kmod.o obj-$(CONFIG_MODULES) += kmod.o
......
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/regset.h>
static int __regset_get(struct task_struct *target,
const struct user_regset *regset,
unsigned int size,
void **data)
{
void *p = *data, *to_free = NULL;
int res;
if (!regset->regset_get)
return -EOPNOTSUPP;
if (size > regset->n * regset->size)
size = regset->n * regset->size;
if (!p) {
to_free = p = kzalloc(size, GFP_KERNEL);
if (!p)
return -ENOMEM;
}
res = regset->regset_get(target, regset,
(struct membuf){.p = p, .left = size});
if (res < 0) {
kfree(to_free);
return res;
}
*data = p;
return size - res;
}
int regset_get(struct task_struct *target,
const struct user_regset *regset,
unsigned int size,
void *data)
{
return __regset_get(target, regset, size, &data);
}
EXPORT_SYMBOL(regset_get);
int regset_get_alloc(struct task_struct *target,
const struct user_regset *regset,
unsigned int size,
void **data)
{
*data = NULL;
return __regset_get(target, regset, size, data);
}
EXPORT_SYMBOL(regset_get_alloc);
/**
* copy_regset_to_user - fetch a thread's user_regset data into user memory
* @target: thread to be examined
* @view: &struct user_regset_view describing user thread machine state
* @setno: index in @view->regsets
* @offset: offset into the regset data, in bytes
* @size: amount of data to copy, in bytes
* @data: user-mode pointer to copy into
*/
int copy_regset_to_user(struct task_struct *target,
const struct user_regset_view *view,
unsigned int setno,
unsigned int offset, unsigned int size,
void __user *data)
{
const struct user_regset *regset = &view->regsets[setno];
void *buf;
int ret;
ret = regset_get_alloc(target, regset, size, &buf);
if (ret > 0)
ret = copy_to_user(data, buf, ret) ? -EFAULT : 0;
kfree(buf);
return ret;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment