mirror of
https://github.com/torvalds/linux.git
synced 2024-12-27 21:33:00 +00:00
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() ...
This commit is contained in:
commit
19b39c38ab
@ -18,88 +18,61 @@ static struct callee_regs *task_callee_regs(struct task_struct *tsk)
|
||||
|
||||
static int genregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
const struct pt_regs *ptregs = task_pt_regs(target);
|
||||
const struct callee_regs *cregs = task_callee_regs(target);
|
||||
int ret = 0;
|
||||
unsigned int stop_pc_val;
|
||||
|
||||
#define REG_O_CHUNK(START, END, PTR) \
|
||||
if (!ret) \
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
|
||||
offsetof(struct user_regs_struct, START), \
|
||||
offsetof(struct user_regs_struct, END));
|
||||
membuf_zero(&to, 4); // pad
|
||||
membuf_store(&to, ptregs->bta);
|
||||
membuf_store(&to, ptregs->lp_start);
|
||||
membuf_store(&to, ptregs->lp_end);
|
||||
membuf_store(&to, ptregs->lp_count);
|
||||
membuf_store(&to, ptregs->status32);
|
||||
membuf_store(&to, ptregs->ret);
|
||||
membuf_store(&to, ptregs->blink);
|
||||
membuf_store(&to, ptregs->fp);
|
||||
membuf_store(&to, ptregs->r26); // gp
|
||||
membuf_store(&to, ptregs->r12);
|
||||
membuf_store(&to, ptregs->r11);
|
||||
membuf_store(&to, ptregs->r10);
|
||||
membuf_store(&to, ptregs->r9);
|
||||
membuf_store(&to, ptregs->r8);
|
||||
membuf_store(&to, ptregs->r7);
|
||||
membuf_store(&to, ptregs->r6);
|
||||
membuf_store(&to, ptregs->r5);
|
||||
membuf_store(&to, ptregs->r4);
|
||||
membuf_store(&to, ptregs->r3);
|
||||
membuf_store(&to, ptregs->r2);
|
||||
membuf_store(&to, ptregs->r1);
|
||||
membuf_store(&to, ptregs->r0);
|
||||
membuf_store(&to, ptregs->sp);
|
||||
membuf_zero(&to, 4); // pad2
|
||||
membuf_store(&to, cregs->r25);
|
||||
membuf_store(&to, cregs->r24);
|
||||
membuf_store(&to, cregs->r23);
|
||||
membuf_store(&to, cregs->r22);
|
||||
membuf_store(&to, cregs->r21);
|
||||
membuf_store(&to, cregs->r20);
|
||||
membuf_store(&to, cregs->r19);
|
||||
membuf_store(&to, cregs->r18);
|
||||
membuf_store(&to, cregs->r17);
|
||||
membuf_store(&to, cregs->r16);
|
||||
membuf_store(&to, cregs->r15);
|
||||
membuf_store(&to, cregs->r14);
|
||||
membuf_store(&to, cregs->r13);
|
||||
membuf_store(&to, target->thread.fault_address); // efa
|
||||
|
||||
#define REG_O_ONE(LOC, PTR) \
|
||||
if (!ret) \
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
|
||||
offsetof(struct user_regs_struct, LOC), \
|
||||
offsetof(struct user_regs_struct, LOC) + 4);
|
||||
|
||||
#define REG_O_ZERO(LOC) \
|
||||
if (!ret) \
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \
|
||||
offsetof(struct user_regs_struct, LOC), \
|
||||
offsetof(struct user_regs_struct, LOC) + 4);
|
||||
|
||||
REG_O_ZERO(pad);
|
||||
REG_O_ONE(scratch.bta, &ptregs->bta);
|
||||
REG_O_ONE(scratch.lp_start, &ptregs->lp_start);
|
||||
REG_O_ONE(scratch.lp_end, &ptregs->lp_end);
|
||||
REG_O_ONE(scratch.lp_count, &ptregs->lp_count);
|
||||
REG_O_ONE(scratch.status32, &ptregs->status32);
|
||||
REG_O_ONE(scratch.ret, &ptregs->ret);
|
||||
REG_O_ONE(scratch.blink, &ptregs->blink);
|
||||
REG_O_ONE(scratch.fp, &ptregs->fp);
|
||||
REG_O_ONE(scratch.gp, &ptregs->r26);
|
||||
REG_O_ONE(scratch.r12, &ptregs->r12);
|
||||
REG_O_ONE(scratch.r11, &ptregs->r11);
|
||||
REG_O_ONE(scratch.r10, &ptregs->r10);
|
||||
REG_O_ONE(scratch.r9, &ptregs->r9);
|
||||
REG_O_ONE(scratch.r8, &ptregs->r8);
|
||||
REG_O_ONE(scratch.r7, &ptregs->r7);
|
||||
REG_O_ONE(scratch.r6, &ptregs->r6);
|
||||
REG_O_ONE(scratch.r5, &ptregs->r5);
|
||||
REG_O_ONE(scratch.r4, &ptregs->r4);
|
||||
REG_O_ONE(scratch.r3, &ptregs->r3);
|
||||
REG_O_ONE(scratch.r2, &ptregs->r2);
|
||||
REG_O_ONE(scratch.r1, &ptregs->r1);
|
||||
REG_O_ONE(scratch.r0, &ptregs->r0);
|
||||
REG_O_ONE(scratch.sp, &ptregs->sp);
|
||||
|
||||
REG_O_ZERO(pad2);
|
||||
|
||||
REG_O_ONE(callee.r25, &cregs->r25);
|
||||
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);
|
||||
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");
|
||||
}
|
||||
|
||||
return ret;
|
||||
return membuf_store(&to, stop_pc_val); // stop_pc
|
||||
}
|
||||
|
||||
static int genregs_set(struct task_struct *target,
|
||||
@ -184,25 +157,20 @@ static int genregs_set(struct task_struct *target,
|
||||
#ifdef CONFIG_ISA_ARCV2
|
||||
static int arcv2regs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
const struct pt_regs *regs = task_pt_regs(target);
|
||||
int ret, copy_sz;
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARC_HAS_ACCL_REGS))
|
||||
copy_sz = sizeof(struct user_regs_arcv2);
|
||||
else
|
||||
copy_sz = 4; /* r30 only */
|
||||
/*
|
||||
* 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)
|
||||
*/
|
||||
return membuf_write(&to, ®s->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, ®s->r30,
|
||||
0, copy_sz);
|
||||
|
||||
return ret;
|
||||
membuf_write(&to, ®s->r30, 4); /* r30 only */
|
||||
return membuf_zero(&to, sizeof(struct user_regs_arcv2) - 4);
|
||||
}
|
||||
|
||||
static int arcv2regs_set(struct task_struct *target,
|
||||
@ -237,7 +205,7 @@ static const struct user_regset arc_regsets[] = {
|
||||
.n = ELF_NGREG,
|
||||
.size = sizeof(unsigned long),
|
||||
.align = sizeof(unsigned long),
|
||||
.get = genregs_get,
|
||||
.regset_get = genregs_get,
|
||||
.set = genregs_set,
|
||||
},
|
||||
#ifdef CONFIG_ISA_ARCV2
|
||||
@ -246,7 +214,7 @@ static const struct user_regset arc_regsets[] = {
|
||||
.n = ELF_ARCV2REG,
|
||||
.size = sizeof(unsigned long),
|
||||
.align = sizeof(unsigned long),
|
||||
.get = arcv2regs_get,
|
||||
.regset_get = arcv2regs_get,
|
||||
.set = arcv2regs_set,
|
||||
},
|
||||
#endif
|
||||
|
@ -569,14 +569,9 @@ out:
|
||||
|
||||
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)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
regs,
|
||||
0, sizeof(*regs));
|
||||
return membuf_write(&to, task_pt_regs(target), sizeof(struct pt_regs));
|
||||
}
|
||||
|
||||
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,
|
||||
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,
|
||||
&task_thread_info(target)->fpstate,
|
||||
0, sizeof(struct user_fp));
|
||||
return membuf_write(&to, &task_thread_info(target)->fpstate,
|
||||
sizeof(struct user_fp));
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
* 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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
int ret;
|
||||
struct thread_info *thread = task_thread_info(target);
|
||||
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);
|
||||
|
||||
vfp_sync_hwstate(thread);
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&vfp->fpregs,
|
||||
user_fpregs_offset,
|
||||
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));
|
||||
membuf_write(&to, vfp->fpregs, sizeof(vfp->fpregs));
|
||||
membuf_zero(&to, user_fpscr_offset - sizeof(vfp->fpregs));
|
||||
return membuf_store(&to, vfp->fpscr);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -739,7 +711,7 @@ static const struct user_regset arm_regsets[] = {
|
||||
.n = ELF_NGREG,
|
||||
.size = sizeof(u32),
|
||||
.align = sizeof(u32),
|
||||
.get = gpr_get,
|
||||
.regset_get = gpr_get,
|
||||
.set = gpr_set
|
||||
},
|
||||
[REGSET_FPR] = {
|
||||
@ -751,7 +723,7 @@ static const struct user_regset arm_regsets[] = {
|
||||
.n = sizeof(struct user_fp) / sizeof(u32),
|
||||
.size = sizeof(u32),
|
||||
.align = sizeof(u32),
|
||||
.get = fpa_get,
|
||||
.regset_get = fpa_get,
|
||||
.set = fpa_set
|
||||
},
|
||||
#ifdef CONFIG_VFP
|
||||
@ -764,7 +736,7 @@ static const struct user_regset arm_regsets[] = {
|
||||
.n = ARM_VFPREGS_SIZE / sizeof(u32),
|
||||
.size = sizeof(u32),
|
||||
.align = sizeof(u32),
|
||||
.get = vfp_get,
|
||||
.regset_get = vfp_get,
|
||||
.set = vfp_set
|
||||
},
|
||||
#endif /* CONFIG_VFP */
|
||||
|
@ -474,11 +474,10 @@ static int ptrace_hbp_set_addr(unsigned int note_type,
|
||||
|
||||
static int hw_break_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
unsigned int note_type = regset->core_note_type;
|
||||
int ret, idx = 0, offset, limit;
|
||||
int ret, idx = 0;
|
||||
u32 info, ctrl;
|
||||
u64 addr;
|
||||
|
||||
@ -487,49 +486,21 @@ static int hw_break_get(struct task_struct *target,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &info, 0,
|
||||
sizeof(info));
|
||||
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;
|
||||
|
||||
membuf_write(&to, &info, sizeof(info));
|
||||
membuf_zero(&to, sizeof(u32));
|
||||
/* (address, ctrl) registers */
|
||||
offset = offsetof(struct user_hwdebug_state, dbg_regs);
|
||||
limit = regset->n * regset->size;
|
||||
while (count && offset < limit) {
|
||||
while (to.left) {
|
||||
ret = ptrace_hbp_get_addr(note_type, target, idx, &addr);
|
||||
if (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);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &ctrl,
|
||||
offset, offset + PTRACE_HBP_CTRL_SZ);
|
||||
if (ret)
|
||||
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;
|
||||
membuf_store(&to, addr);
|
||||
membuf_store(&to, ctrl);
|
||||
membuf_zero(&to, sizeof(u32));
|
||||
idx++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -589,11 +560,10 @@ static int hw_break_set(struct task_struct *target,
|
||||
|
||||
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)
|
||||
{
|
||||
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,
|
||||
@ -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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf, unsigned int start_pos)
|
||||
struct membuf to)
|
||||
{
|
||||
struct user_fpsimd_state *uregs;
|
||||
|
||||
@ -635,13 +604,11 @@ static int __fpr_get(struct task_struct *target,
|
||||
|
||||
uregs = &target->thread.uw.fpsimd_state;
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs,
|
||||
start_pos, start_pos + sizeof(*uregs));
|
||||
return membuf_write(&to, uregs, sizeof(*uregs));
|
||||
}
|
||||
|
||||
static 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)
|
||||
{
|
||||
if (!system_supports_fpsimd())
|
||||
return -EINVAL;
|
||||
@ -649,7 +616,7 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
|
||||
if (target == current)
|
||||
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,
|
||||
@ -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,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
unsigned long *tls = &target->thread.uw.tp_value;
|
||||
|
||||
if (target == current)
|
||||
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,
|
||||
@ -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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
int syscallno = task_pt_regs(target)->syscallno;
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&syscallno, 0, -1);
|
||||
return membuf_store(&to, task_pt_regs(target)->syscallno);
|
||||
}
|
||||
|
||||
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)
|
||||
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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
int ret;
|
||||
struct user_sve_header header;
|
||||
unsigned int vq;
|
||||
unsigned long start, end;
|
||||
@ -809,10 +755,7 @@ static int sve_get(struct task_struct *target,
|
||||
sve_init_header_from_task(&header, target);
|
||||
vq = sve_vq_from_vl(header.vl);
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &header,
|
||||
0, sizeof(header));
|
||||
if (ret)
|
||||
return ret;
|
||||
membuf_write(&to, &header, sizeof(header));
|
||||
|
||||
if (target == current)
|
||||
fpsimd_preserve_current_state();
|
||||
@ -821,26 +764,18 @@ static int sve_get(struct task_struct *target,
|
||||
|
||||
BUILD_BUG_ON(SVE_PT_FPSIMD_OFFSET != sizeof(header));
|
||||
if ((header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD)
|
||||
return __fpr_get(target, regset, pos, count, kbuf, ubuf,
|
||||
SVE_PT_FPSIMD_OFFSET);
|
||||
return __fpr_get(target, regset, to);
|
||||
|
||||
/* Otherwise: full SVE case */
|
||||
|
||||
BUILD_BUG_ON(SVE_PT_SVE_OFFSET != sizeof(header));
|
||||
start = SVE_PT_SVE_OFFSET;
|
||||
end = SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq);
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
target->thread.sve_state,
|
||||
start, end);
|
||||
if (ret)
|
||||
return ret;
|
||||
membuf_write(&to, target->thread.sve_state, end - start);
|
||||
|
||||
start = end;
|
||||
end = SVE_PT_SVE_FPSR_OFFSET(vq);
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
start, end);
|
||||
if (ret)
|
||||
return ret;
|
||||
membuf_zero(&to, end - start);
|
||||
|
||||
/*
|
||||
* Copy fpsr, and fpcr which must follow contiguously in
|
||||
@ -848,16 +783,11 @@ static int sve_get(struct task_struct *target,
|
||||
*/
|
||||
start = end;
|
||||
end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE;
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.uw.fpsimd_state.fpsr,
|
||||
start, end);
|
||||
if (ret)
|
||||
return ret;
|
||||
membuf_write(&to, &target->thread.uw.fpsimd_state.fpsr, end - start);
|
||||
|
||||
start = end;
|
||||
end = sve_size_from_header(&header);
|
||||
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
start, end);
|
||||
return membuf_zero(&to, end - start);
|
||||
}
|
||||
|
||||
static int sve_set(struct task_struct *target,
|
||||
@ -961,8 +891,7 @@ out:
|
||||
#ifdef CONFIG_ARM64_PTR_AUTH
|
||||
static int pac_mask_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
/*
|
||||
* The PAC bits can differ across data and instruction pointers
|
||||
@ -978,7 +907,7 @@ static int pac_mask_get(struct task_struct *target,
|
||||
if (!system_supports_address_auth())
|
||||
return -EINVAL;
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &uregs, 0, -1);
|
||||
return membuf_write(&to, &uregs, sizeof(uregs));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CHECKPOINT_RESTORE
|
||||
@ -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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
struct ptrauth_keys_user *keys = &target->thread.keys_user;
|
||||
struct user_pac_address_keys user_keys;
|
||||
@ -1028,8 +956,7 @@ static int pac_address_keys_get(struct task_struct *target,
|
||||
|
||||
pac_address_keys_to_user(&user_keys, keys);
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&user_keys, 0, -1);
|
||||
return membuf_write(&to, &user_keys, sizeof(user_keys));
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
static int pac_generic_keys_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
struct ptrauth_keys_user *keys = &target->thread.keys_user;
|
||||
struct user_pac_generic_keys user_keys;
|
||||
@ -1079,8 +1005,7 @@ static int pac_generic_keys_get(struct task_struct *target,
|
||||
|
||||
pac_generic_keys_to_user(&user_keys, keys);
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&user_keys, 0, -1);
|
||||
return membuf_write(&to, &user_keys, sizeof(user_keys));
|
||||
}
|
||||
|
||||
static int pac_generic_keys_set(struct task_struct *target,
|
||||
@ -1134,7 +1059,7 @@ static const struct user_regset aarch64_regsets[] = {
|
||||
.n = sizeof(struct user_pt_regs) / sizeof(u64),
|
||||
.size = sizeof(u64),
|
||||
.align = sizeof(u64),
|
||||
.get = gpr_get,
|
||||
.regset_get = gpr_get,
|
||||
.set = gpr_set
|
||||
},
|
||||
[REGSET_FPR] = {
|
||||
@ -1147,7 +1072,7 @@ static const struct user_regset aarch64_regsets[] = {
|
||||
.size = sizeof(u32),
|
||||
.align = sizeof(u32),
|
||||
.active = fpr_active,
|
||||
.get = fpr_get,
|
||||
.regset_get = fpr_get,
|
||||
.set = fpr_set
|
||||
},
|
||||
[REGSET_TLS] = {
|
||||
@ -1155,7 +1080,7 @@ static const struct user_regset aarch64_regsets[] = {
|
||||
.n = 1,
|
||||
.size = sizeof(void *),
|
||||
.align = sizeof(void *),
|
||||
.get = tls_get,
|
||||
.regset_get = tls_get,
|
||||
.set = tls_set,
|
||||
},
|
||||
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||
@ -1164,7 +1089,7 @@ static const struct user_regset aarch64_regsets[] = {
|
||||
.n = sizeof(struct user_hwdebug_state) / sizeof(u32),
|
||||
.size = sizeof(u32),
|
||||
.align = sizeof(u32),
|
||||
.get = hw_break_get,
|
||||
.regset_get = hw_break_get,
|
||||
.set = hw_break_set,
|
||||
},
|
||||
[REGSET_HW_WATCH] = {
|
||||
@ -1172,7 +1097,7 @@ static const struct user_regset aarch64_regsets[] = {
|
||||
.n = sizeof(struct user_hwdebug_state) / sizeof(u32),
|
||||
.size = sizeof(u32),
|
||||
.align = sizeof(u32),
|
||||
.get = hw_break_get,
|
||||
.regset_get = hw_break_get,
|
||||
.set = hw_break_set,
|
||||
},
|
||||
#endif
|
||||
@ -1181,7 +1106,7 @@ static const struct user_regset aarch64_regsets[] = {
|
||||
.n = 1,
|
||||
.size = sizeof(int),
|
||||
.align = sizeof(int),
|
||||
.get = system_call_get,
|
||||
.regset_get = system_call_get,
|
||||
.set = system_call_set,
|
||||
},
|
||||
#ifdef CONFIG_ARM64_SVE
|
||||
@ -1191,9 +1116,8 @@ static const struct user_regset aarch64_regsets[] = {
|
||||
SVE_VQ_BYTES),
|
||||
.size = SVE_VQ_BYTES,
|
||||
.align = SVE_VQ_BYTES,
|
||||
.get = sve_get,
|
||||
.regset_get = sve_get,
|
||||
.set = sve_set,
|
||||
.get_size = sve_get_size,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_ARM64_PTR_AUTH
|
||||
@ -1202,7 +1126,7 @@ static const struct user_regset aarch64_regsets[] = {
|
||||
.n = sizeof(struct user_pac_mask) / sizeof(u64),
|
||||
.size = sizeof(u64),
|
||||
.align = sizeof(u64),
|
||||
.get = pac_mask_get,
|
||||
.regset_get = pac_mask_get,
|
||||
/* this cannot be set dynamically */
|
||||
},
|
||||
#ifdef CONFIG_CHECKPOINT_RESTORE
|
||||
@ -1211,7 +1135,7 @@ static const struct user_regset aarch64_regsets[] = {
|
||||
.n = sizeof(struct user_pac_address_keys) / sizeof(__uint128_t),
|
||||
.size = sizeof(__uint128_t),
|
||||
.align = sizeof(__uint128_t),
|
||||
.get = pac_address_keys_get,
|
||||
.regset_get = pac_address_keys_get,
|
||||
.set = pac_address_keys_set,
|
||||
},
|
||||
[REGSET_PACG_KEYS] = {
|
||||
@ -1219,7 +1143,7 @@ static const struct user_regset aarch64_regsets[] = {
|
||||
.n = sizeof(struct user_pac_generic_keys) / sizeof(__uint128_t),
|
||||
.size = sizeof(__uint128_t),
|
||||
.align = sizeof(__uint128_t),
|
||||
.get = pac_generic_keys_get,
|
||||
.regset_get = pac_generic_keys_get,
|
||||
.set = pac_generic_keys_set,
|
||||
},
|
||||
#endif
|
||||
@ -1237,57 +1161,31 @@ enum compat_regset {
|
||||
REGSET_COMPAT_VFP,
|
||||
};
|
||||
|
||||
static inline compat_ulong_t compat_get_user_reg(struct task_struct *task, int idx)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(task);
|
||||
|
||||
switch (idx) {
|
||||
case 15:
|
||||
return regs->pc;
|
||||
case 16:
|
||||
return pstate_to_compat_psr(regs->pstate);
|
||||
case 17:
|
||||
return regs->orig_x0;
|
||||
default:
|
||||
return regs->regs[idx];
|
||||
}
|
||||
}
|
||||
|
||||
static int compat_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 ret = 0;
|
||||
unsigned int i, start, num_regs;
|
||||
int i = 0;
|
||||
|
||||
/* Calculate the number of AArch32 registers contained in count */
|
||||
num_regs = count / regset->size;
|
||||
|
||||
/* Convert pos into an register number */
|
||||
start = pos / regset->size;
|
||||
|
||||
if (start + num_regs > regset->n)
|
||||
return -EIO;
|
||||
|
||||
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, ®, sizeof(reg));
|
||||
kbuf += sizeof(reg);
|
||||
} else {
|
||||
ret = copy_to_user(ubuf, ®, sizeof(reg));
|
||||
if (ret) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
ubuf += sizeof(reg);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
while (to.left)
|
||||
membuf_store(&to, compat_get_user_reg(target, i++));
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
struct user_fpsimd_state *uregs;
|
||||
compat_ulong_t fpscr;
|
||||
int ret, vregs_end_pos;
|
||||
|
||||
if (!system_supports_fpsimd())
|
||||
return -EINVAL;
|
||||
@ -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
|
||||
* nicely together for us. We just need to create the fpscr separately.
|
||||
*/
|
||||
vregs_end_pos = VFP_STATE_SIZE - sizeof(compat_ulong_t);
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs,
|
||||
0, vregs_end_pos);
|
||||
|
||||
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;
|
||||
membuf_write(&to, uregs, VFP_STATE_SIZE - sizeof(compat_ulong_t));
|
||||
fpscr = (uregs->fpsr & VFP_FPSCR_STAT_MASK) |
|
||||
(uregs->fpcr & VFP_FPSCR_CTRL_MASK);
|
||||
return membuf_store(&to, fpscr);
|
||||
}
|
||||
|
||||
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,
|
||||
const struct user_regset *regset, unsigned int pos,
|
||||
unsigned int count, void *kbuf, void __user *ubuf)
|
||||
const struct user_regset *regset,
|
||||
struct membuf to)
|
||||
{
|
||||
compat_ulong_t tls = (compat_ulong_t)target->thread.uw.tp_value;
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
|
||||
return membuf_store(&to, (compat_ulong_t)target->thread.uw.tp_value);
|
||||
}
|
||||
|
||||
static int compat_tls_set(struct task_struct *target,
|
||||
@ -1449,7 +1335,7 @@ static const struct user_regset aarch32_regsets[] = {
|
||||
.n = COMPAT_ELF_NGREG,
|
||||
.size = sizeof(compat_elf_greg_t),
|
||||
.align = sizeof(compat_elf_greg_t),
|
||||
.get = compat_gpr_get,
|
||||
.regset_get = compat_gpr_get,
|
||||
.set = compat_gpr_set
|
||||
},
|
||||
[REGSET_COMPAT_VFP] = {
|
||||
@ -1458,7 +1344,7 @@ static const struct user_regset aarch32_regsets[] = {
|
||||
.size = sizeof(compat_ulong_t),
|
||||
.align = sizeof(compat_ulong_t),
|
||||
.active = fpr_active,
|
||||
.get = compat_vfp_get,
|
||||
.regset_get = compat_vfp_get,
|
||||
.set = compat_vfp_set
|
||||
},
|
||||
};
|
||||
@ -1474,7 +1360,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
|
||||
.n = COMPAT_ELF_NGREG,
|
||||
.size = sizeof(compat_elf_greg_t),
|
||||
.align = sizeof(compat_elf_greg_t),
|
||||
.get = compat_gpr_get,
|
||||
.regset_get = compat_gpr_get,
|
||||
.set = compat_gpr_set
|
||||
},
|
||||
[REGSET_FPR] = {
|
||||
@ -1482,7 +1368,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
|
||||
.n = VFP_STATE_SIZE / sizeof(compat_ulong_t),
|
||||
.size = sizeof(compat_ulong_t),
|
||||
.align = sizeof(compat_ulong_t),
|
||||
.get = compat_vfp_get,
|
||||
.regset_get = compat_vfp_get,
|
||||
.set = compat_vfp_set
|
||||
},
|
||||
[REGSET_TLS] = {
|
||||
@ -1490,7 +1376,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
|
||||
.n = 1,
|
||||
.size = sizeof(compat_ulong_t),
|
||||
.align = sizeof(compat_ulong_t),
|
||||
.get = compat_tls_get,
|
||||
.regset_get = compat_tls_get,
|
||||
.set = compat_tls_set,
|
||||
},
|
||||
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||
@ -1499,7 +1385,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
|
||||
.n = sizeof(struct user_hwdebug_state) / sizeof(u32),
|
||||
.size = sizeof(u32),
|
||||
.align = sizeof(u32),
|
||||
.get = hw_break_get,
|
||||
.regset_get = hw_break_get,
|
||||
.set = hw_break_set,
|
||||
},
|
||||
[REGSET_HW_WATCH] = {
|
||||
@ -1507,7 +1393,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
|
||||
.n = sizeof(struct user_hwdebug_state) / sizeof(u32),
|
||||
.size = sizeof(u32),
|
||||
.align = sizeof(u32),
|
||||
.get = hw_break_get,
|
||||
.regset_get = hw_break_get,
|
||||
.set = hw_break_set,
|
||||
},
|
||||
#endif
|
||||
@ -1516,7 +1402,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
|
||||
.n = 1,
|
||||
.size = sizeof(int),
|
||||
.align = sizeof(int),
|
||||
.get = system_call_get,
|
||||
.regset_get = system_call_get,
|
||||
.set = system_call_set,
|
||||
},
|
||||
};
|
||||
@ -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)
|
||||
tmp = tsk->mm->end_code;
|
||||
else if (off < sizeof(compat_elf_gregset_t))
|
||||
return copy_regset_to_user(tsk, &user_aarch32_view,
|
||||
REGSET_COMPAT_GPR, off,
|
||||
sizeof(compat_ulong_t), ret);
|
||||
tmp = compat_get_user_reg(tsk, off >> 2);
|
||||
else if (off >= COMPAT_USER_SZ)
|
||||
return -EIO;
|
||||
else
|
||||
@ -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,
|
||||
compat_ulong_t val)
|
||||
{
|
||||
int ret;
|
||||
mm_segment_t old_fs = get_fs();
|
||||
struct pt_regs newregs = *task_pt_regs(tsk);
|
||||
unsigned int idx = off / 4;
|
||||
|
||||
if (off & 3 || off >= COMPAT_USER_SZ)
|
||||
return -EIO;
|
||||
@ -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))
|
||||
return 0;
|
||||
|
||||
set_fs(KERNEL_DS);
|
||||
ret = copy_regset_from_user(tsk, &user_aarch32_view,
|
||||
REGSET_COMPAT_GPR, off,
|
||||
sizeof(compat_ulong_t),
|
||||
&val);
|
||||
set_fs(old_fs);
|
||||
switch (idx) {
|
||||
case 15:
|
||||
newregs.pc = val;
|
||||
break;
|
||||
case 16:
|
||||
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
|
||||
|
@ -57,14 +57,9 @@ static inline int put_reg(struct task_struct *task,
|
||||
|
||||
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)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
regs,
|
||||
0, sizeof(*regs));
|
||||
return membuf_write(&to, task_pt_regs(target), sizeof(struct pt_regs));
|
||||
}
|
||||
|
||||
enum c6x_regset {
|
||||
@ -77,7 +72,7 @@ static const struct user_regset c6x_regsets[] = {
|
||||
.n = ELF_NGREG,
|
||||
.size = sizeof(u32),
|
||||
.align = sizeof(u32),
|
||||
.get = gpr_get,
|
||||
.regset_get = gpr_get,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -76,17 +76,14 @@ enum csky_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)
|
||||
{
|
||||
struct pt_regs *regs;
|
||||
|
||||
regs = task_pt_regs(target);
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
|
||||
/* Abiv1 regs->tls is fake and we need sync here. */
|
||||
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,
|
||||
@ -114,8 +111,7 @@ static int gpr_set(struct task_struct *target,
|
||||
|
||||
static 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)
|
||||
{
|
||||
struct user_fp *regs = (struct user_fp *)&target->thread.user_fp;
|
||||
|
||||
@ -131,9 +127,9 @@ static int fpr_get(struct task_struct *target,
|
||||
for (i = 0; i < 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
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
|
||||
return membuf_write(&to, regs, sizeof(*regs));
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -173,16 +169,16 @@ static const struct user_regset csky_regsets[] = {
|
||||
.n = sizeof(struct pt_regs) / sizeof(u32),
|
||||
.size = sizeof(u32),
|
||||
.align = sizeof(u32),
|
||||
.get = &gpr_get,
|
||||
.set = &gpr_set,
|
||||
.regset_get = gpr_get,
|
||||
.set = gpr_set,
|
||||
},
|
||||
[REGSET_FPR] = {
|
||||
.core_note_type = NT_PRFPREG,
|
||||
.n = sizeof(struct user_fp) / sizeof(u32),
|
||||
.size = sizeof(u32),
|
||||
.align = sizeof(u32),
|
||||
.get = &fpr_get,
|
||||
.set = &fpr_set,
|
||||
.regset_get = fpr_get,
|
||||
.set = fpr_set,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
int r;
|
||||
struct user_regs_struct regs;
|
||||
long *reg = (long *)®s;
|
||||
|
||||
/* build user regs in buffer */
|
||||
BUILD_BUG_ON(sizeof(regs) % sizeof(long) != 0);
|
||||
for (r = 0; r < sizeof(regs) / sizeof(long); r++)
|
||||
*reg++ = h8300_get_reg(target, r);
|
||||
BUILD_BUG_ON(sizeof(struct user_regs_struct) % sizeof(long) != 0);
|
||||
for (r = 0; r < ELF_NGREG; r++)
|
||||
membuf_store(&to, h8300_get_reg(target, r));
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
®s, 0, sizeof(regs));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int regs_set(struct task_struct *target,
|
||||
@ -139,7 +134,7 @@ static const struct user_regset h8300_regsets[] = {
|
||||
.n = ELF_NGREG,
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.get = regs_get,
|
||||
.regset_get = regs_get,
|
||||
.set = regs_set,
|
||||
},
|
||||
};
|
||||
|
@ -35,58 +35,38 @@ void user_disable_single_step(struct task_struct *child)
|
||||
|
||||
static int genregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
srtuct membuf to)
|
||||
{
|
||||
int ret;
|
||||
unsigned int dummy;
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
|
||||
|
||||
if (!regs)
|
||||
return -EIO;
|
||||
|
||||
/* The general idea here is that the copyout must happen in
|
||||
* exactly the same order in which the userspace expects these
|
||||
* regs. Now, the sequence in userspace does not match the
|
||||
* sequence in the kernel, so everything past the 32 gprs
|
||||
* happens one at a time.
|
||||
*/
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
®s->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));
|
||||
|
||||
membuf_write(&to, ®s->r00, 32*sizeof(unsigned long));
|
||||
/* Must be exactly same sequence as struct user_regs_struct */
|
||||
ONEXT(®s->sa0, sa0);
|
||||
ONEXT(®s->lc0, lc0);
|
||||
ONEXT(®s->sa1, sa1);
|
||||
ONEXT(®s->lc1, lc1);
|
||||
ONEXT(®s->m0, m0);
|
||||
ONEXT(®s->m1, m1);
|
||||
ONEXT(®s->usr, usr);
|
||||
ONEXT(®s->preds, p3_0);
|
||||
ONEXT(®s->gp, gp);
|
||||
ONEXT(®s->ugp, ugp);
|
||||
ONEXT(&pt_elr(regs), pc);
|
||||
dummy = pt_cause(regs);
|
||||
ONEXT(&dummy, cause);
|
||||
ONEXT(&pt_badva(regs), badva);
|
||||
membuf_store(&to, regs->sa0);
|
||||
membuf_store(&to, regs->lc0);
|
||||
membuf_store(&to, regs->sa1);
|
||||
membuf_store(&to, regs->lc1);
|
||||
membuf_store(&to, regs->m0);
|
||||
membuf_store(&to, regs->m1);
|
||||
membuf_store(&to, regs->usr);
|
||||
membuf_store(&to, regs->p3_0);
|
||||
membuf_store(&to, regs->gp);
|
||||
membuf_store(&to, regs->ugp);
|
||||
membuf_store(&to, pt_elr(regs)); // pc
|
||||
membuf_store(&to, (unsigned long)pt_cause(regs)); // cause
|
||||
membuf_store(&to, pt_badva(regs)); // badva
|
||||
#if CONFIG_HEXAGON_ARCH_VERSION >=4
|
||||
ONEXT(®s->cs0, cs0);
|
||||
ONEXT(®s->cs1, cs1);
|
||||
membuf_store(&to, regs->cs0);
|
||||
membuf_store(&to, regs->cs1);
|
||||
return membuf_zero(&to, sizeof(unsigned long));
|
||||
#else
|
||||
return membuf_zero(&to, 3 * sizeof(unsigned long));
|
||||
#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,
|
||||
@ -159,7 +139,7 @@ static const struct user_regset hexagon_regsets[] = {
|
||||
.n = ELF_NGREG,
|
||||
.size = sizeof(unsigned long),
|
||||
.align = sizeof(unsigned long),
|
||||
.get = genregs_get,
|
||||
.regset_get = genregs_get,
|
||||
.set = genregs_set,
|
||||
},
|
||||
};
|
||||
|
@ -1273,52 +1273,43 @@ struct regset_getset {
|
||||
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
|
||||
access_elf_gpreg(struct task_struct *target, struct unw_frame_info *info,
|
||||
unsigned long addr, unsigned long *data, int write_access)
|
||||
{
|
||||
struct pt_regs *pt;
|
||||
unsigned long *ptr = NULL;
|
||||
int ret;
|
||||
char nat = 0;
|
||||
struct pt_regs *pt = task_pt_regs(target);
|
||||
unsigned reg = addr / sizeof(unsigned long);
|
||||
ptrdiff_t d = pt_offsets[reg];
|
||||
|
||||
pt = task_pt_regs(target);
|
||||
switch (addr) {
|
||||
case ELF_GR_OFFSET(1):
|
||||
ptr = &pt->r1;
|
||||
break;
|
||||
case ELF_GR_OFFSET(2):
|
||||
case ELF_GR_OFFSET(3):
|
||||
ptr = (void *)&pt->r2 + (addr - ELF_GR_OFFSET(2));
|
||||
break;
|
||||
case ELF_GR_OFFSET(4) ... ELF_GR_OFFSET(7):
|
||||
if (d >= 0) {
|
||||
unsigned long *ptr = (void *)pt + d;
|
||||
if (write_access)
|
||||
*ptr = *data;
|
||||
else
|
||||
*data = *ptr;
|
||||
return 0;
|
||||
} else {
|
||||
char nat = 0;
|
||||
if (write_access) {
|
||||
/* read NaT bit first: */
|
||||
unsigned long dummy;
|
||||
|
||||
ret = unw_get_gr(info, addr/8, &dummy, &nat);
|
||||
int ret = unw_get_gr(info, reg, &dummy, &nat);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return unw_access_gr(info, addr/8, 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;
|
||||
return unw_access_gr(info, reg, data, &nat, write_access);
|
||||
}
|
||||
if (write_access)
|
||||
*ptr = *data;
|
||||
else
|
||||
*data = *ptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1490,7 +1481,7 @@ static int
|
||||
access_elf_reg(struct task_struct *target, struct unw_frame_info *info,
|
||||
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);
|
||||
else if (addr >= ELF_BR_OFFSET(0) && addr <= ELF_BR_OFFSET(7))
|
||||
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,
|
||||
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)
|
||||
{
|
||||
struct pt_regs *pt;
|
||||
struct regset_getset *dst = arg;
|
||||
elf_greg_t tmp[16];
|
||||
unsigned int i, index, min_copy;
|
||||
struct regset_membuf *dst = arg;
|
||||
struct membuf to = dst->to;
|
||||
unsigned int n;
|
||||
elf_greg_t reg;
|
||||
|
||||
if (unw_unwind_to_user(info) < 0)
|
||||
return;
|
||||
@ -1521,165 +1517,53 @@ void do_gpregs_get(struct unw_frame_info *info, void *arg)
|
||||
|
||||
|
||||
/* Skip r0 */
|
||||
if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) {
|
||||
dst->ret = user_regset_copyout_zero(&dst->pos, &dst->count,
|
||||
&dst->u.get.kbuf,
|
||||
&dst->u.get.ubuf,
|
||||
0, ELF_GR_OFFSET(1));
|
||||
if (dst->ret || dst->count == 0)
|
||||
membuf_zero(&to, 8);
|
||||
for (n = 8; to.left && n < ELF_AR_END_OFFSET; n += 8) {
|
||||
if (access_elf_reg(info->task, info, n, ®, 0) < 0) {
|
||||
dst->ret = -EIO;
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
membuf_store(&to, reg);
|
||||
}
|
||||
}
|
||||
|
||||
void do_gpregs_set(struct unw_frame_info *info, void *arg)
|
||||
{
|
||||
struct pt_regs *pt;
|
||||
struct regset_getset *dst = arg;
|
||||
elf_greg_t tmp[16];
|
||||
unsigned int i, index;
|
||||
|
||||
if (unw_unwind_to_user(info) < 0)
|
||||
return;
|
||||
|
||||
if (!dst->count)
|
||||
return;
|
||||
/* 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->u.set.kbuf,
|
||||
&dst->u.set.ubuf,
|
||||
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)
|
||||
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;
|
||||
}
|
||||
while (dst->count && dst->pos < ELF_AR_END_OFFSET) {
|
||||
unsigned int n, from, to;
|
||||
elf_greg_t tmp[16];
|
||||
|
||||
/* nat, pr, b0 - b7 */
|
||||
if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) {
|
||||
i = dst->pos;
|
||||
index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t);
|
||||
from = dst->pos;
|
||||
to = from + sizeof(tmp);
|
||||
if (to > ELF_AR_END_OFFSET)
|
||||
to = ELF_AR_END_OFFSET;
|
||||
/* get up to 16 values */
|
||||
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);
|
||||
from, to);
|
||||
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
|
||||
* 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)) {
|
||||
i = dst->pos;
|
||||
index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t);
|
||||
dst->ret = user_regset_copyin(&dst->pos, &dst->count,
|
||||
&dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
|
||||
ELF_CR_IIP_OFFSET, ELF_AR_END_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) {
|
||||
/* now copy them into registers */
|
||||
for (n = 0; from < dst->pos; from += sizeof(elf_greg_t), n++)
|
||||
if (access_elf_reg(dst->target, info, from,
|
||||
&tmp[n], 1) < 0) {
|
||||
dst->ret = -EIO;
|
||||
return;
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
struct regset_getset *dst = arg;
|
||||
struct task_struct *task = dst->target;
|
||||
elf_fpreg_t tmp[30];
|
||||
int index, min_copy, i;
|
||||
struct task_struct *task = info->task;
|
||||
struct regset_membuf *dst = arg;
|
||||
struct membuf to = dst->to;
|
||||
elf_fpreg_t reg;
|
||||
unsigned int n;
|
||||
|
||||
if (unw_unwind_to_user(info) < 0)
|
||||
return;
|
||||
|
||||
/* Skip pos 0 and 1 */
|
||||
if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(2)) {
|
||||
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;
|
||||
}
|
||||
membuf_zero(&to, 2 * sizeof(elf_fpreg_t));
|
||||
|
||||
/* fr2-fr31 */
|
||||
if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(32)) {
|
||||
index = (dst->pos - ELF_FP_OFFSET(2)) / sizeof(elf_fpreg_t);
|
||||
|
||||
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)
|
||||
for (n = 2; to.left && n < 32; n++) {
|
||||
if (unw_get_fr(info, n, ®)) {
|
||||
dst->ret = -EIO;
|
||||
return;
|
||||
}
|
||||
membuf_write(&to, ®, sizeof(reg));
|
||||
}
|
||||
|
||||
/* fph */
|
||||
if (dst->count > 0) {
|
||||
ia64_flush_fph(dst->target);
|
||||
if (task->thread.flags & IA64_THREAD_FPH_VALID)
|
||||
dst->ret = user_regset_copyout(
|
||||
&dst->pos, &dst->count,
|
||||
&dst->u.get.kbuf, &dst->u.get.ubuf,
|
||||
&dst->target->thread.fph,
|
||||
ELF_FP_OFFSET(32), -1);
|
||||
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);
|
||||
}
|
||||
if (!to.left)
|
||||
return;
|
||||
|
||||
ia64_flush_fph(task);
|
||||
if (task->thread.flags & IA64_THREAD_FPH_VALID)
|
||||
membuf_write(&to, &task->thread.fph, 96 * sizeof(reg));
|
||||
else
|
||||
membuf_zero(&to, 96 * sizeof(reg));
|
||||
}
|
||||
|
||||
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
|
||||
do_regset_call(void (*call)(struct unw_frame_info *, void *),
|
||||
struct task_struct *target,
|
||||
@ -1830,27 +1704,18 @@ do_regset_call(void (*call)(struct unw_frame_info *, void *),
|
||||
.pos = pos, .count = count,
|
||||
.u.set = { .kbuf = kbuf, .ubuf = ubuf },
|
||||
.ret = 0 };
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
unwind_and_call(call, target, &info);
|
||||
return info.ret;
|
||||
}
|
||||
|
||||
static int
|
||||
gpregs_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 do_regset_call(do_gpregs_get, target, regset, pos, count,
|
||||
kbuf, ubuf);
|
||||
struct regset_membuf info = {.to = to};
|
||||
unwind_and_call(do_gpregs_get, target, &info);
|
||||
return info.ret;
|
||||
}
|
||||
|
||||
static int gpregs_set(struct task_struct *target,
|
||||
@ -1892,11 +1757,11 @@ fpregs_active(struct task_struct *target, const struct user_regset *regset)
|
||||
|
||||
static int fpregs_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 do_regset_call(do_fpregs_get, target, regset, pos, count,
|
||||
kbuf, ubuf);
|
||||
struct regset_membuf info = {.to = to};
|
||||
unwind_and_call(do_fpregs_get, target, &info);
|
||||
return info.ret;
|
||||
}
|
||||
|
||||
static int fpregs_set(struct task_struct *target,
|
||||
@ -1913,7 +1778,6 @@ access_uarea(struct task_struct *child, unsigned long addr,
|
||||
unsigned long *data, int write_access)
|
||||
{
|
||||
unsigned int pos = -1; /* an invalid value */
|
||||
int ret;
|
||||
unsigned long *ptr, regnum;
|
||||
|
||||
if ((addr & 0x7) != 0) {
|
||||
@ -1945,14 +1809,39 @@ access_uarea(struct task_struct *child, unsigned long addr,
|
||||
}
|
||||
|
||||
if (pos != -1) {
|
||||
if (write_access)
|
||||
ret = fpregs_set(child, NULL, pos,
|
||||
sizeof(unsigned long), data, NULL);
|
||||
else
|
||||
ret = fpregs_get(child, NULL, pos,
|
||||
sizeof(unsigned long), data, NULL);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
unsigned reg = pos / sizeof(elf_fpreg_t);
|
||||
int which_half = (pos / sizeof(unsigned long)) & 1;
|
||||
|
||||
if (reg < 32) { /* fr2-fr31 */
|
||||
struct unw_frame_info info;
|
||||
elf_fpreg_t fpreg;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2038,15 +1927,14 @@ access_uarea(struct task_struct *child, unsigned long addr,
|
||||
}
|
||||
|
||||
if (pos != -1) {
|
||||
if (write_access)
|
||||
ret = gpregs_set(child, NULL, pos,
|
||||
sizeof(unsigned long), data, NULL);
|
||||
else
|
||||
ret = gpregs_get(child, NULL, pos,
|
||||
sizeof(unsigned long), data, NULL);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
return 0;
|
||||
struct unw_frame_info info;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
unw_init_from_blocked_task(&info, child);
|
||||
if (unw_unwind_to_user(&info) < 0)
|
||||
return 0;
|
||||
|
||||
return access_elf_reg(child, &info, pos, data, write_access);
|
||||
}
|
||||
|
||||
/* access debug registers */
|
||||
@ -2112,14 +2000,14 @@ static const struct user_regset native_regsets[] = {
|
||||
.core_note_type = NT_PRSTATUS,
|
||||
.n = ELF_NGREG,
|
||||
.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
|
||||
},
|
||||
{
|
||||
.core_note_type = NT_PRFPREG,
|
||||
.n = ELF_NFPREG,
|
||||
.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,
|
||||
|
||||
static int gpr32_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
u32 uregs[ELF_NGREG] = {};
|
||||
|
||||
mips_dump_regs32(uregs, regs);
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
|
||||
sizeof(uregs));
|
||||
return membuf_write(&to, uregs, sizeof(uregs));
|
||||
}
|
||||
|
||||
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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
u64 uregs[ELF_NGREG] = {};
|
||||
|
||||
mips_dump_regs64(uregs, regs);
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
|
||||
sizeof(uregs));
|
||||
return membuf_write(&to, uregs, sizeof(uregs));
|
||||
}
|
||||
|
||||
static int gpr64_set(struct task_struct *target,
|
||||
@ -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
|
||||
* correspond 1:1 to buffer slots. Only general registers are copied.
|
||||
*/
|
||||
static int fpr_get_fpa(struct task_struct *target,
|
||||
unsigned int *pos, unsigned int *count,
|
||||
void **kbuf, void __user **ubuf)
|
||||
static void fpr_get_fpa(struct task_struct *target,
|
||||
struct membuf *to)
|
||||
{
|
||||
return user_regset_copyout(pos, count, kbuf, ubuf,
|
||||
&target->thread.fpu,
|
||||
0, NUM_FPU_REGS * sizeof(elf_fpreg_t));
|
||||
membuf_write(to, &target->thread.fpu,
|
||||
NUM_FPU_REGS * sizeof(elf_fpreg_t));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -423,25 +417,13 @@ static int fpr_get_fpa(struct task_struct *target,
|
||||
* general register slots are copied to buffer slots. Only general
|
||||
* registers are copied.
|
||||
*/
|
||||
static int fpr_get_msa(struct task_struct *target,
|
||||
unsigned int *pos, unsigned int *count,
|
||||
void **kbuf, void __user **ubuf)
|
||||
static void fpr_get_msa(struct task_struct *target, struct membuf *to)
|
||||
{
|
||||
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,
|
||||
*/
|
||||
static 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)
|
||||
{
|
||||
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))
|
||||
err = fpr_get_fpa(target, &pos, &count, &kbuf, &ubuf);
|
||||
fpr_get_fpa(target, &to);
|
||||
else
|
||||
err = fpr_get_msa(target, &pos, &count, &kbuf, &ubuf);
|
||||
if (err)
|
||||
return err;
|
||||
fpr_get_msa(target, &to);
|
||||
|
||||
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,
|
||||
&boot_cpu_data.fpu_id,
|
||||
fir_pos, fir_pos + sizeof(u32));
|
||||
|
||||
return err;
|
||||
membuf_write(&to, &target->thread.fpu.fcr31, sizeof(u32));
|
||||
membuf_write(&to, &boot_cpu_data.fpu_id, sizeof(u32));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -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. */
|
||||
static int fp_mode_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 fp_mode;
|
||||
|
||||
fp_mode = mips_get_process_fp_mode(target);
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &fp_mode, 0,
|
||||
sizeof(fp_mode));
|
||||
return membuf_store(&to, (int)mips_get_process_fp_mode(target));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -630,13 +592,12 @@ struct msa_control_regs {
|
||||
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,
|
||||
unsigned int *ppos, unsigned int *pcount,
|
||||
void **pkbuf, void __user **pubuf,
|
||||
struct membuf *to,
|
||||
unsigned int live_sz)
|
||||
{
|
||||
int i, j, start, start_pad, err;
|
||||
int i, j;
|
||||
unsigned long long fill = ~0ull;
|
||||
unsigned int cp_sz, pad_sz;
|
||||
|
||||
@ -644,28 +605,16 @@ static int copy_pad_fprs(struct task_struct *target,
|
||||
pad_sz = regset->size - cp_sz;
|
||||
WARN_ON(pad_sz % sizeof(fill));
|
||||
|
||||
i = start = err = 0;
|
||||
for (; i < NUM_FPU_REGS; i++, start += regset->size) {
|
||||
err |= user_regset_copyout(ppos, pcount, pkbuf, pubuf,
|
||||
&target->thread.fpu.fpr[i],
|
||||
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);
|
||||
}
|
||||
for (i = 0; i < NUM_FPU_REGS; i++) {
|
||||
membuf_write(to, &target->thread.fpu.fpr[i], cp_sz);
|
||||
for (j = 0; j < (pad_sz / sizeof(fill)); j++)
|
||||
membuf_store(to, fill);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int msa_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
const unsigned int wr_size = NUM_FPU_REGS * regset->size;
|
||||
const struct msa_control_regs ctrl_regs = {
|
||||
@ -674,32 +623,23 @@ static int msa_get(struct task_struct *target,
|
||||
.msair = boot_cpu_data.msa_id,
|
||||
.msacsr = target->thread.fpu.msacsr,
|
||||
};
|
||||
int err;
|
||||
|
||||
if (!tsk_used_math(target)) {
|
||||
/* The task hasn't used FP or MSA, fill with 0xff */
|
||||
err = copy_pad_fprs(target, regset, &pos, &count,
|
||||
&kbuf, &ubuf, 0);
|
||||
copy_pad_fprs(target, regset, &to, 0);
|
||||
} else if (!test_tsk_thread_flag(target, TIF_MSA_CTX_LIVE)) {
|
||||
/* Copy scalar FP context, fill the rest with 0xff */
|
||||
err = copy_pad_fprs(target, regset, &pos, &count,
|
||||
&kbuf, &ubuf, 8);
|
||||
copy_pad_fprs(target, regset, &to, 8);
|
||||
} else if (sizeof(target->thread.fpu.fpr[0]) == regset->size) {
|
||||
/* Trivially copy the vector registers */
|
||||
err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.fpu.fpr,
|
||||
0, wr_size);
|
||||
membuf_write(&to, &target->thread.fpu.fpr, wr_size);
|
||||
} else {
|
||||
/* Copy as much context as possible, fill the rest with 0xff */
|
||||
err = copy_pad_fprs(target, regset, &pos, &count,
|
||||
&kbuf, &ubuf,
|
||||
sizeof(target->thread.fpu.fpr[0]));
|
||||
copy_pad_fprs(target, regset, &to,
|
||||
sizeof(target->thread.fpu.fpr[0]));
|
||||
}
|
||||
|
||||
err |= user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&ctrl_regs, wr_size,
|
||||
wr_size + sizeof(ctrl_regs));
|
||||
return err;
|
||||
return membuf_write(&to, &ctrl_regs, sizeof(ctrl_regs));
|
||||
}
|
||||
|
||||
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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
unsigned int start, num_regs, i;
|
||||
u32 dspregs[NUM_DSP_REGS + 1];
|
||||
unsigned int i;
|
||||
|
||||
BUG_ON(count % sizeof(u32));
|
||||
BUG_ON(to.left % sizeof(u32));
|
||||
|
||||
if (!cpu_has_dsp)
|
||||
return -EIO;
|
||||
|
||||
start = pos / sizeof(u32);
|
||||
num_regs = count / sizeof(u32);
|
||||
|
||||
if (start + num_regs > NUM_DSP_REGS + 1)
|
||||
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));
|
||||
for (i = 0; i < NUM_DSP_REGS; i++)
|
||||
dspregs[i] = target->thread.dsp.dspr[i];
|
||||
dspregs[NUM_DSP_REGS] = target->thread.dsp.dspcontrol;
|
||||
return membuf_write(&to, dspregs, sizeof(dspregs));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -832,34 +758,20 @@ static int dsp32_set(struct task_struct *target,
|
||||
*/
|
||||
static int dsp64_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
unsigned int start, num_regs, i;
|
||||
u64 dspregs[NUM_DSP_REGS + 1];
|
||||
unsigned int i;
|
||||
|
||||
BUG_ON(count % sizeof(u64));
|
||||
BUG_ON(to.left % sizeof(u64));
|
||||
|
||||
if (!cpu_has_dsp)
|
||||
return -EIO;
|
||||
|
||||
start = pos / sizeof(u64);
|
||||
num_regs = count / sizeof(u64);
|
||||
|
||||
if (start + num_regs > NUM_DSP_REGS + 1)
|
||||
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));
|
||||
for (i = 0; i < NUM_DSP_REGS; i++)
|
||||
dspregs[i] = target->thread.dsp.dspr[i];
|
||||
dspregs[NUM_DSP_REGS] = target->thread.dsp.dspcontrol;
|
||||
return membuf_write(&to, dspregs, sizeof(dspregs));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1018,7 +930,7 @@ static const struct user_regset mips_regsets[] = {
|
||||
.n = ELF_NGREG,
|
||||
.size = sizeof(unsigned int),
|
||||
.align = sizeof(unsigned int),
|
||||
.get = gpr32_get,
|
||||
.regset_get = gpr32_get,
|
||||
.set = gpr32_set,
|
||||
},
|
||||
[REGSET_DSP] = {
|
||||
@ -1026,7 +938,7 @@ static const struct user_regset mips_regsets[] = {
|
||||
.n = NUM_DSP_REGS + 1,
|
||||
.size = sizeof(u32),
|
||||
.align = sizeof(u32),
|
||||
.get = dsp32_get,
|
||||
.regset_get = dsp32_get,
|
||||
.set = dsp32_set,
|
||||
.active = dsp_active,
|
||||
},
|
||||
@ -1036,7 +948,7 @@ static const struct user_regset mips_regsets[] = {
|
||||
.n = ELF_NFPREG,
|
||||
.size = sizeof(elf_fpreg_t),
|
||||
.align = sizeof(elf_fpreg_t),
|
||||
.get = fpr_get,
|
||||
.regset_get = fpr_get,
|
||||
.set = fpr_set,
|
||||
},
|
||||
[REGSET_FP_MODE] = {
|
||||
@ -1044,7 +956,7 @@ static const struct user_regset mips_regsets[] = {
|
||||
.n = 1,
|
||||
.size = sizeof(int),
|
||||
.align = sizeof(int),
|
||||
.get = fp_mode_get,
|
||||
.regset_get = fp_mode_get,
|
||||
.set = fp_mode_set,
|
||||
},
|
||||
#endif
|
||||
@ -1054,7 +966,7 @@ static const struct user_regset mips_regsets[] = {
|
||||
.n = NUM_FPU_REGS + 1,
|
||||
.size = 16,
|
||||
.align = 16,
|
||||
.get = msa_get,
|
||||
.regset_get = msa_get,
|
||||
.set = msa_set,
|
||||
},
|
||||
#endif
|
||||
@ -1078,7 +990,7 @@ static const struct user_regset mips64_regsets[] = {
|
||||
.n = ELF_NGREG,
|
||||
.size = sizeof(unsigned long),
|
||||
.align = sizeof(unsigned long),
|
||||
.get = gpr64_get,
|
||||
.regset_get = gpr64_get,
|
||||
.set = gpr64_set,
|
||||
},
|
||||
[REGSET_DSP] = {
|
||||
@ -1086,7 +998,7 @@ static const struct user_regset mips64_regsets[] = {
|
||||
.n = NUM_DSP_REGS + 1,
|
||||
.size = sizeof(u64),
|
||||
.align = sizeof(u64),
|
||||
.get = dsp64_get,
|
||||
.regset_get = dsp64_get,
|
||||
.set = dsp64_set,
|
||||
.active = dsp_active,
|
||||
},
|
||||
@ -1096,7 +1008,7 @@ static const struct user_regset mips64_regsets[] = {
|
||||
.n = 1,
|
||||
.size = sizeof(int),
|
||||
.align = sizeof(int),
|
||||
.get = fp_mode_get,
|
||||
.regset_get = fp_mode_get,
|
||||
.set = fp_mode_set,
|
||||
},
|
||||
[REGSET_FPR] = {
|
||||
@ -1104,7 +1016,7 @@ static const struct user_regset mips64_regsets[] = {
|
||||
.n = ELF_NFPREG,
|
||||
.size = sizeof(elf_fpreg_t),
|
||||
.align = sizeof(elf_fpreg_t),
|
||||
.get = fpr_get,
|
||||
.regset_get = fpr_get,
|
||||
.set = fpr_set,
|
||||
},
|
||||
#endif
|
||||
@ -1114,7 +1026,7 @@ static const struct user_regset mips64_regsets[] = {
|
||||
.n = NUM_FPU_REGS + 1,
|
||||
.size = 16,
|
||||
.align = 16,
|
||||
.get = msa_get,
|
||||
.regset_get = msa_get,
|
||||
.set = msa_set,
|
||||
},
|
||||
#endif
|
||||
|
@ -13,11 +13,10 @@ enum nds32_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)
|
||||
{
|
||||
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, &task_pt_regs(target)->user_regs,
|
||||
sizeof(struct user_pt_regs));
|
||||
}
|
||||
|
||||
static int gpr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
@ -41,7 +40,7 @@ static const struct user_regset nds32_regsets[] = {
|
||||
.n = sizeof(struct user_pt_regs) / sizeof(u32),
|
||||
.size = sizeof(elf_greg_t),
|
||||
.align = sizeof(elf_greg_t),
|
||||
.get = gpr_get,
|
||||
.regset_get = gpr_get,
|
||||
.set = gpr_set}
|
||||
};
|
||||
|
||||
|
@ -21,45 +21,24 @@
|
||||
|
||||
static int genregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
const struct pt_regs *regs = task_pt_regs(target);
|
||||
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) \
|
||||
if (!ret) \
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
|
||||
START * 4, (END * 4) + 4);
|
||||
|
||||
REG_O_ZERO_RANGE(PTR_R0, PTR_R0);
|
||||
REG_O_RANGE(®s->r1, PTR_R1, PTR_R7);
|
||||
REG_O_RANGE(®s->r8, PTR_R8, PTR_R15);
|
||||
REG_O_RANGE(sw, PTR_R16, PTR_R23);
|
||||
REG_O_ZERO_RANGE(PTR_R24, PTR_R25); /* et and bt */
|
||||
REG_O_ONE(®s->gp, PTR_GP);
|
||||
REG_O_ONE(®s->sp, PTR_SP);
|
||||
REG_O_ONE(®s->fp, PTR_FP);
|
||||
REG_O_ONE(®s->ea, PTR_EA);
|
||||
REG_O_ZERO_RANGE(PTR_BA, PTR_BA);
|
||||
REG_O_ONE(®s->ra, PTR_RA);
|
||||
REG_O_ONE(®s->ea, PTR_PC); /* use ea for PC */
|
||||
if (!ret)
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
PTR_STATUS * 4, -1);
|
||||
|
||||
return ret;
|
||||
membuf_zero(&to, 4); // R0
|
||||
membuf_write(&to, ®s->r1, 7 * 4); // R1..R7
|
||||
membuf_write(&to, ®s->r8, 8 * 4); // R8..R15
|
||||
membuf_write(&to, sw, 8 * 4); // R16..R23
|
||||
membuf_zero(&to, 2 * 4); /* et and bt */
|
||||
membuf_store(&to, regs->gp);
|
||||
membuf_store(&to, regs->sp);
|
||||
membuf_store(&to, regs->fp);
|
||||
membuf_store(&to, regs->ea);
|
||||
membuf_zero(&to, 4); // PTR_BA
|
||||
membuf_store(&to, regs->ra);
|
||||
membuf_store(&to, regs->ea); /* use ea for PC */
|
||||
return membuf_zero(&to, (NUM_PTRACE_REG - PTR_PC) * 4);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -121,7 +100,7 @@ static const struct user_regset nios2_regsets[] = {
|
||||
.n = NUM_PTRACE_REG,
|
||||
.size = sizeof(unsigned long),
|
||||
.align = sizeof(unsigned long),
|
||||
.get = genregs_get,
|
||||
.regset_get = genregs_get,
|
||||
.set = genregs_set,
|
||||
}
|
||||
};
|
||||
|
@ -44,29 +44,15 @@
|
||||
*/
|
||||
static int genregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user * ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
const struct pt_regs *regs = task_pt_regs(target);
|
||||
int ret;
|
||||
|
||||
/* r0 */
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 0, 4);
|
||||
|
||||
if (!ret)
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
regs->gpr+1, 4, 4*32);
|
||||
if (!ret)
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
®s->pc, 4*32, 4*33);
|
||||
if (!ret)
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
®s->sr, 4*33, 4*34);
|
||||
if (!ret)
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
4*34, -1);
|
||||
|
||||
return ret;
|
||||
membuf_zero(&to, 4);
|
||||
membuf_write(&to, regs->gpr + 1, 31 * 4);
|
||||
membuf_store(&to, regs->pc);
|
||||
return membuf_store(&to, regs->sr);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -114,7 +100,7 @@ static const struct user_regset or1k_regsets[] = {
|
||||
.n = ELF_NGREG,
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.get = genregs_get,
|
||||
.regset_get = genregs_get,
|
||||
.set = genregs_set,
|
||||
},
|
||||
};
|
||||
|
@ -391,31 +391,11 @@ void do_syscall_trace_exit(struct pt_regs *regs)
|
||||
|
||||
static 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)
|
||||
{
|
||||
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;
|
||||
ubuf = u;
|
||||
pos *= sizeof(reg);
|
||||
count *= sizeof(reg);
|
||||
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
ELF_NFPREG * sizeof(reg), -1);
|
||||
return membuf_write(&to, regs->fr, ELF_NFPREG * sizeof(__u64));
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
{
|
||||
struct pt_regs *regs = task_regs(target);
|
||||
unsigned long *k = kbuf;
|
||||
unsigned long __user *u = ubuf;
|
||||
unsigned long reg;
|
||||
unsigned int pos;
|
||||
|
||||
pos /= sizeof(reg);
|
||||
count /= sizeof(reg);
|
||||
|
||||
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);
|
||||
for (pos = 0; pos < ELF_NGREG; pos++)
|
||||
membuf_store(&to, get_reg(regs, pos));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpr_set(struct task_struct *target,
|
||||
@ -588,12 +552,12 @@ static const struct user_regset native_regsets[] = {
|
||||
[REGSET_GENERAL] = {
|
||||
.core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
|
||||
.size = sizeof(long), .align = sizeof(long),
|
||||
.get = gpr_get, .set = gpr_set
|
||||
.regset_get = gpr_get, .set = gpr_set
|
||||
},
|
||||
[REGSET_FP] = {
|
||||
.core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
|
||||
.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 = {
|
||||
|
||||
static int gpr32_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
struct pt_regs *regs = task_regs(target);
|
||||
compat_ulong_t *k = kbuf;
|
||||
compat_ulong_t __user *u = ubuf;
|
||||
compat_ulong_t reg;
|
||||
unsigned int pos;
|
||||
|
||||
pos /= sizeof(reg);
|
||||
count /= sizeof(reg);
|
||||
for (pos = 0; pos < ELF_NGREG; pos++)
|
||||
membuf_store(&to, (compat_ulong_t)get_reg(regs, pos));
|
||||
|
||||
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((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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpr32_set(struct task_struct *target,
|
||||
@ -672,12 +620,12 @@ static const struct user_regset compat_regsets[] = {
|
||||
[REGSET_GENERAL] = {
|
||||
.core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
|
||||
.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] = {
|
||||
.core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
|
||||
.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)
|
||||
* };
|
||||
*/
|
||||
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);
|
||||
|
||||
BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
|
||||
offsetof(struct thread_vr_state, vr[32]));
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.vr_state, 0,
|
||||
33 * sizeof(vector128));
|
||||
if (!ret) {
|
||||
/*
|
||||
* Copy out only the low-order word of 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;
|
||||
membuf_write(&to, &target->thread.vr_state, 33 * sizeof(vector128));
|
||||
/*
|
||||
* Copy out only the low-order word of vrsave.
|
||||
*/
|
||||
memset(&vrsave, 0, sizeof(vrsave));
|
||||
vrsave.word = target->thread.vrsave;
|
||||
return membuf_write(&to, &vrsave, sizeof(vrsave));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -63,8 +63,7 @@ enum powerpc_regset {
|
||||
|
||||
/* ptrace-(no)vsx */
|
||||
|
||||
int fpr_get(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
|
||||
user_regset_get2_fn fpr_get;
|
||||
int fpr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf);
|
||||
@ -72,8 +71,7 @@ int fpr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
/* ptrace-vsx */
|
||||
|
||||
int vsr_active(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);
|
||||
user_regset_get2_fn vsr_get;
|
||||
int vsr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf);
|
||||
@ -81,8 +79,7 @@ int vsr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
/* ptrace-altivec */
|
||||
|
||||
int vr_active(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);
|
||||
user_regset_get2_fn vr_get;
|
||||
int vr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf);
|
||||
@ -90,8 +87,7 @@ int vr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
/* ptrace-spe */
|
||||
|
||||
int evr_active(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);
|
||||
user_regset_get2_fn evr_get;
|
||||
int evr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf);
|
||||
@ -100,9 +96,8 @@ int evr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
|
||||
int gpr32_get_common(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf,
|
||||
unsigned long *regs);
|
||||
struct membuf to,
|
||||
unsigned long *regs);
|
||||
int gpr32_set_common(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
@ -118,55 +113,46 @@ static inline void flush_tmregs_to_thread(struct task_struct *tsk) { }
|
||||
#endif
|
||||
|
||||
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,
|
||||
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
|
||||
user_regset_get2_fn tm_cgpr_get;
|
||||
int tm_cgpr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf);
|
||||
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,
|
||||
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
|
||||
user_regset_get2_fn tm_cfpr_get;
|
||||
int tm_cfpr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf);
|
||||
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,
|
||||
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
|
||||
user_regset_get2_fn tm_cvmx_get;
|
||||
int tm_cvmx_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf);
|
||||
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,
|
||||
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
|
||||
user_regset_get2_fn tm_cvsx_get;
|
||||
int tm_cvsx_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf);
|
||||
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,
|
||||
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
|
||||
user_regset_get2_fn tm_spr_get;
|
||||
int tm_spr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf);
|
||||
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,
|
||||
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
|
||||
user_regset_get2_fn tm_tar_get;
|
||||
int tm_tar_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf);
|
||||
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,
|
||||
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
|
||||
user_regset_get2_fn tm_ppr_get;
|
||||
int tm_ppr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf);
|
||||
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,
|
||||
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
|
||||
user_regset_get2_fn tm_dscr_get;
|
||||
int tm_dscr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf);
|
||||
int tm_cgpr32_get(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf);
|
||||
user_regset_get2_fn tm_cgpr32_get;
|
||||
int tm_cgpr32_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf);
|
||||
|
@ -19,15 +19,14 @@
|
||||
* };
|
||||
*/
|
||||
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) !=
|
||||
offsetof(struct thread_fp_state, fpr[32]));
|
||||
|
||||
flush_fp_to_thread(target);
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.fp_state, 0, -1);
|
||||
return membuf_write(&to, &target->thread.fp_state, 33 * sizeof(u64));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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,
|
||||
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
int ret;
|
||||
|
||||
flush_spe_to_thread(target);
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.evr,
|
||||
0, sizeof(target->thread.evr));
|
||||
membuf_write(&to, &target->thread.evr, sizeof(target->thread.evr));
|
||||
|
||||
BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) !=
|
||||
offsetof(struct thread_struct, spefscr));
|
||||
|
||||
if (!ret)
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.acc,
|
||||
sizeof(target->thread.evr), -1);
|
||||
|
||||
return ret;
|
||||
return membuf_write(&to, &target->thread.acc,
|
||||
sizeof(u64) + sizeof(u32));
|
||||
}
|
||||
|
||||
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)
|
||||
* tm_cgpr_get - get CGPR registers
|
||||
* @target: The target task.
|
||||
* @regset: The user regset structure.
|
||||
* @pos: The buffer position.
|
||||
* @count: Number of bytes to copy.
|
||||
* @kbuf: Kernel buffer to copy from.
|
||||
* @ubuf: User buffer to copy into.
|
||||
* @to: Destination of copy.
|
||||
*
|
||||
* This function gets transaction checkpointed GPR registers.
|
||||
*
|
||||
@ -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,
|
||||
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!cpu_has_feature(CPU_FTR_TM))
|
||||
return -ENODEV;
|
||||
|
||||
@ -101,31 +96,18 @@ int tm_cgpr_get(struct task_struct *target, const struct user_regset *regset,
|
||||
flush_fp_to_thread(target);
|
||||
flush_altivec_to_thread(target);
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.ckpt_regs,
|
||||
0, offsetof(struct pt_regs, msr));
|
||||
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));
|
||||
}
|
||||
membuf_write(&to, &target->thread.ckpt_regs,
|
||||
offsetof(struct pt_regs, msr));
|
||||
membuf_store(&to, get_user_ckpt_msr(target));
|
||||
|
||||
BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
|
||||
offsetof(struct pt_regs, msr) + sizeof(long));
|
||||
|
||||
if (!ret)
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.ckpt_regs.orig_gpr3,
|
||||
offsetof(struct pt_regs, orig_gpr3),
|
||||
sizeof(struct user_pt_regs));
|
||||
if (!ret)
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
sizeof(struct user_pt_regs), -1);
|
||||
|
||||
return ret;
|
||||
membuf_write(&to, &target->thread.ckpt_regs.orig_gpr3,
|
||||
sizeof(struct user_pt_regs) -
|
||||
offsetof(struct pt_regs, orig_gpr3));
|
||||
return membuf_zero(&to, ELF_NGREG * sizeof(unsigned long) -
|
||||
sizeof(struct user_pt_regs));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -229,10 +211,7 @@ int tm_cfpr_active(struct task_struct *target, const struct user_regset *regset)
|
||||
* tm_cfpr_get - get CFPR registers
|
||||
* @target: The target task.
|
||||
* @regset: The user regset structure.
|
||||
* @pos: The buffer position.
|
||||
* @count: Number of bytes to copy.
|
||||
* @kbuf: Kernel buffer to copy from.
|
||||
* @ubuf: User buffer to copy into.
|
||||
* @to: Destination of copy.
|
||||
*
|
||||
* 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)
|
||||
*};
|
||||
*/
|
||||
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];
|
||||
int i;
|
||||
@ -266,7 +245,7 @@ int tm_cfpr_get(struct task_struct *target, const struct user_regset *regset,
|
||||
for (i = 0; i < 32 ; i++)
|
||||
buf[i] = target->thread.TS_CKFPR(i);
|
||||
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)
|
||||
* tm_cvmx_get - get CMVX registers
|
||||
* @target: The target task.
|
||||
* @regset: The user regset structure.
|
||||
* @pos: The buffer position.
|
||||
* @count: Number of bytes to copy.
|
||||
* @kbuf: Kernel buffer to copy from.
|
||||
* @ubuf: User buffer to copy into.
|
||||
* @to: Destination of copy.
|
||||
*
|
||||
* 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)
|
||||
*};
|
||||
*/
|
||||
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]));
|
||||
|
||||
if (!cpu_has_feature(CPU_FTR_TM))
|
||||
@ -380,23 +358,13 @@ int tm_cvmx_get(struct task_struct *target, const struct user_regset *regset,
|
||||
flush_fp_to_thread(target);
|
||||
flush_altivec_to_thread(target);
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.ckvr_state,
|
||||
0, 33 * sizeof(vector128));
|
||||
if (!ret) {
|
||||
/*
|
||||
* Copy out only the low-order word of vrsave.
|
||||
*/
|
||||
union {
|
||||
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;
|
||||
membuf_write(&to, &target->thread.ckvr_state, 33 * sizeof(vector128));
|
||||
/*
|
||||
* Copy out only the low-order word of vrsave.
|
||||
*/
|
||||
memset(&vrsave, 0, sizeof(vrsave));
|
||||
vrsave.word = target->thread.ckvrsave;
|
||||
return membuf_write(&to, &vrsave, sizeof(vrsave));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -484,10 +452,7 @@ int tm_cvsx_active(struct task_struct *target, const struct user_regset *regset)
|
||||
* tm_cvsx_get - get CVSX registers
|
||||
* @target: The target task.
|
||||
* @regset: The user regset structure.
|
||||
* @pos: The buffer position.
|
||||
* @count: Number of bytes to copy.
|
||||
* @kbuf: Kernel buffer to copy from.
|
||||
* @ubuf: User buffer to copy into.
|
||||
* @to: Destination of copy.
|
||||
*
|
||||
* 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)
|
||||
*};
|
||||
*/
|
||||
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];
|
||||
int ret, i;
|
||||
int i;
|
||||
|
||||
if (!cpu_has_feature(CPU_FTR_TM))
|
||||
return -ENODEV;
|
||||
@ -520,10 +485,7 @@ int tm_cvsx_get(struct task_struct *target, const struct user_regset *regset,
|
||||
|
||||
for (i = 0; i < 32 ; i++)
|
||||
buf[i] = target->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET];
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
buf, 0, 32 * sizeof(double));
|
||||
|
||||
return ret;
|
||||
return membuf_write(&to, buf, 32 * sizeof(double));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -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
|
||||
* @target: The target task.
|
||||
* @regset: The user regset structure.
|
||||
* @pos: The buffer position.
|
||||
* @count: Number of bytes to copy.
|
||||
* @kbuf: Kernel buffer to copy from.
|
||||
* @ubuf: User buffer to copy into.
|
||||
* @to: Destination of copy.
|
||||
*
|
||||
* This function gets transactional memory related SPR registers.
|
||||
* 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)
|
||||
* };
|
||||
*/
|
||||
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_BUG_ON(TSO(tm_tfhar) + sizeof(u64) != TSO(tm_texasr));
|
||||
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,
|
||||
flush_altivec_to_thread(target);
|
||||
|
||||
/* TFHAR register */
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.tm_tfhar, 0, sizeof(u64));
|
||||
|
||||
membuf_write(&to, &target->thread.tm_tfhar, sizeof(u64));
|
||||
/* TEXASR register */
|
||||
if (!ret)
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.tm_texasr, sizeof(u64),
|
||||
2 * sizeof(u64));
|
||||
|
||||
membuf_write(&to, &target->thread.tm_texasr, sizeof(u64));
|
||||
/* TFIAR register */
|
||||
if (!ret)
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.tm_tfiar,
|
||||
2 * sizeof(u64), 3 * sizeof(u64));
|
||||
return ret;
|
||||
return membuf_write(&to, &target->thread.tm_tfiar, sizeof(u64));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -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,
|
||||
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!cpu_has_feature(CPU_FTR_TM))
|
||||
return -ENODEV;
|
||||
|
||||
if (!MSR_TM_ACTIVE(target->thread.regs->msr))
|
||||
return -ENODATA;
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.tm_tar, 0, sizeof(u64));
|
||||
return ret;
|
||||
return membuf_write(&to, &target->thread.tm_tar, sizeof(u64));
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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))
|
||||
return -ENODEV;
|
||||
|
||||
if (!MSR_TM_ACTIVE(target->thread.regs->msr))
|
||||
return -ENODATA;
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.tm_ppr, 0, sizeof(u64));
|
||||
return ret;
|
||||
return membuf_write(&to, &target->thread.tm_ppr, sizeof(u64));
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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))
|
||||
return -ENODEV;
|
||||
|
||||
if (!MSR_TM_ACTIVE(target->thread.regs->msr))
|
||||
return -ENODATA;
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.tm_dscr, 0, sizeof(u64));
|
||||
return ret;
|
||||
return membuf_write(&to, &target->thread.tm_dscr, sizeof(u64));
|
||||
}
|
||||
|
||||
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,
|
||||
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]);
|
||||
return membuf_zero(&to, ELF_NGREG * sizeof(u32));
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
return -EIO;
|
||||
@ -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;
|
||||
}
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
target->thread.regs,
|
||||
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));
|
||||
}
|
||||
membuf_write(&to, target->thread.regs, offsetof(struct pt_regs, msr));
|
||||
membuf_store(&to, get_user_msr(target));
|
||||
|
||||
BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
|
||||
offsetof(struct pt_regs, msr) + sizeof(long));
|
||||
|
||||
if (!ret)
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.regs->orig_gpr3,
|
||||
offsetof(struct pt_regs, orig_gpr3),
|
||||
sizeof(struct user_pt_regs));
|
||||
if (!ret)
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
sizeof(struct user_pt_regs), -1);
|
||||
|
||||
return ret;
|
||||
membuf_write(&to, &target->thread.regs->orig_gpr3,
|
||||
sizeof(struct user_pt_regs) -
|
||||
offsetof(struct pt_regs, orig_gpr3));
|
||||
return membuf_zero(&to, ELF_NGREG * sizeof(unsigned long) -
|
||||
sizeof(struct user_pt_regs));
|
||||
}
|
||||
|
||||
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
|
||||
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,
|
||||
&target->thread.regs->ppr, 0, sizeof(u64));
|
||||
return membuf_write(&to, &target->thread.regs->ppr, sizeof(u64));
|
||||
}
|
||||
|
||||
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,
|
||||
unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.dscr, 0, sizeof(u64));
|
||||
return membuf_write(&to, &target->thread.dscr, sizeof(u64));
|
||||
}
|
||||
static int dscr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
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
|
||||
#endif
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
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,
|
||||
&target->thread.tar, 0, sizeof(u64));
|
||||
return membuf_write(&to, &target->thread.tar, sizeof(u64));
|
||||
}
|
||||
static int tar_set(struct task_struct *target, const struct user_regset *regset,
|
||||
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
|
||||
}
|
||||
|
||||
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_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,
|
||||
if (!target->thread.used_ebb)
|
||||
return -ENODATA;
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.ebbrr,
|
||||
0, 3 * sizeof(unsigned long));
|
||||
return membuf_write(&to, &target->thread.ebbrr, 3 * sizeof(unsigned long));
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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_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,
|
||||
if (!cpu_has_feature(CPU_FTR_ARCH_207S))
|
||||
return -ENODEV;
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.siar,
|
||||
0, 5 * sizeof(unsigned long));
|
||||
return membuf_write(&to, &target->thread.siar, 5 * sizeof(unsigned long));
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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(iamr) + sizeof(unsigned long) != TSO(uamor));
|
||||
@ -494,8 +476,7 @@ static int pkey_get(struct task_struct *target, const struct user_regset *regset
|
||||
if (!arch_pkeys_enabled())
|
||||
return -ENODEV;
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.amr,
|
||||
0, ELF_NPKEY * sizeof(unsigned long));
|
||||
return membuf_write(&to, &target->thread.amr, ELF_NPKEY * sizeof(unsigned long));
|
||||
}
|
||||
|
||||
static int pkey_set(struct task_struct *target, const struct user_regset *regset,
|
||||
@ -529,110 +510,110 @@ static const struct user_regset native_regsets[] = {
|
||||
[REGSET_GPR] = {
|
||||
.core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
|
||||
.size = sizeof(long), .align = sizeof(long),
|
||||
.get = gpr_get, .set = gpr_set
|
||||
.regset_get = gpr_get, .set = gpr_set
|
||||
},
|
||||
[REGSET_FPR] = {
|
||||
.core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
|
||||
.size = sizeof(double), .align = sizeof(double),
|
||||
.get = fpr_get, .set = fpr_set
|
||||
.regset_get = fpr_get, .set = fpr_set
|
||||
},
|
||||
#ifdef CONFIG_ALTIVEC
|
||||
[REGSET_VMX] = {
|
||||
.core_note_type = NT_PPC_VMX, .n = 34,
|
||||
.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
|
||||
#ifdef CONFIG_VSX
|
||||
[REGSET_VSX] = {
|
||||
.core_note_type = NT_PPC_VSX, .n = 32,
|
||||
.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
|
||||
#ifdef CONFIG_SPE
|
||||
[REGSET_SPE] = {
|
||||
.core_note_type = NT_PPC_SPE, .n = 35,
|
||||
.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
|
||||
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
|
||||
[REGSET_TM_CGPR] = {
|
||||
.core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG,
|
||||
.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] = {
|
||||
.core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,
|
||||
.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] = {
|
||||
.core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX,
|
||||
.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] = {
|
||||
.core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX,
|
||||
.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] = {
|
||||
.core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG,
|
||||
.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] = {
|
||||
.core_note_type = NT_PPC_TM_CTAR, .n = 1,
|
||||
.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] = {
|
||||
.core_note_type = NT_PPC_TM_CPPR, .n = 1,
|
||||
.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] = {
|
||||
.core_note_type = NT_PPC_TM_CDSCR, .n = 1,
|
||||
.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
|
||||
#ifdef CONFIG_PPC64
|
||||
[REGSET_PPR] = {
|
||||
.core_note_type = NT_PPC_PPR, .n = 1,
|
||||
.size = sizeof(u64), .align = sizeof(u64),
|
||||
.get = ppr_get, .set = ppr_set
|
||||
.regset_get = ppr_get, .set = ppr_set
|
||||
},
|
||||
[REGSET_DSCR] = {
|
||||
.core_note_type = NT_PPC_DSCR, .n = 1,
|
||||
.size = sizeof(u64), .align = sizeof(u64),
|
||||
.get = dscr_get, .set = dscr_set
|
||||
.regset_get = dscr_get, .set = dscr_set
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
[REGSET_TAR] = {
|
||||
.core_note_type = NT_PPC_TAR, .n = 1,
|
||||
.size = sizeof(u64), .align = sizeof(u64),
|
||||
.get = tar_get, .set = tar_set
|
||||
.regset_get = tar_get, .set = tar_set
|
||||
},
|
||||
[REGSET_EBB] = {
|
||||
.core_note_type = NT_PPC_EBB, .n = ELF_NEBB,
|
||||
.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] = {
|
||||
.core_note_type = NT_PPC_PMU, .n = ELF_NPMU,
|
||||
.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
|
||||
#ifdef CONFIG_PPC_MEM_KEYS
|
||||
[REGSET_PKEY] = {
|
||||
.core_note_type = NT_PPC_PKEY, .n = ELF_NPKEY,
|
||||
.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
|
||||
};
|
||||
@ -646,49 +627,16 @@ const struct user_regset_view user_ppc_native_view = {
|
||||
|
||||
int gpr32_get_common(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf,
|
||||
unsigned long *regs)
|
||||
struct membuf to, unsigned long *regs)
|
||||
{
|
||||
compat_ulong_t *k = kbuf;
|
||||
compat_ulong_t __user *u = ubuf;
|
||||
compat_ulong_t reg;
|
||||
int i;
|
||||
|
||||
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;
|
||||
ubuf = u;
|
||||
pos *= sizeof(reg);
|
||||
count *= sizeof(reg);
|
||||
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
PT_REGS_COUNT * sizeof(reg), -1);
|
||||
for (i = 0; i < PT_MSR; i++)
|
||||
membuf_store(&to, (u32)regs[i]);
|
||||
membuf_store(&to, (u32)get_user_msr(target));
|
||||
for (i++ ; i < PT_REGS_COUNT; i++)
|
||||
membuf_store(&to, (u32)regs[i]);
|
||||
return membuf_zero(&to, (ELF_NGREG - PT_REGS_COUNT) * sizeof(u32));
|
||||
}
|
||||
|
||||
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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -777,7 +724,7 @@ static int gpr32_get(struct task_struct *target,
|
||||
for (i = 14; i < 32; i++)
|
||||
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]);
|
||||
}
|
||||
|
||||
@ -801,25 +748,25 @@ static const struct user_regset compat_regsets[] = {
|
||||
[REGSET_GPR] = {
|
||||
.core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
|
||||
.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] = {
|
||||
.core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
|
||||
.size = sizeof(double), .align = sizeof(double),
|
||||
.get = fpr_get, .set = fpr_set
|
||||
.regset_get = fpr_get, .set = fpr_set
|
||||
},
|
||||
#ifdef CONFIG_ALTIVEC
|
||||
[REGSET_VMX] = {
|
||||
.core_note_type = NT_PPC_VMX, .n = 34,
|
||||
.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
|
||||
#ifdef CONFIG_SPE
|
||||
[REGSET_SPE] = {
|
||||
.core_note_type = NT_PPC_SPE, .n = 35,
|
||||
.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
|
||||
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
|
||||
@ -827,66 +774,66 @@ static const struct user_regset compat_regsets[] = {
|
||||
.core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG,
|
||||
.size = sizeof(long), .align = sizeof(long),
|
||||
.active = tm_cgpr_active,
|
||||
.get = tm_cgpr32_get, .set = tm_cgpr32_set
|
||||
.regset_get = tm_cgpr32_get, .set = tm_cgpr32_set
|
||||
},
|
||||
[REGSET_TM_CFPR] = {
|
||||
.core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,
|
||||
.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] = {
|
||||
.core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX,
|
||||
.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] = {
|
||||
.core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX,
|
||||
.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] = {
|
||||
.core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG,
|
||||
.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] = {
|
||||
.core_note_type = NT_PPC_TM_CTAR, .n = 1,
|
||||
.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] = {
|
||||
.core_note_type = NT_PPC_TM_CPPR, .n = 1,
|
||||
.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] = {
|
||||
.core_note_type = NT_PPC_TM_CDSCR, .n = 1,
|
||||
.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
|
||||
#ifdef CONFIG_PPC64
|
||||
[REGSET_PPR] = {
|
||||
.core_note_type = NT_PPC_PPR, .n = 1,
|
||||
.size = sizeof(u64), .align = sizeof(u64),
|
||||
.get = ppr_get, .set = ppr_set
|
||||
.regset_get = ppr_get, .set = ppr_set
|
||||
},
|
||||
[REGSET_DSCR] = {
|
||||
.core_note_type = NT_PPC_DSCR, .n = 1,
|
||||
.size = sizeof(u64), .align = sizeof(u64),
|
||||
.get = dscr_get, .set = dscr_set
|
||||
.regset_get = dscr_get, .set = dscr_set
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
[REGSET_TAR] = {
|
||||
.core_note_type = NT_PPC_TAR, .n = 1,
|
||||
.size = sizeof(u64), .align = sizeof(u64),
|
||||
.get = tar_get, .set = tar_set
|
||||
.regset_get = tar_get, .set = tar_set
|
||||
},
|
||||
[REGSET_EBB] = {
|
||||
.core_note_type = NT_PPC_EBB, .n = ELF_NEBB,
|
||||
.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
|
||||
};
|
||||
|
@ -19,7 +19,7 @@
|
||||
* };
|
||||
*/
|
||||
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];
|
||||
int i;
|
||||
@ -30,7 +30,7 @@ int fpr_get(struct task_struct *target, const struct user_regset *regset,
|
||||
for (i = 0; i < 32 ; i++)
|
||||
buf[i] = target->thread.TS_FPR(i);
|
||||
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)
|
||||
* };
|
||||
*/
|
||||
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];
|
||||
int ret, i;
|
||||
int i;
|
||||
|
||||
flush_tmregs_to_thread(target);
|
||||
flush_fp_to_thread(target);
|
||||
@ -108,10 +108,7 @@ int vsr_get(struct task_struct *target, const struct user_regset *regset,
|
||||
for (i = 0; i < 32 ; i++)
|
||||
buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET];
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
buf, 0, 32 * sizeof(double));
|
||||
|
||||
return ret;
|
||||
return membuf_write(&to, buf, 32 * sizeof(double));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -30,13 +30,10 @@ enum riscv_regset {
|
||||
|
||||
static int riscv_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)
|
||||
{
|
||||
struct pt_regs *regs;
|
||||
|
||||
regs = task_pt_regs(target);
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
|
||||
return membuf_write(&to, task_pt_regs(target),
|
||||
sizeof(struct user_regs_struct));
|
||||
}
|
||||
|
||||
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
|
||||
static int riscv_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)
|
||||
{
|
||||
int ret;
|
||||
struct __riscv_d_ext_state *fstate = &target->thread.fstate;
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, fstate, 0,
|
||||
offsetof(struct __riscv_d_ext_state, fcsr));
|
||||
if (!ret) {
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, fstate, 0,
|
||||
offsetof(struct __riscv_d_ext_state, fcsr) +
|
||||
sizeof(fstate->fcsr));
|
||||
}
|
||||
|
||||
return ret;
|
||||
membuf_write(&to, fstate, offsetof(struct __riscv_d_ext_state, fcsr));
|
||||
membuf_store(&to, fstate->fcsr);
|
||||
return membuf_zero(&to, 4); // explicitly pad
|
||||
}
|
||||
|
||||
static int riscv_fpr_set(struct task_struct *target,
|
||||
@ -98,8 +87,8 @@ static const struct user_regset riscv_user_regset[] = {
|
||||
.n = ELF_NGREG,
|
||||
.size = sizeof(elf_greg_t),
|
||||
.align = sizeof(elf_greg_t),
|
||||
.get = &riscv_gpr_get,
|
||||
.set = &riscv_gpr_set,
|
||||
.regset_get = riscv_gpr_get,
|
||||
.set = riscv_gpr_set,
|
||||
},
|
||||
#ifdef CONFIG_FPU
|
||||
[REGSET_F] = {
|
||||
@ -107,8 +96,8 @@ static const struct user_regset riscv_user_regset[] = {
|
||||
.n = ELF_NFPREG,
|
||||
.size = sizeof(elf_fpreg_t),
|
||||
.align = sizeof(elf_fpreg_t),
|
||||
.get = &riscv_fpr_get,
|
||||
.set = &riscv_fpr_set,
|
||||
.regset_get = riscv_fpr_get,
|
||||
.set = riscv_fpr_set,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
@ -945,28 +945,14 @@ asmlinkage void do_syscall_trace_exit(struct pt_regs *regs)
|
||||
|
||||
static int s390_regs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
unsigned pos;
|
||||
if (target == current)
|
||||
save_access_regs(target->thread.acrs);
|
||||
|
||||
if (kbuf) {
|
||||
unsigned long *k = kbuf;
|
||||
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);
|
||||
}
|
||||
}
|
||||
for (pos = 0; pos < sizeof(s390_regs); pos += sizeof(long))
|
||||
membuf_store(&to, __peek_user(target, pos));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1007,8 +993,8 @@ static int s390_regs_set(struct task_struct *target,
|
||||
}
|
||||
|
||||
static int s390_fpregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset, unsigned int pos,
|
||||
unsigned int count, void *kbuf, void __user *ubuf)
|
||||
const struct user_regset *regset,
|
||||
struct membuf to)
|
||||
{
|
||||
_s390_fp_regs fp_regs;
|
||||
|
||||
@ -1018,8 +1004,7 @@ static int s390_fpregs_get(struct task_struct *target,
|
||||
fp_regs.fpc = target->thread.fpu.fpc;
|
||||
fpregs_store(&fp_regs, &target->thread.fpu);
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&fp_regs, 0, -1);
|
||||
return membuf_write(&to, &fp_regs, sizeof(fp_regs));
|
||||
}
|
||||
|
||||
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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
if (count > 0) {
|
||||
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;
|
||||
return membuf_store(&to, target->thread.last_break);
|
||||
}
|
||||
|
||||
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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
unsigned char *data;
|
||||
|
||||
if (!(regs->int_code & 0x200))
|
||||
return -ENODATA;
|
||||
data = target->thread.trap_tdb;
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, data, 0, 256);
|
||||
return membuf_write(&to, target->thread.trap_tdb, 256);
|
||||
}
|
||||
|
||||
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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
__u64 vxrs[__NUM_VXRS_LOW];
|
||||
int i;
|
||||
@ -1126,7 +1096,7 @@ static int s390_vxrs_low_get(struct task_struct *target,
|
||||
save_fpu_regs();
|
||||
for (i = 0; i < __NUM_VXRS_LOW; i++)
|
||||
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,
|
||||
@ -1155,18 +1125,14 @@ static int s390_vxrs_low_set(struct task_struct *target,
|
||||
|
||||
static int s390_vxrs_high_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
__vector128 vxrs[__NUM_VXRS_HIGH];
|
||||
|
||||
if (!MACHINE_HAS_VX)
|
||||
return -ENODEV;
|
||||
if (target == current)
|
||||
save_fpu_regs();
|
||||
memcpy(vxrs, target->thread.fpu.vxrs + __NUM_VXRS_LOW, sizeof(vxrs));
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1);
|
||||
return membuf_write(&to, target->thread.fpu.vxrs + __NUM_VXRS_LOW,
|
||||
__NUM_VXRS_HIGH * sizeof(__vector128));
|
||||
}
|
||||
|
||||
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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
unsigned int *data = &target->thread.system_call;
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
data, 0, sizeof(unsigned int));
|
||||
return membuf_store(&to, target->thread.system_call);
|
||||
}
|
||||
|
||||
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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
struct gs_cb *data = target->thread.gs_cb;
|
||||
|
||||
@ -1219,8 +1181,7 @@ static int s390_gs_cb_get(struct task_struct *target,
|
||||
return -ENODATA;
|
||||
if (target == current)
|
||||
save_gs_cb(data);
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
data, 0, sizeof(struct gs_cb));
|
||||
return membuf_write(&to, data, sizeof(struct gs_cb));
|
||||
}
|
||||
|
||||
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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
struct gs_cb *data = target->thread.gs_bc_cb;
|
||||
|
||||
@ -1273,8 +1233,7 @@ static int s390_gs_bc_get(struct task_struct *target,
|
||||
return -ENODEV;
|
||||
if (!data)
|
||||
return -ENODATA;
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
data, 0, sizeof(struct gs_cb));
|
||||
return membuf_write(&to, data, sizeof(struct gs_cb));
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
static int s390_runtime_instr_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
struct runtime_instr_cb *data = target->thread.ri_cb;
|
||||
|
||||
@ -1335,8 +1293,7 @@ static int s390_runtime_instr_get(struct task_struct *target,
|
||||
if (!data)
|
||||
return -ENODATA;
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
data, 0, sizeof(struct runtime_instr_cb));
|
||||
return membuf_write(&to, data, sizeof(struct runtime_instr_cb));
|
||||
}
|
||||
|
||||
static int s390_runtime_instr_set(struct task_struct *target,
|
||||
@ -1392,7 +1349,7 @@ static const struct user_regset s390_regsets[] = {
|
||||
.n = sizeof(s390_regs) / sizeof(long),
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.get = s390_regs_get,
|
||||
.regset_get = s390_regs_get,
|
||||
.set = s390_regs_set,
|
||||
},
|
||||
{
|
||||
@ -1400,7 +1357,7 @@ static const struct user_regset s390_regsets[] = {
|
||||
.n = sizeof(s390_fp_regs) / sizeof(long),
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.get = s390_fpregs_get,
|
||||
.regset_get = s390_fpregs_get,
|
||||
.set = s390_fpregs_set,
|
||||
},
|
||||
{
|
||||
@ -1408,7 +1365,7 @@ static const struct user_regset s390_regsets[] = {
|
||||
.n = 1,
|
||||
.size = sizeof(unsigned int),
|
||||
.align = sizeof(unsigned int),
|
||||
.get = s390_system_call_get,
|
||||
.regset_get = s390_system_call_get,
|
||||
.set = s390_system_call_set,
|
||||
},
|
||||
{
|
||||
@ -1416,7 +1373,7 @@ static const struct user_regset s390_regsets[] = {
|
||||
.n = 1,
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.get = s390_last_break_get,
|
||||
.regset_get = s390_last_break_get,
|
||||
.set = s390_last_break_set,
|
||||
},
|
||||
{
|
||||
@ -1424,7 +1381,7 @@ static const struct user_regset s390_regsets[] = {
|
||||
.n = 1,
|
||||
.size = 256,
|
||||
.align = 1,
|
||||
.get = s390_tdb_get,
|
||||
.regset_get = s390_tdb_get,
|
||||
.set = s390_tdb_set,
|
||||
},
|
||||
{
|
||||
@ -1432,7 +1389,7 @@ static const struct user_regset s390_regsets[] = {
|
||||
.n = __NUM_VXRS_LOW,
|
||||
.size = sizeof(__u64),
|
||||
.align = sizeof(__u64),
|
||||
.get = s390_vxrs_low_get,
|
||||
.regset_get = s390_vxrs_low_get,
|
||||
.set = s390_vxrs_low_set,
|
||||
},
|
||||
{
|
||||
@ -1440,7 +1397,7 @@ static const struct user_regset s390_regsets[] = {
|
||||
.n = __NUM_VXRS_HIGH,
|
||||
.size = sizeof(__vector128),
|
||||
.align = sizeof(__vector128),
|
||||
.get = s390_vxrs_high_get,
|
||||
.regset_get = s390_vxrs_high_get,
|
||||
.set = s390_vxrs_high_set,
|
||||
},
|
||||
{
|
||||
@ -1448,7 +1405,7 @@ static const struct user_regset s390_regsets[] = {
|
||||
.n = sizeof(struct gs_cb) / sizeof(__u64),
|
||||
.size = sizeof(__u64),
|
||||
.align = sizeof(__u64),
|
||||
.get = s390_gs_cb_get,
|
||||
.regset_get = s390_gs_cb_get,
|
||||
.set = s390_gs_cb_set,
|
||||
},
|
||||
{
|
||||
@ -1456,7 +1413,7 @@ static const struct user_regset s390_regsets[] = {
|
||||
.n = sizeof(struct gs_cb) / sizeof(__u64),
|
||||
.size = sizeof(__u64),
|
||||
.align = sizeof(__u64),
|
||||
.get = s390_gs_bc_get,
|
||||
.regset_get = s390_gs_bc_get,
|
||||
.set = s390_gs_bc_set,
|
||||
},
|
||||
{
|
||||
@ -1464,7 +1421,7 @@ static const struct user_regset s390_regsets[] = {
|
||||
.n = sizeof(struct runtime_instr_cb) / sizeof(__u64),
|
||||
.size = sizeof(__u64),
|
||||
.align = sizeof(__u64),
|
||||
.get = s390_runtime_instr_get,
|
||||
.regset_get = s390_runtime_instr_get,
|
||||
.set = s390_runtime_instr_set,
|
||||
},
|
||||
};
|
||||
@ -1479,28 +1436,15 @@ static const struct user_regset_view user_s390_view = {
|
||||
#ifdef CONFIG_COMPAT
|
||||
static int s390_compat_regs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
unsigned n;
|
||||
|
||||
if (target == current)
|
||||
save_access_regs(target->thread.acrs);
|
||||
|
||||
if (kbuf) {
|
||||
compat_ulong_t *k = kbuf;
|
||||
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);
|
||||
}
|
||||
}
|
||||
for (n = 0; n < sizeof(s390_compat_regs); n += sizeof(compat_ulong_t))
|
||||
membuf_store(&to, __peek_user_compat(target, n));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
compat_ulong_t *gprs_high;
|
||||
int i;
|
||||
|
||||
gprs_high = (compat_ulong_t *)
|
||||
&task_pt_regs(target)->gprs[pos / sizeof(compat_ulong_t)];
|
||||
if (kbuf) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
gprs_high = (compat_ulong_t *)task_pt_regs(target)->gprs;
|
||||
for (i = 0; i < NUM_GPRS; i++, gprs_high += 2)
|
||||
membuf_store(&to, *gprs_high);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
compat_ulong_t last_break;
|
||||
compat_ulong_t last_break = target->thread.last_break;
|
||||
|
||||
if (count > 0) {
|
||||
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;
|
||||
return membuf_store(&to, (unsigned long)last_break);
|
||||
}
|
||||
|
||||
static int s390_compat_last_break_set(struct task_struct *target,
|
||||
@ -1636,7 +1553,7 @@ static const struct user_regset s390_compat_regsets[] = {
|
||||
.n = sizeof(s390_compat_regs) / sizeof(compat_long_t),
|
||||
.size = 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,
|
||||
},
|
||||
{
|
||||
@ -1644,7 +1561,7 @@ static const struct user_regset s390_compat_regsets[] = {
|
||||
.n = sizeof(s390_fp_regs) / sizeof(compat_long_t),
|
||||
.size = sizeof(compat_long_t),
|
||||
.align = sizeof(compat_long_t),
|
||||
.get = s390_fpregs_get,
|
||||
.regset_get = s390_fpregs_get,
|
||||
.set = s390_fpregs_set,
|
||||
},
|
||||
{
|
||||
@ -1652,7 +1569,7 @@ static const struct user_regset s390_compat_regsets[] = {
|
||||
.n = 1,
|
||||
.size = 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,
|
||||
},
|
||||
{
|
||||
@ -1660,7 +1577,7 @@ static const struct user_regset s390_compat_regsets[] = {
|
||||
.n = 1,
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.get = s390_compat_last_break_get,
|
||||
.regset_get = s390_compat_last_break_get,
|
||||
.set = s390_compat_last_break_set,
|
||||
},
|
||||
{
|
||||
@ -1668,7 +1585,7 @@ static const struct user_regset s390_compat_regsets[] = {
|
||||
.n = 1,
|
||||
.size = 256,
|
||||
.align = 1,
|
||||
.get = s390_tdb_get,
|
||||
.regset_get = s390_tdb_get,
|
||||
.set = s390_tdb_set,
|
||||
},
|
||||
{
|
||||
@ -1676,7 +1593,7 @@ static const struct user_regset s390_compat_regsets[] = {
|
||||
.n = __NUM_VXRS_LOW,
|
||||
.size = sizeof(__u64),
|
||||
.align = sizeof(__u64),
|
||||
.get = s390_vxrs_low_get,
|
||||
.regset_get = s390_vxrs_low_get,
|
||||
.set = s390_vxrs_low_set,
|
||||
},
|
||||
{
|
||||
@ -1684,7 +1601,7 @@ static const struct user_regset s390_compat_regsets[] = {
|
||||
.n = __NUM_VXRS_HIGH,
|
||||
.size = sizeof(__vector128),
|
||||
.align = sizeof(__vector128),
|
||||
.get = s390_vxrs_high_get,
|
||||
.regset_get = s390_vxrs_high_get,
|
||||
.set = s390_vxrs_high_set,
|
||||
},
|
||||
{
|
||||
@ -1692,7 +1609,7 @@ static const struct user_regset s390_compat_regsets[] = {
|
||||
.n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t),
|
||||
.size = 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,
|
||||
},
|
||||
{
|
||||
@ -1700,7 +1617,7 @@ static const struct user_regset s390_compat_regsets[] = {
|
||||
.n = sizeof(struct gs_cb) / sizeof(__u64),
|
||||
.size = sizeof(__u64),
|
||||
.align = sizeof(__u64),
|
||||
.get = s390_gs_cb_get,
|
||||
.regset_get = s390_gs_cb_get,
|
||||
.set = s390_gs_cb_set,
|
||||
},
|
||||
{
|
||||
@ -1708,7 +1625,7 @@ static const struct user_regset s390_compat_regsets[] = {
|
||||
.n = sizeof(struct gs_cb) / sizeof(__u64),
|
||||
.size = sizeof(__u64),
|
||||
.align = sizeof(__u64),
|
||||
.get = s390_gs_bc_get,
|
||||
.regset_get = s390_gs_bc_get,
|
||||
.set = s390_gs_bc_set,
|
||||
},
|
||||
{
|
||||
@ -1716,7 +1633,7 @@ static const struct user_regset s390_compat_regsets[] = {
|
||||
.n = sizeof(struct runtime_instr_cb) / sizeof(__u64),
|
||||
.size = sizeof(__u64),
|
||||
.align = sizeof(__u64),
|
||||
.get = s390_runtime_instr_get,
|
||||
.regset_get = s390_runtime_instr_get,
|
||||
.set = s390_runtime_instr_set,
|
||||
},
|
||||
};
|
||||
|
@ -103,9 +103,8 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
|
||||
|
||||
fpvalid = !!tsk_used_math(tsk);
|
||||
if (fpvalid)
|
||||
fpvalid = !fpregs_get(tsk, NULL, 0,
|
||||
sizeof(struct user_fpu_struct),
|
||||
fpu, NULL);
|
||||
fpvalid = !fpregs_get(tsk, NULL,
|
||||
(struct membuf){fpu, sizeof(*fpu)});
|
||||
#endif
|
||||
|
||||
return fpvalid;
|
||||
|
@ -134,26 +134,11 @@ void ptrace_disable(struct task_struct *child)
|
||||
|
||||
static int genregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
const struct pt_regs *regs = task_pt_regs(target);
|
||||
int ret;
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
regs->regs,
|
||||
0, 16 * sizeof(unsigned long));
|
||||
if (!ret)
|
||||
/* PC, PR, SR, GBR, MACH, MACL, TRA */
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
®s->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;
|
||||
return membuf_write(&to, regs, sizeof(struct pt_regs));
|
||||
}
|
||||
|
||||
static int genregs_set(struct task_struct *target,
|
||||
@ -182,8 +167,7 @@ static int genregs_set(struct task_struct *target,
|
||||
#ifdef CONFIG_SH_FPU
|
||||
int fpregs_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;
|
||||
|
||||
@ -191,12 +175,8 @@ int fpregs_get(struct task_struct *target,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if ((boot_cpu_data.flags & CPU_HAS_FPU))
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.xstate->hardfpu, 0, -1);
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.xstate->softfpu, 0, -1);
|
||||
return membuf_write(&to, target->thread.xstate,
|
||||
sizeof(struct user_fpu_struct));
|
||||
}
|
||||
|
||||
static int fpregs_set(struct task_struct *target,
|
||||
@ -230,20 +210,12 @@ static int fpregs_active(struct task_struct *target,
|
||||
#ifdef CONFIG_SH_DSP
|
||||
static int dspregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
const struct pt_dspregs *regs =
|
||||
(struct pt_dspregs *)&target->thread.dsp_status.dsp_regs;
|
||||
int ret;
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs,
|
||||
0, sizeof(struct pt_dspregs));
|
||||
if (!ret)
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
sizeof(struct pt_dspregs), -1);
|
||||
|
||||
return ret;
|
||||
return membuf_write(&to, regs, sizeof(struct pt_dspregs));
|
||||
}
|
||||
|
||||
static int dspregs_set(struct task_struct *target,
|
||||
@ -324,7 +296,7 @@ static const struct user_regset sh_regsets[] = {
|
||||
.n = ELF_NGREG,
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.get = genregs_get,
|
||||
.regset_get = genregs_get,
|
||||
.set = genregs_set,
|
||||
},
|
||||
|
||||
@ -334,7 +306,7 @@ static const struct user_regset sh_regsets[] = {
|
||||
.n = sizeof(struct user_fpu_struct) / sizeof(long),
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.get = fpregs_get,
|
||||
.regset_get = fpregs_get,
|
||||
.set = fpregs_set,
|
||||
.active = fpregs_active,
|
||||
},
|
||||
@ -345,7 +317,7 @@ static const struct user_regset sh_regsets[] = {
|
||||
.n = sizeof(struct pt_dspregs) / sizeof(long),
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.get = dspregs_get,
|
||||
.regset_get = dspregs_get,
|
||||
.set = dspregs_set,
|
||||
.active = dspregs_active,
|
||||
},
|
||||
|
@ -83,41 +83,25 @@ static int regwindow32_set(struct task_struct *target,
|
||||
|
||||
static int genregs32_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
const struct pt_regs *regs = target->thread.kregs;
|
||||
u32 uregs[16];
|
||||
int ret;
|
||||
|
||||
if (target == current)
|
||||
flush_user_windows();
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
regs->u_regs,
|
||||
0, 16 * sizeof(u32));
|
||||
if (ret || !count)
|
||||
return ret;
|
||||
|
||||
if (pos < 32 * sizeof(u32)) {
|
||||
if (regwindow32_get(target, regs, uregs))
|
||||
return -EFAULT;
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
uregs,
|
||||
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));
|
||||
membuf_write(&to, regs->u_regs, 16 * sizeof(u32));
|
||||
if (!to.left)
|
||||
return 0;
|
||||
if (regwindow32_get(target, regs, uregs))
|
||||
return -EFAULT;
|
||||
membuf_write(&to, uregs, 16 * sizeof(u32));
|
||||
membuf_store(&to, regs->psr);
|
||||
membuf_store(&to, regs->pc);
|
||||
membuf_store(&to, regs->npc);
|
||||
membuf_store(&to, regs->y);
|
||||
return membuf_zero(&to, 2 * sizeof(u32));
|
||||
}
|
||||
|
||||
static int genregs32_set(struct task_struct *target,
|
||||
@ -139,19 +123,18 @@ static int genregs32_set(struct task_struct *target,
|
||||
if (ret || !count)
|
||||
return ret;
|
||||
|
||||
if (pos < 32 * sizeof(u32)) {
|
||||
if (regwindow32_get(target, regs, uregs))
|
||||
return -EFAULT;
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
uregs,
|
||||
16 * sizeof(u32), 32 * sizeof(u32));
|
||||
if (ret)
|
||||
return ret;
|
||||
if (regwindow32_set(target, regs, uregs))
|
||||
return -EFAULT;
|
||||
if (!count)
|
||||
return 0;
|
||||
}
|
||||
if (regwindow32_get(target, regs, uregs))
|
||||
return -EFAULT;
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
uregs,
|
||||
16 * sizeof(u32), 32 * sizeof(u32));
|
||||
if (ret)
|
||||
return ret;
|
||||
if (regwindow32_set(target, regs, uregs))
|
||||
return -EFAULT;
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&psr,
|
||||
32 * sizeof(u32), 33 * sizeof(u32));
|
||||
@ -182,46 +165,18 @@ static int genregs32_set(struct task_struct *target,
|
||||
|
||||
static int fpregs32_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
const unsigned long *fpregs = target->thread.float_regs;
|
||||
int ret = 0;
|
||||
|
||||
#if 0
|
||||
if (target == current)
|
||||
save_and_clear_fpu();
|
||||
#endif
|
||||
|
||||
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,
|
||||
&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;
|
||||
membuf_write(&to, target->thread.float_regs, 32 * sizeof(u32));
|
||||
membuf_zero(&to, sizeof(u32));
|
||||
membuf_write(&to, &target->thread.fsr, sizeof(u32));
|
||||
membuf_store(&to, (u32)((1 << 8) | (8 << 16)));
|
||||
return membuf_zero(&to, 64 * sizeof(u32));
|
||||
}
|
||||
|
||||
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,
|
||||
32 * sizeof(u32),
|
||||
33 * sizeof(u32));
|
||||
if (!ret && count > 0) {
|
||||
if (!ret)
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.fsr,
|
||||
33 * sizeof(u32),
|
||||
34 * sizeof(u32));
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
||||
34 * sizeof(u32), -1);
|
||||
@ -268,7 +221,7 @@ static const struct user_regset sparc32_regsets[] = {
|
||||
.core_note_type = NT_PRSTATUS,
|
||||
.n = 38,
|
||||
.size = sizeof(u32), .align = sizeof(u32),
|
||||
.get = genregs32_get, .set = genregs32_set
|
||||
.regset_get = genregs32_get, .set = genregs32_set
|
||||
},
|
||||
/* Format is:
|
||||
* F0 --> F31
|
||||
@ -284,10 +237,104 @@ static const struct user_regset sparc32_regsets[] = {
|
||||
.core_note_type = NT_PRFPREG,
|
||||
.n = 99,
|
||||
.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 = {
|
||||
.name = "sparc", .e_machine = EM_SPARC,
|
||||
.regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
|
||||
@ -315,74 +362,44 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||
{
|
||||
unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
|
||||
void __user *addr2p;
|
||||
const struct user_regset_view *view;
|
||||
struct pt_regs __user *pregs;
|
||||
struct fps __user *fps;
|
||||
int ret;
|
||||
|
||||
view = task_user_regset_view(current);
|
||||
addr2p = (void __user *) addr2;
|
||||
pregs = (struct pt_regs __user *) addr;
|
||||
fps = (struct fps __user *) addr;
|
||||
|
||||
switch(request) {
|
||||
case PTRACE_GETREGS: {
|
||||
ret = copy_regset_to_user(child, view, REGSET_GENERAL,
|
||||
32 * sizeof(u32),
|
||||
4 * sizeof(u32),
|
||||
&pregs->psr);
|
||||
if (!ret)
|
||||
copy_regset_to_user(child, view, REGSET_GENERAL,
|
||||
1 * sizeof(u32),
|
||||
15 * sizeof(u32),
|
||||
&pregs->u_regs[0]);
|
||||
ret = copy_regset_to_user(child, &ptrace32_view,
|
||||
REGSET_GENERAL, 0,
|
||||
19 * sizeof(u32),
|
||||
pregs);
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SETREGS: {
|
||||
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
|
||||
32 * sizeof(u32),
|
||||
4 * sizeof(u32),
|
||||
&pregs->psr);
|
||||
if (!ret)
|
||||
copy_regset_from_user(child, view, REGSET_GENERAL,
|
||||
1 * sizeof(u32),
|
||||
15 * sizeof(u32),
|
||||
&pregs->u_regs[0]);
|
||||
ret = copy_regset_from_user(child, &ptrace32_view,
|
||||
REGSET_GENERAL, 0,
|
||||
19 * sizeof(u32),
|
||||
pregs);
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_GETFPREGS: {
|
||||
ret = copy_regset_to_user(child, view, REGSET_FP,
|
||||
0 * sizeof(u32),
|
||||
32 * sizeof(u32),
|
||||
&fps->regs[0]);
|
||||
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;
|
||||
}
|
||||
ret = copy_regset_to_user(child, &ptrace32_view,
|
||||
REGSET_FP, 0,
|
||||
68 * sizeof(u32),
|
||||
fps);
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SETFPREGS: {
|
||||
ret = copy_regset_from_user(child, view, REGSET_FP,
|
||||
0 * sizeof(u32),
|
||||
32 * sizeof(u32),
|
||||
&fps->regs[0]);
|
||||
if (!ret)
|
||||
ret = copy_regset_from_user(child, view, REGSET_FP,
|
||||
33 * sizeof(u32),
|
||||
1 * sizeof(u32),
|
||||
&fps->fsr);
|
||||
ret = copy_regset_from_user(child, &ptrace32_view,
|
||||
REGSET_FP, 0,
|
||||
33 * sizeof(u32),
|
||||
fps);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -246,52 +246,23 @@ enum sparc_regset {
|
||||
|
||||
static int genregs64_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
const struct pt_regs *regs = task_pt_regs(target);
|
||||
int ret;
|
||||
struct reg_window window;
|
||||
|
||||
if (target == current)
|
||||
flushw_user();
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
regs->u_regs,
|
||||
0, 16 * sizeof(u64));
|
||||
if (!ret && count && pos < (32 * sizeof(u64))) {
|
||||
struct reg_window window;
|
||||
|
||||
if (regwindow64_get(target, regs, &window))
|
||||
return -EFAULT;
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&window,
|
||||
16 * sizeof(u64),
|
||||
32 * sizeof(u64));
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
/* TSTATE, TPC, TNPC */
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
®s->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;
|
||||
membuf_write(&to, regs->u_regs, 16 * sizeof(u64));
|
||||
if (!to.left)
|
||||
return 0;
|
||||
if (regwindow64_get(target, regs, &window))
|
||||
return -EFAULT;
|
||||
membuf_write(&to, &window, 16 * sizeof(u64));
|
||||
/* TSTATE, TPC, TNPC */
|
||||
membuf_write(&to, ®s->tstate, 3 * sizeof(u64));
|
||||
return membuf_store(&to, (u64)regs->y);
|
||||
}
|
||||
|
||||
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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
const unsigned long *fpregs = task_thread_info(target)->fpregs;
|
||||
unsigned long fprs, fsr, gsr;
|
||||
int ret;
|
||||
struct thread_info *t = task_thread_info(target);
|
||||
unsigned long fprs;
|
||||
|
||||
if (target == current)
|
||||
save_and_clear_fpu();
|
||||
|
||||
fprs = task_thread_info(target)->fpsaved[0];
|
||||
fprs = t->fpsaved[0];
|
||||
|
||||
if (fprs & FPRS_DL)
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
fpregs,
|
||||
0, 16 * sizeof(u64));
|
||||
membuf_write(&to, t->fpregs, 16 * sizeof(u64));
|
||||
else
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
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));
|
||||
}
|
||||
membuf_zero(&to, 16 * 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) {
|
||||
fsr = task_thread_info(target)->xfsr[0];
|
||||
gsr = task_thread_info(target)->gsr[0];
|
||||
membuf_store(&to, t->xfsr[0]);
|
||||
membuf_store(&to, t->gsr[0]);
|
||||
} else {
|
||||
fsr = gsr = 0;
|
||||
membuf_zero(&to, 2 * sizeof(u64));
|
||||
}
|
||||
|
||||
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;
|
||||
return membuf_store(&to, fprs);
|
||||
}
|
||||
|
||||
static int fpregs64_set(struct task_struct *target,
|
||||
@ -490,7 +424,7 @@ static const struct user_regset sparc64_regsets[] = {
|
||||
.core_note_type = NT_PRSTATUS,
|
||||
.n = 36,
|
||||
.size = sizeof(u64), .align = sizeof(u64),
|
||||
.get = genregs64_get, .set = genregs64_set
|
||||
.regset_get = genregs64_get, .set = genregs64_set
|
||||
},
|
||||
/* Format is:
|
||||
* F0 --> F63
|
||||
@ -502,10 +436,96 @@ static const struct user_regset sparc64_regsets[] = {
|
||||
.core_note_type = NT_PRFPREG,
|
||||
.n = 35,
|
||||
.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, ®s->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,
|
||||
®s->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 = {
|
||||
.name = "sparc64", .e_machine = EM_SPARCV9,
|
||||
.regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets)
|
||||
@ -514,108 +534,28 @@ static const struct user_regset_view user_sparc64_view = {
|
||||
#ifdef CONFIG_COMPAT
|
||||
static int genregs32_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
const struct pt_regs *regs = task_pt_regs(target);
|
||||
compat_ulong_t __user *reg_window;
|
||||
compat_ulong_t *k = kbuf;
|
||||
compat_ulong_t __user *u = ubuf;
|
||||
compat_ulong_t reg;
|
||||
u32 uregs[16];
|
||||
int i;
|
||||
|
||||
if (target == current)
|
||||
flushw_user();
|
||||
|
||||
pos /= sizeof(reg);
|
||||
count /= sizeof(reg);
|
||||
|
||||
if (kbuf) {
|
||||
for (; count > 0 && pos < 16; count--)
|
||||
*k++ = regs->u_regs[pos++];
|
||||
|
||||
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(*k++, ®_window[pos++]))
|
||||
return -EFAULT;
|
||||
}
|
||||
} else {
|
||||
for (; count > 0 && pos < 32; count--) {
|
||||
if (access_process_vm(target,
|
||||
(unsigned long)
|
||||
®_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, ®_window[pos++]) ||
|
||||
put_user(reg, u++))
|
||||
return -EFAULT;
|
||||
}
|
||||
} else {
|
||||
for (; count > 0 && pos < 32; count--) {
|
||||
if (access_process_vm(target,
|
||||
(unsigned long)
|
||||
®_window[pos++],
|
||||
®, 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);
|
||||
for (i = 0; i < 16; i++)
|
||||
membuf_store(&to, (u32)regs->u_regs[i]);
|
||||
if (!to.left)
|
||||
return 0;
|
||||
if (get_from_target(target, regs->u_regs[UREG_I6],
|
||||
uregs, sizeof(uregs)))
|
||||
return -EFAULT;
|
||||
membuf_write(&to, uregs, 16 * sizeof(u32));
|
||||
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));
|
||||
return membuf_zero(&to, 2 * sizeof(u32));
|
||||
}
|
||||
|
||||
static int genregs32_set(struct task_struct *target,
|
||||
@ -737,56 +677,24 @@ finish:
|
||||
|
||||
static int fpregs32_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
const unsigned long *fpregs = task_thread_info(target)->fpregs;
|
||||
compat_ulong_t enabled;
|
||||
unsigned long fprs;
|
||||
compat_ulong_t fsr;
|
||||
int ret = 0;
|
||||
struct thread_info *t = task_thread_info(target);
|
||||
bool enabled;
|
||||
|
||||
if (target == current)
|
||||
save_and_clear_fpu();
|
||||
|
||||
fprs = task_thread_info(target)->fpsaved[0];
|
||||
if (fprs & FPRS_FEF) {
|
||||
fsr = task_thread_info(target)->xfsr[0];
|
||||
enabled = 1;
|
||||
} else {
|
||||
fsr = 0;
|
||||
enabled = 0;
|
||||
}
|
||||
enabled = t->fpsaved[0] & FPRS_FEF;
|
||||
|
||||
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)
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
35 * sizeof(u32), -1);
|
||||
|
||||
return ret;
|
||||
membuf_write(&to, t->fpregs, 32 * sizeof(u32));
|
||||
membuf_zero(&to, sizeof(u32));
|
||||
if (enabled)
|
||||
membuf_store(&to, (u32)t->xfsr[0]);
|
||||
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,
|
||||
@ -847,7 +755,7 @@ static const struct user_regset sparc32_regsets[] = {
|
||||
.core_note_type = NT_PRSTATUS,
|
||||
.n = 38,
|
||||
.size = sizeof(u32), .align = sizeof(u32),
|
||||
.get = genregs32_get, .set = genregs32_set
|
||||
.regset_get = genregs32_get, .set = genregs32_set
|
||||
},
|
||||
/* Format is:
|
||||
* F0 --> F31
|
||||
@ -863,10 +771,133 @@ static const struct user_regset sparc32_regsets[] = {
|
||||
.core_note_type = NT_PRFPREG,
|
||||
.n = 99,
|
||||
.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 = {
|
||||
.name = "sparc", .e_machine = EM_SPARC,
|
||||
.regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
|
||||
@ -898,7 +929,6 @@ struct compat_fps {
|
||||
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||
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];
|
||||
struct pt_regs32 __user *pregs;
|
||||
struct compat_fps __user *fps;
|
||||
@ -916,58 +946,31 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||
break;
|
||||
|
||||
case PTRACE_GETREGS:
|
||||
ret = copy_regset_to_user(child, view, REGSET_GENERAL,
|
||||
32 * sizeof(u32),
|
||||
4 * sizeof(u32),
|
||||
&pregs->psr);
|
||||
if (!ret)
|
||||
ret = copy_regset_to_user(child, view, REGSET_GENERAL,
|
||||
1 * sizeof(u32),
|
||||
15 * sizeof(u32),
|
||||
&pregs->u_regs[0]);
|
||||
ret = copy_regset_to_user(child, &ptrace32_view,
|
||||
REGSET_GENERAL, 0,
|
||||
19 * sizeof(u32),
|
||||
pregs);
|
||||
break;
|
||||
|
||||
case PTRACE_SETREGS:
|
||||
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
|
||||
32 * sizeof(u32),
|
||||
4 * sizeof(u32),
|
||||
&pregs->psr);
|
||||
if (!ret)
|
||||
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
|
||||
1 * sizeof(u32),
|
||||
15 * sizeof(u32),
|
||||
&pregs->u_regs[0]);
|
||||
ret = copy_regset_from_user(child, &ptrace32_view,
|
||||
REGSET_GENERAL, 0,
|
||||
19 * sizeof(u32),
|
||||
pregs);
|
||||
break;
|
||||
|
||||
case PTRACE_GETFPREGS:
|
||||
ret = copy_regset_to_user(child, view, REGSET_FP,
|
||||
0 * sizeof(u32),
|
||||
32 * sizeof(u32),
|
||||
&fps->regs[0]);
|
||||
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;
|
||||
}
|
||||
ret = copy_regset_to_user(child, &ptrace32_view,
|
||||
REGSET_FP, 0,
|
||||
68 * sizeof(u32),
|
||||
fps);
|
||||
break;
|
||||
|
||||
case PTRACE_SETFPREGS:
|
||||
ret = copy_regset_from_user(child, view, REGSET_FP,
|
||||
0 * sizeof(u32),
|
||||
32 * sizeof(u32),
|
||||
&fps->regs[0]);
|
||||
if (!ret)
|
||||
ret = copy_regset_from_user(child, view, REGSET_FP,
|
||||
33 * sizeof(u32),
|
||||
1 * sizeof(u32),
|
||||
&fps->fsr);
|
||||
ret = copy_regset_from_user(child, &ptrace32_view,
|
||||
REGSET_FP, 0,
|
||||
33 * sizeof(u32),
|
||||
fps);
|
||||
break;
|
||||
|
||||
case PTRACE_READTEXT:
|
||||
@ -1026,31 +1029,17 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||
break;
|
||||
|
||||
case PTRACE_GETREGS64:
|
||||
ret = copy_regset_to_user(child, view, REGSET_GENERAL,
|
||||
1 * sizeof(u64),
|
||||
15 * sizeof(u64),
|
||||
&pregs->u_regs[0]);
|
||||
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);
|
||||
}
|
||||
ret = copy_regset_to_user(child, &ptrace64_view,
|
||||
REGSET_GENERAL, 0,
|
||||
19 * sizeof(u64),
|
||||
pregs);
|
||||
break;
|
||||
|
||||
case PTRACE_SETREGS64:
|
||||
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
|
||||
1 * sizeof(u64),
|
||||
15 * sizeof(u64),
|
||||
&pregs->u_regs[0]);
|
||||
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);
|
||||
}
|
||||
ret = copy_regset_from_user(child, &ptrace64_view,
|
||||
REGSET_GENERAL, 0,
|
||||
19 * sizeof(u64),
|
||||
pregs);
|
||||
break;
|
||||
|
||||
case PTRACE_GETFPREGS64:
|
||||
|
@ -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_all(struct fpu *fpu);
|
||||
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:
|
||||
|
@ -8,8 +8,8 @@
|
||||
#include <linux/regset.h>
|
||||
|
||||
extern user_regset_active_fn regset_fpregs_active, regset_xregset_fpregs_active;
|
||||
extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get,
|
||||
xstateregs_get;
|
||||
extern user_regset_get2_fn fpregs_get, xfpregs_get, fpregs_soft_get,
|
||||
xstateregs_get;
|
||||
extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
|
||||
xstateregs_set;
|
||||
|
||||
|
@ -104,8 +104,8 @@ void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr);
|
||||
const void *get_xsave_field_ptr(int xfeature_nr);
|
||||
int using_compacted_format(void);
|
||||
int xfeature_size(int xfeature_nr);
|
||||
int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int offset, unsigned int size);
|
||||
int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned int offset, unsigned int size);
|
||||
struct membuf;
|
||||
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_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf);
|
||||
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
|
||||
}
|
||||
|
||||
int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
struct fpu *fpu = &target->thread.fpu;
|
||||
|
||||
@ -38,8 +37,7 @@ int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
|
||||
fpu__prepare_read(fpu);
|
||||
fpstate_sanitize_xstate(fpu);
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&fpu->state.fxsave, 0, -1);
|
||||
return membuf_write(&to, &fpu->state.fxsave, sizeof(struct fxregs_state));
|
||||
}
|
||||
|
||||
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,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
struct fpu *fpu = &target->thread.fpu;
|
||||
struct xregs_state *xsave;
|
||||
int ret;
|
||||
|
||||
if (!boot_cpu_has(X86_FEATURE_XSAVE))
|
||||
return -ENODEV;
|
||||
@ -89,10 +85,8 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
|
||||
fpu__prepare_read(fpu);
|
||||
|
||||
if (using_compacted_format()) {
|
||||
if (kbuf)
|
||||
ret = copy_xstate_to_kernel(kbuf, xsave, pos, count);
|
||||
else
|
||||
ret = copy_xstate_to_user(ubuf, xsave, pos, count);
|
||||
copy_xstate_to_kernel(to, xsave);
|
||||
return 0;
|
||||
} else {
|
||||
fpstate_sanitize_xstate(fpu);
|
||||
/*
|
||||
@ -105,9 +99,8 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
|
||||
/*
|
||||
* 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,
|
||||
@ -293,8 +286,7 @@ void convert_to_fxsr(struct fxregs_state *fxsave,
|
||||
}
|
||||
|
||||
int fpregs_get(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
struct fpu *fpu = &target->thread.fpu;
|
||||
struct user_i387_ia32_struct env;
|
||||
@ -302,23 +294,22 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset,
|
||||
fpu__prepare_read(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))
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&fpu->state.fsave, 0,
|
||||
-1);
|
||||
if (!boot_cpu_has(X86_FEATURE_FXSR)) {
|
||||
return membuf_write(&to, &fpu->state.fsave,
|
||||
sizeof(struct fregs_state));
|
||||
}
|
||||
|
||||
fpstate_sanitize_xstate(fpu);
|
||||
|
||||
if (kbuf && pos == 0 && count == sizeof(env)) {
|
||||
convert_from_fxsr(kbuf, target);
|
||||
if (to.left == sizeof(env)) {
|
||||
convert_from_fxsr(to.p, target);
|
||||
return 0;
|
||||
}
|
||||
|
||||
convert_from_fxsr(&env, target);
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &env, 0, -1);
|
||||
return membuf_write(&to, &env, sizeof(env));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
|
@ -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) ||
|
||||
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))
|
||||
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:
|
||||
/*
|
||||
* 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)
|
||||
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) {
|
||||
unsigned size = to - *pos;
|
||||
|
||||
if (size > *count)
|
||||
size = *count;
|
||||
memcpy(*kbuf, (void *)&init_fpstate.xsave + *pos, size);
|
||||
*kbuf += size;
|
||||
*pos += size;
|
||||
*count -= size;
|
||||
}
|
||||
if (*last >= offset)
|
||||
return;
|
||||
membuf_write(to, (void *)&init_fpstate.xsave + *last, offset - *last);
|
||||
*last = offset;
|
||||
}
|
||||
|
||||
static void copy_part(unsigned offset, unsigned size, void *from,
|
||||
void **kbuf, unsigned *pos, unsigned *count)
|
||||
static void copy_part(struct membuf *to, unsigned *last, unsigned offset,
|
||||
unsigned size, void *from)
|
||||
{
|
||||
fill_gap(offset, kbuf, pos, count);
|
||||
if (size > *count)
|
||||
size = *count;
|
||||
if (size) {
|
||||
memcpy(*kbuf, from, size);
|
||||
*kbuf += size;
|
||||
*pos += size;
|
||||
*count -= size;
|
||||
}
|
||||
fill_gap(to, last, offset);
|
||||
membuf_write(to, from, size);
|
||||
*last = offset + size;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -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
|
||||
* 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;
|
||||
const unsigned off_mxcsr = offsetof(struct fxregs_state, mxcsr);
|
||||
unsigned count = size_total;
|
||||
unsigned size = to.left;
|
||||
unsigned last = 0;
|
||||
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:
|
||||
*/
|
||||
@ -1070,27 +1053,26 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of
|
||||
header.xfeatures &= xfeatures_mask_user();
|
||||
|
||||
if (header.xfeatures & XFEATURE_MASK_FP)
|
||||
copy_part(0, off_mxcsr,
|
||||
&xsave->i387, &kbuf, &offset_start, &count);
|
||||
copy_part(&to, &last, 0, off_mxcsr, &xsave->i387);
|
||||
if (header.xfeatures & (XFEATURE_MASK_SSE | XFEATURE_MASK_YMM))
|
||||
copy_part(off_mxcsr, MXCSR_AND_FLAGS_SIZE,
|
||||
&xsave->i387.mxcsr, &kbuf, &offset_start, &count);
|
||||
copy_part(&to, &last, off_mxcsr,
|
||||
MXCSR_AND_FLAGS_SIZE, &xsave->i387.mxcsr);
|
||||
if (header.xfeatures & XFEATURE_MASK_FP)
|
||||
copy_part(offsetof(struct fxregs_state, st_space), 128,
|
||||
&xsave->i387.st_space, &kbuf, &offset_start, &count);
|
||||
copy_part(&to, &last, offsetof(struct fxregs_state, st_space),
|
||||
128, &xsave->i387.st_space);
|
||||
if (header.xfeatures & XFEATURE_MASK_SSE)
|
||||
copy_part(xstate_offsets[XFEATURE_SSE], 256,
|
||||
&xsave->i387.xmm_space, &kbuf, &offset_start, &count);
|
||||
copy_part(&to, &last, xstate_offsets[XFEATURE_SSE],
|
||||
256, &xsave->i387.xmm_space);
|
||||
/*
|
||||
* Fill xsave->i387.sw_reserved value for ptrace frame:
|
||||
*/
|
||||
copy_part(offsetof(struct fxregs_state, sw_reserved), 48,
|
||||
xstate_fx_sw_bytes, &kbuf, &offset_start, &count);
|
||||
copy_part(&to, &last, offsetof(struct fxregs_state, sw_reserved),
|
||||
48, xstate_fx_sw_bytes);
|
||||
/*
|
||||
* Copy xregs_state->header:
|
||||
*/
|
||||
copy_part(offsetof(struct xregs_state, header), sizeof(header),
|
||||
&header, &kbuf, &offset_start, &count);
|
||||
copy_part(&to, &last, offsetof(struct xregs_state, header),
|
||||
sizeof(header), &header);
|
||||
|
||||
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
|
||||
if ((header.xfeatures >> i) & 1) {
|
||||
void *src = __raw_xsave_addr(xsave, i);
|
||||
|
||||
copy_part(xstate_offsets[i], xstate_sizes[i],
|
||||
src, &kbuf, &offset_start, &count);
|
||||
copy_part(&to, &last, xstate_offsets[i],
|
||||
xstate_sizes[i], src);
|
||||
}
|
||||
|
||||
}
|
||||
fill_gap(size_total, &kbuf, &offset_start, &count);
|
||||
|
||||
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;
|
||||
fill_gap(&to, &last, size);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -412,26 +412,12 @@ static unsigned long getreg(struct task_struct *task, unsigned long offset)
|
||||
|
||||
static int genregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
if (kbuf) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
int reg;
|
||||
|
||||
for (reg = 0; to.left; reg++)
|
||||
membuf_store(&to, getreg(target, reg * sizeof(unsigned long)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -695,16 +681,14 @@ static int ioperm_active(struct task_struct *target,
|
||||
|
||||
static int ioperm_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
struct io_bitmap *iobm = target->thread.io_bitmap;
|
||||
|
||||
if (!iobm)
|
||||
return -ENXIO;
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
iobm->bitmap, 0, IO_BITMAP_BYTES);
|
||||
return membuf_write(&to, iobm->bitmap, IO_BITMAP_BYTES);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1007,28 +991,15 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
|
||||
|
||||
static int genregs32_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
if (kbuf) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
int reg;
|
||||
|
||||
for (reg = 0; to.left; reg++) {
|
||||
u32 val;
|
||||
getreg32(target, reg * 4, &val);
|
||||
membuf_store(&to, val);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1238,25 +1209,25 @@ static struct user_regset x86_64_regsets[] __ro_after_init = {
|
||||
.core_note_type = NT_PRSTATUS,
|
||||
.n = sizeof(struct user_regs_struct) / sizeof(long),
|
||||
.size = sizeof(long), .align = sizeof(long),
|
||||
.get = genregs_get, .set = genregs_set
|
||||
.regset_get = genregs_get, .set = genregs_set
|
||||
},
|
||||
[REGSET_FP] = {
|
||||
.core_note_type = NT_PRFPREG,
|
||||
.n = sizeof(struct user_i387_struct) / 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] = {
|
||||
.core_note_type = NT_X86_XSTATE,
|
||||
.size = sizeof(u64), .align = sizeof(u64),
|
||||
.active = xstateregs_active, .get = xstateregs_get,
|
||||
.active = xstateregs_active, .regset_get = xstateregs_get,
|
||||
.set = xstateregs_set
|
||||
},
|
||||
[REGSET_IOPERM64] = {
|
||||
.core_note_type = NT_386_IOPERM,
|
||||
.n = IO_BITMAP_LONGS,
|
||||
.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 = {
|
||||
.core_note_type = NT_PRSTATUS,
|
||||
.n = sizeof(struct user_regs_struct32) / sizeof(u32),
|
||||
.size = sizeof(u32), .align = sizeof(u32),
|
||||
.get = genregs32_get, .set = genregs32_set
|
||||
.regset_get = genregs32_get, .set = genregs32_set
|
||||
},
|
||||
[REGSET_FP] = {
|
||||
.core_note_type = NT_PRFPREG,
|
||||
.n = sizeof(struct user_i387_ia32_struct) / 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] = {
|
||||
.core_note_type = NT_PRXFPREG,
|
||||
.n = sizeof(struct user32_fxsr_struct) / 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] = {
|
||||
.core_note_type = NT_X86_XSTATE,
|
||||
.size = sizeof(u64), .align = sizeof(u64),
|
||||
.active = xstateregs_active, .get = xstateregs_get,
|
||||
.active = xstateregs_active, .regset_get = xstateregs_get,
|
||||
.set = xstateregs_set
|
||||
},
|
||||
[REGSET_TLS] = {
|
||||
@ -1305,13 +1276,13 @@ static struct user_regset x86_32_regsets[] __ro_after_init = {
|
||||
.size = sizeof(struct user_desc),
|
||||
.align = sizeof(struct user_desc),
|
||||
.active = regset_tls_active,
|
||||
.get = regset_tls_get, .set = regset_tls_set
|
||||
.regset_get = regset_tls_get, .set = regset_tls_set
|
||||
},
|
||||
[REGSET_IOPERM32] = {
|
||||
.core_note_type = NT_386_IOPERM,
|
||||
.n = IO_BITMAP_BYTES / 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,
|
||||
}
|
||||
|
||||
int regset_tls_get(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
const struct desc_struct *tls;
|
||||
struct user_desc v;
|
||||
int pos;
|
||||
|
||||
if (pos >= GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) ||
|
||||
(pos % sizeof(struct user_desc)) != 0 ||
|
||||
(count % sizeof(struct user_desc)) != 0)
|
||||
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;
|
||||
}
|
||||
for (pos = 0, tls = target->thread.tls_array; to.left; pos++, tls++) {
|
||||
fill_user_desc(&v, GDT_ENTRY_TLS_MIN + pos, tls);
|
||||
membuf_write(&to, &v, sizeof(v));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include <linux/regset.h>
|
||||
|
||||
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;
|
||||
|
||||
#endif /* _ARCH_X86_KERNEL_TLS_H */
|
||||
|
@ -689,12 +689,10 @@ int fpregs_soft_set(struct task_struct *target,
|
||||
|
||||
int fpregs_soft_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
struct swregs_state *s387 = &target->thread.fpu.state.soft;
|
||||
const void *space = s387->st_space;
|
||||
int ret;
|
||||
int offset = (S387->ftop & 7) * 10, other = 80 - offset;
|
||||
|
||||
RE_ENTRANT_CHECK_OFF;
|
||||
@ -709,18 +707,11 @@ int fpregs_soft_get(struct task_struct *target,
|
||||
S387->fos |= 0xffff0000;
|
||||
#endif /* PECULIAR_486 */
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, s387, 0,
|
||||
offsetof(struct swregs_state, st_space));
|
||||
|
||||
/* 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);
|
||||
membuf_write(&to, s387, offsetof(struct swregs_state, st_space));
|
||||
membuf_write(&to, space + offset, other);
|
||||
membuf_write(&to, space, offset);
|
||||
|
||||
RE_ENTRANT_CHECK_ON;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
@ -39,8 +39,7 @@
|
||||
|
||||
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)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
struct user_pt_regs newregs = {
|
||||
@ -63,8 +62,7 @@ static int gpr_get(struct task_struct *target,
|
||||
regs->areg,
|
||||
(WSBITS - regs->windowbase) * 16);
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&newregs, 0, -1);
|
||||
return membuf_write(&to, &newregs, sizeof(newregs));
|
||||
}
|
||||
|
||||
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,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
struct membuf to)
|
||||
{
|
||||
int ret;
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
@ -147,8 +144,7 @@ static int tie_get(struct task_struct *target,
|
||||
newregs->cp6 = ti->xtregs_cp.cp6;
|
||||
newregs->cp7 = ti->xtregs_cp.cp7;
|
||||
#endif
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
newregs, 0, -1);
|
||||
ret = membuf_write(&to, newregs, sizeof(*newregs));
|
||||
kfree(newregs);
|
||||
return ret;
|
||||
}
|
||||
@ -203,7 +199,7 @@ static const struct user_regset xtensa_regsets[] = {
|
||||
.n = sizeof(struct user_pt_regs) / sizeof(u32),
|
||||
.size = sizeof(u32),
|
||||
.align = sizeof(u32),
|
||||
.get = gpr_get,
|
||||
.regset_get = gpr_get,
|
||||
.set = gpr_set,
|
||||
},
|
||||
[REGSET_TIE] = {
|
||||
@ -211,7 +207,7 @@ static const struct user_regset xtensa_regsets[] = {
|
||||
.n = sizeof(elf_xtregs_t) / sizeof(u32),
|
||||
.size = sizeof(u32),
|
||||
.align = sizeof(u32),
|
||||
.get = tie_get,
|
||||
.regset_get = tie_get,
|
||||
.set = tie_set,
|
||||
},
|
||||
};
|
||||
|
@ -1821,7 +1821,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
|
||||
long signr, size_t *total)
|
||||
{
|
||||
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
|
||||
@ -1830,8 +1830,10 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
|
||||
* We assume that regset 0 is NT_PRSTATUS.
|
||||
*/
|
||||
fill_prstatus(&t->prstatus, t->task, signr);
|
||||
(void) view->regsets[0].get(t->task, &view->regsets[0], 0, regset0_size,
|
||||
&t->prstatus.pr_reg, NULL);
|
||||
regset0_size = regset_get(t->task, &view->regsets[0],
|
||||
sizeof(t->prstatus.pr_reg), &t->prstatus.pr_reg);
|
||||
if (regset0_size < 0)
|
||||
return 0;
|
||||
|
||||
fill_note(&t->notes[0], "CORE", NT_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,
|
||||
*/
|
||||
for (i = 1; i < view->n; ++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);
|
||||
if (regset->core_note_type && regset->get &&
|
||||
(!regset->active || regset->active(t->task, regset) > 0)) {
|
||||
int ret;
|
||||
size_t size = regset_size(t->task, regset);
|
||||
void *data = kzalloc(size, GFP_KERNEL);
|
||||
if (unlikely(!data))
|
||||
return 0;
|
||||
ret = regset->get(t->task, regset,
|
||||
0, size, data, NULL);
|
||||
if (unlikely(ret))
|
||||
kfree(data);
|
||||
else {
|
||||
if (regset->core_note_type != NT_PRFPREG)
|
||||
fill_note(&t->notes[i], "LINUX",
|
||||
regset->core_note_type,
|
||||
size, data);
|
||||
else {
|
||||
SET_PR_FPVALID(&t->prstatus,
|
||||
1, regset0_size);
|
||||
fill_note(&t->notes[i], "CORE",
|
||||
NT_PRFPREG, size, data);
|
||||
}
|
||||
*total += notesize(&t->notes[i]);
|
||||
}
|
||||
}
|
||||
if (!note_type) // not for coredumps
|
||||
continue;
|
||||
if (regset->active && regset->active(t->task, regset) <= 0)
|
||||
continue;
|
||||
|
||||
ret = regset_get_alloc(t->task, regset, ~0U, &data);
|
||||
if (ret < 0)
|
||||
continue;
|
||||
|
||||
if (is_fpreg)
|
||||
SET_PR_FPVALID(&t->prstatus, 1, regset0_size);
|
||||
|
||||
fill_note(&t->notes[i], is_fpreg ? "CORE" : "LINUX",
|
||||
note_type, ret, data);
|
||||
|
||||
*total += notesize(&t->notes[i]);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -17,6 +17,52 @@
|
||||
struct task_struct;
|
||||
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
|
||||
@ -36,26 +82,9 @@ struct user_regset;
|
||||
typedef int user_regset_active_fn(struct task_struct *target,
|
||||
const struct user_regset *regset);
|
||||
|
||||
/**
|
||||
* 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,
|
||||
typedef int user_regset_get2_fn(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf);
|
||||
struct membuf to);
|
||||
|
||||
/**
|
||||
* 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,
|
||||
const struct user_regset *regset,
|
||||
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
|
||||
* @n: Number of slots (registers).
|
||||
@ -136,7 +143,6 @@ typedef unsigned int user_regset_get_size_fn(struct task_struct *target,
|
||||
* @set: Function to store values.
|
||||
* @active: Function to report if regset is active, 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 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,
|
||||
* similar slots, given by @n. Each slot is @size bytes, and aligned to
|
||||
* @align bytes (which is at least @size). For dynamically-sized
|
||||
* regsets, @n must contain the maximum possible number of slots for the
|
||||
* regset, and @get_size must point to a function that returns the
|
||||
* 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.
|
||||
* regset.
|
||||
*
|
||||
* For backward compatibility, the @get and @set methods must pad to, or
|
||||
* 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,
|
||||
* omitted when there is an @active function and it returns zero.
|
||||
*/
|
||||
struct user_regset {
|
||||
user_regset_get_fn *get;
|
||||
user_regset_get2_fn *regset_get;
|
||||
user_regset_set_fn *set;
|
||||
user_regset_active_fn *active;
|
||||
user_regset_writeback_fn *writeback;
|
||||
user_regset_get_size_fn *get_size;
|
||||
unsigned int n;
|
||||
unsigned int size;
|
||||
unsigned int align;
|
||||
@ -238,44 +238,6 @@ struct user_regset_view {
|
||||
*/
|
||||
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,
|
||||
const void **kbuf,
|
||||
const void __user **ubuf, void *data,
|
||||
@ -301,35 +263,6 @@ static inline int user_regset_copyin(unsigned int *pos, unsigned int *count,
|
||||
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,
|
||||
unsigned int *count,
|
||||
const void **kbuf,
|
||||
@ -353,31 +286,19 @@ static inline int user_regset_copyin_ignore(unsigned int *pos,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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];
|
||||
extern int regset_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int size, void *data);
|
||||
|
||||
if (!regset->get)
|
||||
return -EOPNOTSUPP;
|
||||
extern int regset_get_alloc(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int size,
|
||||
void **data);
|
||||
|
||||
if (!access_ok(data, size))
|
||||
return -EFAULT;
|
||||
|
||||
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
|
||||
@ -405,21 +326,4 @@ static inline int copy_regset_from_user(struct task_struct *target,
|
||||
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> */
|
||||
|
@ -10,7 +10,7 @@ obj-y = fork.o exec_domain.o panic.o \
|
||||
extable.o params.o \
|
||||
kthread.o sys_ni.o nsproxy.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_MODULES) += kmod.o
|
||||
|
76
kernel/regset.c
Normal file
76
kernel/regset.c
Normal file
@ -0,0 +1,76 @@
|
||||
// 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user