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 { ...@@ -1237,6 +1237,22 @@ enum compat_regset {
REGSET_COMPAT_VFP, 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, static int compat_gpr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
...@@ -1255,23 +1271,7 @@ static int compat_gpr_get(struct task_struct *target, ...@@ -1255,23 +1271,7 @@ static int compat_gpr_get(struct task_struct *target,
return -EIO; return -EIO;
for (i = 0; i < num_regs; ++i) { for (i = 0; i < num_regs; ++i) {
unsigned int idx = start + i; compat_ulong_t reg = compat_get_user_reg(target, 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) { if (kbuf) {
memcpy(kbuf, &reg, sizeof(reg)); memcpy(kbuf, &reg, sizeof(reg));
...@@ -1541,9 +1541,7 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off, ...@@ -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) else if (off == COMPAT_PT_TEXT_END_ADDR)
tmp = tsk->mm->end_code; tmp = tsk->mm->end_code;
else if (off < sizeof(compat_elf_gregset_t)) else if (off < sizeof(compat_elf_gregset_t))
return copy_regset_to_user(tsk, &user_aarch32_view, tmp = compat_get_user_reg(tsk, off >> 2);
REGSET_COMPAT_GPR, off,
sizeof(compat_ulong_t), ret);
else if (off >= COMPAT_USER_SZ) else if (off >= COMPAT_USER_SZ)
return -EIO; return -EIO;
else else
...@@ -1555,8 +1553,8 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off, ...@@ -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, static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
compat_ulong_t val) compat_ulong_t val)
{ {
int ret; struct pt_regs newregs = *task_pt_regs(tsk);
mm_segment_t old_fs = get_fs(); unsigned int idx = off / 4;
if (off & 3 || off >= COMPAT_USER_SZ) if (off & 3 || off >= COMPAT_USER_SZ)
return -EIO; return -EIO;
...@@ -1564,14 +1562,25 @@ static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off, ...@@ -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)) if (off >= sizeof(compat_elf_gregset_t))
return 0; return 0;
set_fs(KERNEL_DS); switch (idx) {
ret = copy_regset_from_user(tsk, &user_aarch32_view, case 15:
REGSET_COMPAT_GPR, off, newregs.pc = val;
sizeof(compat_ulong_t), break;
&val); case 16:
set_fs(old_fs); newregs.pstate = compat_psr_to_pstate(val);
break;
case 17:
newregs.orig_x0 = val;
break;
default:
newregs.regs[idx] = val;
}
if (!valid_user_regs(&newregs.user_regs, tsk))
return -EINVAL;
return ret; *task_pt_regs(tsk) = newregs;
return 0;
} }
#ifdef CONFIG_HAVE_HW_BREAKPOINT #ifdef CONFIG_HAVE_HW_BREAKPOINT
......
This diff is collapsed.
...@@ -99,15 +99,13 @@ static int genregs32_get(struct task_struct *target, ...@@ -99,15 +99,13 @@ static int genregs32_get(struct task_struct *target,
if (ret || !count) if (ret || !count)
return ret; return ret;
if (pos < 32 * sizeof(u32)) { if (regwindow32_get(target, regs, uregs))
if (regwindow32_get(target, regs, uregs)) return -EFAULT;
return -EFAULT; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs,
uregs, 16 * sizeof(u32), 32 * sizeof(u32));
16 * sizeof(u32), 32 * sizeof(u32)); if (ret)
if (ret || !count) return ret;
return ret;
}
uregs[0] = regs->psr; uregs[0] = regs->psr;
uregs[1] = regs->pc; uregs[1] = regs->pc;
...@@ -139,19 +137,18 @@ static int genregs32_set(struct task_struct *target, ...@@ -139,19 +137,18 @@ static int genregs32_set(struct task_struct *target,
if (ret || !count) if (ret || !count)
return ret; return ret;
if (pos < 32 * sizeof(u32)) { if (regwindow32_get(target, regs, uregs))
if (regwindow32_get(target, regs, uregs)) return -EFAULT;
return -EFAULT; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs,
uregs, 16 * sizeof(u32), 32 * sizeof(u32));
16 * sizeof(u32), 32 * sizeof(u32)); if (ret)
if (ret) return ret;
return ret; if (regwindow32_set(target, regs, uregs))
if (regwindow32_set(target, regs, uregs)) return -EFAULT;
return -EFAULT; if (!count)
if (!count) return 0;
return 0;
}
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&psr, &psr,
32 * sizeof(u32), 33 * sizeof(u32)); 32 * sizeof(u32), 33 * sizeof(u32));
...@@ -243,13 +240,11 @@ static int fpregs32_set(struct task_struct *target, ...@@ -243,13 +240,11 @@ static int fpregs32_set(struct task_struct *target,
user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
32 * sizeof(u32), 32 * sizeof(u32),
33 * sizeof(u32)); 33 * sizeof(u32));
if (!ret && count > 0) { if (!ret)
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&target->thread.fsr, &target->thread.fsr,
33 * sizeof(u32), 33 * sizeof(u32),
34 * sizeof(u32)); 34 * sizeof(u32));
}
if (!ret) if (!ret)
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
34 * sizeof(u32), -1); 34 * sizeof(u32), -1);
...@@ -288,6 +283,125 @@ static const struct user_regset sparc32_regsets[] = { ...@@ -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 = { static const struct user_regset_view user_sparc32_view = {
.name = "sparc", .e_machine = EM_SPARC, .name = "sparc", .e_machine = EM_SPARC,
.regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets) .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
...@@ -315,74 +429,44 @@ long arch_ptrace(struct task_struct *child, long request, ...@@ -315,74 +429,44 @@ long arch_ptrace(struct task_struct *child, long request,
{ {
unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4]; unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
void __user *addr2p; void __user *addr2p;
const struct user_regset_view *view;
struct pt_regs __user *pregs; struct pt_regs __user *pregs;
struct fps __user *fps; struct fps __user *fps;
int ret; int ret;
view = task_user_regset_view(current);
addr2p = (void __user *) addr2; addr2p = (void __user *) addr2;
pregs = (struct pt_regs __user *) addr; pregs = (struct pt_regs __user *) addr;
fps = (struct fps __user *) addr; fps = (struct fps __user *) addr;
switch(request) { switch(request) {
case PTRACE_GETREGS: { case PTRACE_GETREGS: {
ret = copy_regset_to_user(child, view, REGSET_GENERAL, ret = copy_regset_to_user(child, &ptrace32_view,
32 * sizeof(u32), REGSET_GENERAL, 0,
4 * sizeof(u32), 19 * sizeof(u32),
&pregs->psr); pregs);
if (!ret)
copy_regset_to_user(child, view, REGSET_GENERAL,
1 * sizeof(u32),
15 * sizeof(u32),
&pregs->u_regs[0]);
break; break;
} }
case PTRACE_SETREGS: { case PTRACE_SETREGS: {
ret = copy_regset_from_user(child, view, REGSET_GENERAL, ret = copy_regset_from_user(child, &ptrace32_view,
32 * sizeof(u32), REGSET_GENERAL, 0,
4 * sizeof(u32), 19 * sizeof(u32),
&pregs->psr); pregs);
if (!ret)
copy_regset_from_user(child, view, REGSET_GENERAL,
1 * sizeof(u32),
15 * sizeof(u32),
&pregs->u_regs[0]);
break; break;
} }
case PTRACE_GETFPREGS: { case PTRACE_GETFPREGS: {
ret = copy_regset_to_user(child, view, REGSET_FP, ret = copy_regset_to_user(child, &ptrace32_view,
0 * sizeof(u32), REGSET_FP, 0,
32 * sizeof(u32), 68 * sizeof(u32),
&fps->regs[0]); fps);
if (!ret)
ret = copy_regset_to_user(child, view, REGSET_FP,
33 * sizeof(u32),
1 * sizeof(u32),
&fps->fsr);
if (!ret) {
if (__put_user(0, &fps->fpqd) ||
__put_user(0, &fps->flags) ||
__put_user(0, &fps->extra) ||
clear_user(fps->fpq, sizeof(fps->fpq)))
ret = -EFAULT;
}
break; break;
} }
case PTRACE_SETFPREGS: { case PTRACE_SETFPREGS: {
ret = copy_regset_from_user(child, view, REGSET_FP, ret = copy_regset_from_user(child, &ptrace32_view,
0 * sizeof(u32), REGSET_FP, 0,
32 * sizeof(u32), 33 * sizeof(u32),
&fps->regs[0]); fps);
if (!ret)
ret = copy_regset_from_user(child, view, REGSET_FP,
33 * sizeof(u32),
1 * sizeof(u32),
&fps->fsr);
break; break;
} }
......
This diff is collapsed.
...@@ -34,7 +34,6 @@ extern int fpu__copy(struct task_struct *dst, struct task_struct *src); ...@@ -34,7 +34,6 @@ extern int fpu__copy(struct task_struct *dst, struct task_struct *src);
extern void fpu__clear_user_states(struct fpu *fpu); extern void fpu__clear_user_states(struct fpu *fpu);
extern void fpu__clear_all(struct fpu *fpu); extern void fpu__clear_all(struct fpu *fpu);
extern int fpu__exception_code(struct fpu *fpu, int trap_nr); extern int fpu__exception_code(struct fpu *fpu, int trap_nr);
extern int dump_fpu(struct pt_regs *ptregs, struct user_i387_struct *fpstate);
/* /*
* Boot time FPU initialization functions: * Boot time FPU initialization functions:
......
...@@ -356,20 +356,4 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, ...@@ -356,20 +356,4 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
return ret; return ret;
} }
/*
* FPU state for core dumps.
* This is only used for a.out dumps now.
* It is declared generically using elf_fpregset_t (which is
* struct user_i387_struct) but is in fact only used for 32-bit
* dumps, so on 64-bit it is really struct user_i387_ia32_struct.
*/
int dump_fpu(struct pt_regs *regs, struct user_i387_struct *ufpu)
{
struct task_struct *tsk = current;
return !fpregs_get(tsk, NULL, 0, sizeof(struct user_i387_ia32_struct),
ufpu, NULL);
}
EXPORT_SYMBOL(dump_fpu);
#endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */ #endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
...@@ -170,14 +170,14 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) ...@@ -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) || ia32_fxstate &= (IS_ENABLED(CONFIG_X86_32) ||
IS_ENABLED(CONFIG_IA32_EMULATION)); IS_ENABLED(CONFIG_IA32_EMULATION));
if (!static_cpu_has(X86_FEATURE_FPU)) {
struct user_i387_ia32_struct fp;
fpregs_soft_get(current, NULL, 0, sizeof(fp), &fp, NULL);
return copy_to_user(buf, &fp, sizeof(fp)) ? -EFAULT : 0;
}
if (!access_ok(buf, size)) if (!access_ok(buf, size))
return -EACCES; return -EACCES;
if (!static_cpu_has(X86_FEATURE_FPU))
return fpregs_soft_get(current, NULL, 0,
sizeof(struct user_i387_ia32_struct), NULL,
(struct _fpstate_32 __user *) buf) ? -1 : 1;
retry: retry:
/* /*
* Load the FPU registers if they are not valid for the current task. * Load the FPU registers if they are not valid for the current task.
......
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