Skip to content

Commit b7e46c5

Browse files
author
Al Viro
committed
sparc64: get rid of odd callers of copy_regset_from_user()
Signed-off-by: Al Viro <[email protected]>
1 parent 98a7fbf commit b7e46c5

File tree

1 file changed

+144
-33
lines changed

1 file changed

+144
-33
lines changed

arch/sparc/kernel/ptrace_64.c

Lines changed: 144 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,60 @@ static int getregs64_get(struct task_struct *target,
541541
return ret;
542542
}
543543

544+
static int setregs64_set(struct task_struct *target,
545+
const struct user_regset *regset,
546+
unsigned int pos, unsigned int count,
547+
const void *kbuf, const void __user *ubuf)
548+
{
549+
struct pt_regs *regs = task_pt_regs(target);
550+
unsigned long y = regs->y;
551+
unsigned long tstate;
552+
int ret;
553+
554+
if (target == current)
555+
flushw_user();
556+
557+
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
558+
regs->u_regs + 1,
559+
0 * sizeof(u64),
560+
15 * sizeof(u64));
561+
if (ret)
562+
return ret;
563+
ret =user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
564+
15 * sizeof(u64), 16 * sizeof(u64));
565+
if (ret)
566+
return ret;
567+
/* TSTATE */
568+
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
569+
&tstate,
570+
16 * sizeof(u64),
571+
17 * sizeof(u64));
572+
if (ret)
573+
return ret;
574+
/* Only the condition codes and the "in syscall"
575+
* state can be modified in the %tstate register.
576+
*/
577+
tstate &= (TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
578+
regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
579+
regs->tstate |= tstate;
580+
581+
/* TPC, TNPC */
582+
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
583+
&regs->tpc,
584+
17 * sizeof(u64),
585+
19 * sizeof(u64));
586+
if (ret)
587+
return ret;
588+
/* Y */
589+
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
590+
&y,
591+
19 * sizeof(u64),
592+
20 * sizeof(u64));
593+
if (!ret)
594+
regs->y = y;
595+
return ret;
596+
}
597+
544598
static const struct user_regset ptrace64_regsets[] = {
545599
/* Format is:
546600
* G1 --> G7
@@ -549,7 +603,8 @@ static const struct user_regset ptrace64_regsets[] = {
549603
* TSTATE, TPC, TNPC, Y
550604
*/
551605
[REGSET_GENERAL] = {
552-
.n = 20, .size = sizeof(u64), .get = getregs64_get,
606+
.n = 20, .size = sizeof(u64),
607+
.get = getregs64_get, .set = setregs64_set,
553608
},
554609
};
555610

@@ -914,6 +969,40 @@ static int getregs_get(struct task_struct *target,
914969
0, 19 * sizeof(u32));
915970
}
916971

972+
static int setregs_set(struct task_struct *target,
973+
const struct user_regset *regset,
974+
unsigned int pos, unsigned int count,
975+
const void *kbuf, const void __user *ubuf)
976+
{
977+
struct pt_regs *regs = task_pt_regs(target);
978+
unsigned long tstate;
979+
u32 uregs[19];
980+
int i, ret;
981+
982+
if (target == current)
983+
flushw_user();
984+
985+
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
986+
uregs,
987+
0, 19 * sizeof(u32));
988+
if (ret)
989+
return ret;
990+
991+
tstate = regs->tstate;
992+
tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
993+
tstate |= psr_to_tstate_icc(uregs[0]);
994+
if (uregs[0] & PSR_SYSCALL)
995+
tstate |= TSTATE_SYSCALL;
996+
regs->tstate = tstate;
997+
regs->tpc = uregs[1];
998+
regs->tnpc = uregs[2];
999+
regs->y = uregs[3];
1000+
1001+
for (i = 1; i < 15; i++)
1002+
regs->u_regs[i] = uregs[3 + i];
1003+
return 0;
1004+
}
1005+
9171006
static int getfpregs_get(struct task_struct *target,
9181007
const struct user_regset *regset,
9191008
unsigned int pos, unsigned int count,
@@ -948,12 +1037,52 @@ static int getfpregs_get(struct task_struct *target,
9481037
return ret;
9491038
}
9501039

1040+
static int setfpregs_set(struct task_struct *target,
1041+
const struct user_regset *regset,
1042+
unsigned int pos, unsigned int count,
1043+
const void *kbuf, const void __user *ubuf)
1044+
{
1045+
unsigned long *fpregs = task_thread_info(target)->fpregs;
1046+
unsigned long fprs;
1047+
int ret;
1048+
1049+
if (target == current)
1050+
save_and_clear_fpu();
1051+
1052+
fprs = task_thread_info(target)->fpsaved[0];
1053+
1054+
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
1055+
fpregs,
1056+
0, 32 * sizeof(u32));
1057+
if (!ret) {
1058+
compat_ulong_t fsr;
1059+
unsigned long val;
1060+
1061+
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
1062+
&fsr,
1063+
32 * sizeof(u32),
1064+
33 * sizeof(u32));
1065+
if (!ret) {
1066+
val = task_thread_info(target)->xfsr[0];
1067+
val &= 0xffffffff00000000UL;
1068+
val |= fsr;
1069+
task_thread_info(target)->xfsr[0] = val;
1070+
}
1071+
}
1072+
1073+
fprs |= (FPRS_FEF | FPRS_DL);
1074+
task_thread_info(target)->fpsaved[0] = fprs;
1075+
return ret;
1076+
}
1077+
9511078
static const struct user_regset ptrace32_regsets[] = {
9521079
[REGSET_GENERAL] = {
953-
.n = 19, .size = sizeof(u32), .get = getregs_get,
1080+
.n = 19, .size = sizeof(u32),
1081+
.get = getregs_get, .set = setregs_set,
9541082
},
9551083
[REGSET_FP] = {
956-
.n = 68, .size = sizeof(u32), .get = getfpregs_get,
1084+
.n = 68, .size = sizeof(u32),
1085+
.get = getfpregs_get, .set = setfpregs_set,
9571086
},
9581087
};
9591088

@@ -992,7 +1121,6 @@ struct compat_fps {
9921121
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
9931122
compat_ulong_t caddr, compat_ulong_t cdata)
9941123
{
995-
const struct user_regset_view *view = task_user_regset_view(current);
9961124
compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4];
9971125
struct pt_regs32 __user *pregs;
9981126
struct compat_fps __user *fps;
@@ -1017,15 +1145,10 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
10171145
break;
10181146

10191147
case PTRACE_SETREGS:
1020-
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
1021-
32 * sizeof(u32),
1022-
4 * sizeof(u32),
1023-
&pregs->psr);
1024-
if (!ret)
1025-
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
1026-
1 * sizeof(u32),
1027-
15 * sizeof(u32),
1028-
&pregs->u_regs[0]);
1148+
ret = copy_regset_from_user(child, &ptrace32_view,
1149+
REGSET_GENERAL, 0,
1150+
19 * sizeof(u32),
1151+
pregs);
10291152
break;
10301153

10311154
case PTRACE_GETFPREGS:
@@ -1036,15 +1159,10 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
10361159
break;
10371160

10381161
case PTRACE_SETFPREGS:
1039-
ret = copy_regset_from_user(child, view, REGSET_FP,
1040-
0 * sizeof(u32),
1041-
32 * sizeof(u32),
1042-
&fps->regs[0]);
1043-
if (!ret)
1044-
ret = copy_regset_from_user(child, view, REGSET_FP,
1045-
33 * sizeof(u32),
1046-
1 * sizeof(u32),
1047-
&fps->fsr);
1162+
ret = copy_regset_from_user(child, &ptrace32_view,
1163+
REGSET_FP, 0,
1164+
33 * sizeof(u32),
1165+
fps);
10481166
break;
10491167

10501168
case PTRACE_READTEXT:
@@ -1110,17 +1228,10 @@ long arch_ptrace(struct task_struct *child, long request,
11101228
break;
11111229

11121230
case PTRACE_SETREGS64:
1113-
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
1114-
1 * sizeof(u64),
1115-
15 * sizeof(u64),
1116-
&pregs->u_regs[0]);
1117-
if (!ret) {
1118-
/* XXX doesn't handle 'y' register correctly XXX */
1119-
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
1120-
32 * sizeof(u64),
1121-
4 * sizeof(u64),
1122-
&pregs->tstate);
1123-
}
1231+
ret = copy_regset_from_user(child, &ptrace64_view,
1232+
REGSET_GENERAL, 0,
1233+
19 * sizeof(u64),
1234+
pregs);
11241235
break;
11251236

11261237
case PTRACE_GETFPREGS64:

0 commit comments

Comments
 (0)