Commit 1e56f6d2 authored by Al Viro's avatar Al Viro

Merge branches 'regset.x86', 'regset.ia64', 'regset.sparc' and 'regset.arm64' into work.regset

......@@ -1237,6 +1237,22 @@ 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,
......@@ -1255,23 +1271,7 @@ static int compat_gpr_get(struct task_struct *target,
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];
}
compat_ulong_t reg = compat_get_user_reg(target, start + i);
if (kbuf) {
memcpy(kbuf, &reg, sizeof(reg));
......@@ -1541,9 +1541,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 +1553,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 +1562,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;
}
if (!valid_user_regs(&newregs.user_regs, tsk))
return -EINVAL;
return ret;
*task_pt_regs(tsk) = newregs;
return 0;
}
#ifdef CONFIG_HAVE_HW_BREAKPOINT
......
This diff is collapsed.
......@@ -99,15 +99,13 @@ static int genregs32_get(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_copyout(&pos, &count, &kbuf, &ubuf,
uregs,
16 * sizeof(u32), 32 * sizeof(u32));
if (ret || !count)
return ret;
}
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)
return ret;
uregs[0] = regs->psr;
uregs[1] = regs->pc;
......@@ -139,19 +137,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));
......@@ -243,13 +240,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);
......@@ -288,6 +283,125 @@ static const struct user_regset sparc32_regsets[] = {
},
};
static int getregs_get(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
const struct pt_regs *regs = target->thread.kregs;
u32 v[4];
int ret;
if (target == current)
flush_user_windows();
v[0] = regs->psr;
v[1] = regs->pc;
v[2] = regs->npc;
v[3] = regs->y;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
v,
0 * sizeof(u32), 4 * sizeof(u32));
if (ret)
return ret;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
regs->u_regs + 1,
4 * sizeof(u32), 19 * 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,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
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)
return ret;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.fsr,
32 * sizeof(u32), 33 * sizeof(u32));
if (ret)
return ret;
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
33 * sizeof(u32), 68 * 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),
.get = getregs_get, .set = setregs_set,
},
[REGSET_FP] = {
.n = 68, .size = sizeof(u32),
.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 +429,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;
}
......
This diff is collapsed.
......@@ -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:
......
......@@ -356,20 +356,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,14 @@ 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, 0, sizeof(fp), &fp, NULL);
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.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment