Skip to content

Commit 0557d64

Browse files
author
Al Viro
committed
x86: switch to ->regset_get()
All instances of ->get() in arch/x86 switched; that might or might not be worth splitting up. Notes: * for xstateregs_get() the amount we want to store is determined at the boot time; see init_xstate_size() and update_regset_xstate_info() for details. task->thread.fpu.state.xsave ends with a flexible array member and the amount of data in it depends upon the FPU features supported/enabled. * fpregs_get() writes slightly less than full ->thread.fpu.state.fsave (the last word is not copied); we pass the full size of state.fsave and let membuf_write() trim to the amount declared by regset - __regset_get() will make sure that the space in buffer is no more than that. * copy_xstate_to_user() and its helpers are gone now. * fpregs_soft_get() was getting user_regset_copyout() arguments wrong. Since "x86: x86 user_regset math_emu" back in 2008... I really doubt that it's worth splitting out for -stable, though - you need a 486SX box for that to trigger... [Kevin's braino fix for copy_xstate_to_kernel() essentially duplicated here] Signed-off-by: Al Viro <[email protected]>
1 parent 7717cb9 commit 0557d64

File tree

9 files changed

+83
-259
lines changed

9 files changed

+83
-259
lines changed

arch/x86/include/asm/fpu/regset.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
#include <linux/regset.h>
99

1010
extern user_regset_active_fn regset_fpregs_active, regset_xregset_fpregs_active;
11-
extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get,
12-
xstateregs_get;
11+
extern user_regset_get2_fn fpregs_get, xfpregs_get, fpregs_soft_get,
12+
xstateregs_get;
1313
extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
1414
xstateregs_set;
1515

arch/x86/include/asm/fpu/xstate.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ extern void __init update_regset_xstate_info(unsigned int size,
7171
void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr);
7272
const void *get_xsave_field_ptr(int xfeature_nr);
7373
int using_compacted_format(void);
74-
int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int offset, unsigned int size);
75-
int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned int offset, unsigned int size);
74+
struct membuf;
75+
void copy_xstate_to_kernel(struct membuf to, struct xregs_state *xsave);
7676
int copy_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf);
7777
int copy_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf);
7878
void copy_supervisor_to_kernel(struct xregs_state *xsave);

arch/x86/kernel/fpu/regset.c

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ int regset_xregset_fpregs_active(struct task_struct *target, const struct user_r
2727
}
2828

2929
int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
30-
unsigned int pos, unsigned int count,
31-
void *kbuf, void __user *ubuf)
30+
struct membuf to)
3231
{
3332
struct fpu *fpu = &target->thread.fpu;
3433

@@ -38,8 +37,7 @@ int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
3837
fpu__prepare_read(fpu);
3938
fpstate_sanitize_xstate(fpu);
4039

41-
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
42-
&fpu->state.fxsave, 0, -1);
40+
return membuf_write(&to, &fpu->state.fxsave, sizeof(struct fxregs_state));
4341
}
4442

4543
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,
7472
}
7573

7674
int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
77-
unsigned int pos, unsigned int count,
78-
void *kbuf, void __user *ubuf)
75+
struct membuf to)
7976
{
8077
struct fpu *fpu = &target->thread.fpu;
8178
struct xregs_state *xsave;
82-
int ret;
8379

8480
if (!boot_cpu_has(X86_FEATURE_XSAVE))
8581
return -ENODEV;
@@ -89,10 +85,8 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
8985
fpu__prepare_read(fpu);
9086

9187
if (using_compacted_format()) {
92-
if (kbuf)
93-
ret = copy_xstate_to_kernel(kbuf, xsave, pos, count);
94-
else
95-
ret = copy_xstate_to_user(ubuf, xsave, pos, count);
88+
copy_xstate_to_kernel(to, xsave);
89+
return 0;
9690
} else {
9791
fpstate_sanitize_xstate(fpu);
9892
/*
@@ -105,9 +99,8 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
10599
/*
106100
* Copy the xstate memory layout.
107101
*/
108-
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, xsave, 0, -1);
102+
return membuf_write(&to, xsave, fpu_user_xstate_size);
109103
}
110-
return ret;
111104
}
112105

113106
int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
@@ -293,32 +286,30 @@ void convert_to_fxsr(struct fxregs_state *fxsave,
293286
}
294287

295288
int fpregs_get(struct task_struct *target, const struct user_regset *regset,
296-
unsigned int pos, unsigned int count,
297-
void *kbuf, void __user *ubuf)
289+
struct membuf to)
298290
{
299291
struct fpu *fpu = &target->thread.fpu;
300292
struct user_i387_ia32_struct env;
301293

302294
fpu__prepare_read(fpu);
303295

304296
if (!boot_cpu_has(X86_FEATURE_FPU))
305-
return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf);
297+
return fpregs_soft_get(target, regset, to);
306298

307-
if (!boot_cpu_has(X86_FEATURE_FXSR))
308-
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
309-
&fpu->state.fsave, 0,
310-
-1);
299+
if (!boot_cpu_has(X86_FEATURE_FXSR)) {
300+
return membuf_write(&to, &fpu->state.fsave,
301+
sizeof(struct fregs_state));
302+
}
311303

312304
fpstate_sanitize_xstate(fpu);
313305

314-
if (kbuf && pos == 0 && count == sizeof(env)) {
315-
convert_from_fxsr(kbuf, target);
306+
if (to.left == sizeof(env)) {
307+
convert_from_fxsr(to.p, target);
316308
return 0;
317309
}
318310

319311
convert_from_fxsr(&env, target);
320-
321-
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &env, 0, -1);
312+
return membuf_write(&to, &env, sizeof(env));
322313
}
323314

324315
int fpregs_set(struct task_struct *target, const struct user_regset *regset,

arch/x86/kernel/fpu/signal.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
172172

173173
if (!static_cpu_has(X86_FEATURE_FPU)) {
174174
struct user_i387_ia32_struct fp;
175-
fpregs_soft_get(current, NULL, 0, sizeof(fp), &fp, NULL);
175+
fpregs_soft_get(current, NULL, (struct membuf){.p = &fp,
176+
.left = sizeof(fp)});
176177
return copy_to_user(buf, &fp, sizeof(fp)) ? -EFAULT : 0;
177178
}
178179

arch/x86/kernel/fpu/xstate.c

Lines changed: 27 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,32 +1009,20 @@ static inline bool xfeatures_mxcsr_quirk(u64 xfeatures)
10091009
return true;
10101010
}
10111011

1012-
static void fill_gap(unsigned to, void **kbuf, unsigned *pos, unsigned *count)
1012+
static void fill_gap(struct membuf *to, unsigned *last, unsigned offset)
10131013
{
1014-
if (*pos < to) {
1015-
unsigned size = to - *pos;
1016-
1017-
if (size > *count)
1018-
size = *count;
1019-
memcpy(*kbuf, (void *)&init_fpstate.xsave + *pos, size);
1020-
*kbuf += size;
1021-
*pos += size;
1022-
*count -= size;
1023-
}
1014+
if (*last >= offset)
1015+
return;
1016+
membuf_write(to, (void *)&init_fpstate.xsave + *last, offset - *last);
1017+
*last = offset;
10241018
}
10251019

1026-
static void copy_part(unsigned offset, unsigned size, void *from,
1027-
void **kbuf, unsigned *pos, unsigned *count)
1020+
static void copy_part(struct membuf *to, unsigned *last, unsigned offset,
1021+
unsigned size, void *from)
10281022
{
1029-
fill_gap(offset, kbuf, pos, count);
1030-
if (size > *count)
1031-
size = *count;
1032-
if (size) {
1033-
memcpy(*kbuf, from, size);
1034-
*kbuf += size;
1035-
*pos += size;
1036-
*count -= size;
1037-
}
1023+
fill_gap(to, last, offset);
1024+
membuf_write(to, from, size);
1025+
*last = offset + size;
10381026
}
10391027

10401028
/*
@@ -1044,19 +1032,14 @@ static void copy_part(unsigned offset, unsigned size, void *from,
10441032
* It supports partial copy but pos always starts from zero. This is called
10451033
* from xstateregs_get() and there we check the CPU has XSAVES.
10461034
*/
1047-
int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int offset_start, unsigned int size_total)
1035+
void copy_xstate_to_kernel(struct membuf to, struct xregs_state *xsave)
10481036
{
10491037
struct xstate_header header;
10501038
const unsigned off_mxcsr = offsetof(struct fxregs_state, mxcsr);
1051-
unsigned count = size_total;
1039+
unsigned size = to.left;
1040+
unsigned last = 0;
10521041
int i;
10531042

1054-
/*
1055-
* Currently copy_regset_to_user() starts from pos 0:
1056-
*/
1057-
if (unlikely(offset_start != 0))
1058-
return -EFAULT;
1059-
10601043
/*
10611044
* The destination is a ptrace buffer; we put in only user xstates:
10621045
*/
@@ -1065,27 +1048,26 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of
10651048
header.xfeatures &= xfeatures_mask_user();
10661049

10671050
if (header.xfeatures & XFEATURE_MASK_FP)
1068-
copy_part(0, off_mxcsr,
1069-
&xsave->i387, &kbuf, &offset_start, &count);
1051+
copy_part(&to, &last, 0, off_mxcsr, &xsave->i387);
10701052
if (header.xfeatures & (XFEATURE_MASK_SSE | XFEATURE_MASK_YMM))
1071-
copy_part(off_mxcsr, MXCSR_AND_FLAGS_SIZE,
1072-
&xsave->i387.mxcsr, &kbuf, &offset_start, &count);
1053+
copy_part(&to, &last, off_mxcsr,
1054+
MXCSR_AND_FLAGS_SIZE, &xsave->i387.mxcsr);
10731055
if (header.xfeatures & XFEATURE_MASK_FP)
1074-
copy_part(offsetof(struct fxregs_state, st_space), 128,
1075-
&xsave->i387.st_space, &kbuf, &offset_start, &count);
1056+
copy_part(&to, &last, offsetof(struct fxregs_state, st_space),
1057+
128, &xsave->i387.st_space);
10761058
if (header.xfeatures & XFEATURE_MASK_SSE)
1077-
copy_part(xstate_offsets[XFEATURE_MASK_SSE], 256,
1078-
&xsave->i387.xmm_space, &kbuf, &offset_start, &count);
1059+
copy_part(&to, &last, xstate_offsets[XFEATURE_SSE],
1060+
256, &xsave->i387.xmm_space);
10791061
/*
10801062
* Fill xsave->i387.sw_reserved value for ptrace frame:
10811063
*/
1082-
copy_part(offsetof(struct fxregs_state, sw_reserved), 48,
1083-
xstate_fx_sw_bytes, &kbuf, &offset_start, &count);
1064+
copy_part(&to, &last, offsetof(struct fxregs_state, sw_reserved),
1065+
48, xstate_fx_sw_bytes);
10841066
/*
10851067
* Copy xregs_state->header:
10861068
*/
1087-
copy_part(offsetof(struct xregs_state, header), sizeof(header),
1088-
&header, &kbuf, &offset_start, &count);
1069+
copy_part(&to, &last, offsetof(struct xregs_state, header),
1070+
sizeof(header), &header);
10891071

10901072
for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) {
10911073
/*
@@ -1094,104 +1076,12 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of
10941076
if ((header.xfeatures >> i) & 1) {
10951077
void *src = __raw_xsave_addr(xsave, i);
10961078

1097-
copy_part(xstate_offsets[i], xstate_sizes[i],
1098-
src, &kbuf, &offset_start, &count);
1079+
copy_part(&to, &last, xstate_offsets[i],
1080+
xstate_sizes[i], src);
10991081
}
11001082

11011083
}
1102-
fill_gap(size_total, &kbuf, &offset_start, &count);
1103-
1104-
return 0;
1105-
}
1106-
1107-
static inline int
1108-
__copy_xstate_to_user(void __user *ubuf, const void *data, unsigned int offset, unsigned int size, unsigned int size_total)
1109-
{
1110-
if (!size)
1111-
return 0;
1112-
1113-
if (offset < size_total) {
1114-
unsigned int copy = min(size, size_total - offset);
1115-
1116-
if (__copy_to_user(ubuf + offset, data, copy))
1117-
return -EFAULT;
1118-
}
1119-
return 0;
1120-
}
1121-
1122-
/*
1123-
* Convert from kernel XSAVES compacted format to standard format and copy
1124-
* to a user-space buffer. It supports partial copy but pos always starts from
1125-
* zero. This is called from xstateregs_get() and there we check the CPU
1126-
* has XSAVES.
1127-
*/
1128-
int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned int offset_start, unsigned int size_total)
1129-
{
1130-
unsigned int offset, size;
1131-
int ret, i;
1132-
struct xstate_header header;
1133-
1134-
/*
1135-
* Currently copy_regset_to_user() starts from pos 0:
1136-
*/
1137-
if (unlikely(offset_start != 0))
1138-
return -EFAULT;
1139-
1140-
/*
1141-
* The destination is a ptrace buffer; we put in only user xstates:
1142-
*/
1143-
memset(&header, 0, sizeof(header));
1144-
header.xfeatures = xsave->header.xfeatures;
1145-
header.xfeatures &= xfeatures_mask_user();
1146-
1147-
/*
1148-
* Copy xregs_state->header:
1149-
*/
1150-
offset = offsetof(struct xregs_state, header);
1151-
size = sizeof(header);
1152-
1153-
ret = __copy_xstate_to_user(ubuf, &header, offset, size, size_total);
1154-
if (ret)
1155-
return ret;
1156-
1157-
for (i = 0; i < XFEATURE_MAX; i++) {
1158-
/*
1159-
* Copy only in-use xstates:
1160-
*/
1161-
if ((header.xfeatures >> i) & 1) {
1162-
void *src = __raw_xsave_addr(xsave, i);
1163-
1164-
offset = xstate_offsets[i];
1165-
size = xstate_sizes[i];
1166-
1167-
/* The next component has to fit fully into the output buffer: */
1168-
if (offset + size > size_total)
1169-
break;
1170-
1171-
ret = __copy_xstate_to_user(ubuf, src, offset, size, size_total);
1172-
if (ret)
1173-
return ret;
1174-
}
1175-
1176-
}
1177-
1178-
if (xfeatures_mxcsr_quirk(header.xfeatures)) {
1179-
offset = offsetof(struct fxregs_state, mxcsr);
1180-
size = MXCSR_AND_FLAGS_SIZE;
1181-
__copy_xstate_to_user(ubuf, &xsave->i387.mxcsr, offset, size, size_total);
1182-
}
1183-
1184-
/*
1185-
* Fill xsave->i387.sw_reserved value for ptrace frame:
1186-
*/
1187-
offset = offsetof(struct fxregs_state, sw_reserved);
1188-
size = sizeof(xstate_fx_sw_bytes);
1189-
1190-
ret = __copy_xstate_to_user(ubuf, xstate_fx_sw_bytes, offset, size, size_total);
1191-
if (ret)
1192-
return ret;
1193-
1194-
return 0;
1084+
fill_gap(&to, &last, size);
11951085
}
11961086

11971087
/*

0 commit comments

Comments
 (0)