+48
-38
arch/x86/kernel/fpu/xstate.c
+48
-38
arch/x86/kernel/fpu/xstate.c
···
957
957
return true;
958
958
}
959
959
960
-
/*
961
-
* This is similar to user_regset_copyout(), but will not add offset to
962
-
* the source data pointer or increment pos, count, kbuf, and ubuf.
963
-
*/
964
-
static inline void
965
-
__copy_xstate_to_kernel(void *kbuf, const void *data,
966
-
unsigned int offset, unsigned int size, unsigned int size_total)
960
+
static void fill_gap(unsigned to, void **kbuf, unsigned *pos, unsigned *count)
967
961
{
968
-
if (offset < size_total) {
969
-
unsigned int copy = min(size, size_total - offset);
962
+
if (*pos < to) {
963
+
unsigned size = to - *pos;
970
964
971
-
memcpy(kbuf + offset, data, copy);
965
+
if (size > *count)
966
+
size = *count;
967
+
memcpy(*kbuf, (void *)&init_fpstate.xsave + *pos, size);
968
+
*kbuf += size;
969
+
*pos += size;
970
+
*count -= size;
971
+
}
972
+
}
973
+
974
+
static void copy_part(unsigned offset, unsigned size, void *from,
975
+
void **kbuf, unsigned *pos, unsigned *count)
976
+
{
977
+
fill_gap(offset, kbuf, pos, count);
978
+
if (size > *count)
979
+
size = *count;
980
+
if (size) {
981
+
memcpy(*kbuf, from, size);
982
+
*kbuf += size;
983
+
*pos += size;
984
+
*count -= size;
972
985
}
973
986
}
974
987
···
994
981
*/
995
982
int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int offset_start, unsigned int size_total)
996
983
{
997
-
unsigned int offset, size;
998
984
struct xstate_header header;
985
+
const unsigned off_mxcsr = offsetof(struct fxregs_state, mxcsr);
986
+
unsigned count = size_total;
999
987
int i;
1000
988
1001
989
/*
···
1012
998
header.xfeatures = xsave->header.xfeatures;
1013
999
header.xfeatures &= ~XFEATURE_MASK_SUPERVISOR;
1014
1000
1001
+
if (header.xfeatures & XFEATURE_MASK_FP)
1002
+
copy_part(0, off_mxcsr,
1003
+
&xsave->i387, &kbuf, &offset_start, &count);
1004
+
if (header.xfeatures & (XFEATURE_MASK_SSE | XFEATURE_MASK_YMM))
1005
+
copy_part(off_mxcsr, MXCSR_AND_FLAGS_SIZE,
1006
+
&xsave->i387.mxcsr, &kbuf, &offset_start, &count);
1007
+
if (header.xfeatures & XFEATURE_MASK_FP)
1008
+
copy_part(offsetof(struct fxregs_state, st_space), 128,
1009
+
&xsave->i387.st_space, &kbuf, &offset_start, &count);
1010
+
if (header.xfeatures & XFEATURE_MASK_SSE)
1011
+
copy_part(xstate_offsets[XFEATURE_MASK_SSE], 256,
1012
+
&xsave->i387.xmm_space, &kbuf, &offset_start, &count);
1013
+
/*
1014
+
* Fill xsave->i387.sw_reserved value for ptrace frame:
1015
+
*/
1016
+
copy_part(offsetof(struct fxregs_state, sw_reserved), 48,
1017
+
xstate_fx_sw_bytes, &kbuf, &offset_start, &count);
1015
1018
/*
1016
1019
* Copy xregs_state->header:
1017
1020
*/
1018
-
offset = offsetof(struct xregs_state, header);
1019
-
size = sizeof(header);
1021
+
copy_part(offsetof(struct xregs_state, header), sizeof(header),
1022
+
&header, &kbuf, &offset_start, &count);
1020
1023
1021
-
__copy_xstate_to_kernel(kbuf, &header, offset, size, size_total);
1022
-
1023
-
for (i = 0; i < XFEATURE_MAX; i++) {
1024
+
for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) {
1024
1025
/*
1025
1026
* Copy only in-use xstates:
1026
1027
*/
1027
1028
if ((header.xfeatures >> i) & 1) {
1028
1029
void *src = __raw_xsave_addr(xsave, i);
1029
1030
1030
-
offset = xstate_offsets[i];
1031
-
size = xstate_sizes[i];
1032
-
1033
-
/* The next component has to fit fully into the output buffer: */
1034
-
if (offset + size > size_total)
1035
-
break;
1036
-
1037
-
__copy_xstate_to_kernel(kbuf, src, offset, size, size_total);
1031
+
copy_part(xstate_offsets[i], xstate_sizes[i],
1032
+
src, &kbuf, &offset_start, &count);
1038
1033
}
1039
1034
1040
1035
}
1041
-
1042
-
if (xfeatures_mxcsr_quirk(header.xfeatures)) {
1043
-
offset = offsetof(struct fxregs_state, mxcsr);
1044
-
size = MXCSR_AND_FLAGS_SIZE;
1045
-
__copy_xstate_to_kernel(kbuf, &xsave->i387.mxcsr, offset, size, size_total);
1046
-
}
1047
-
1048
-
/*
1049
-
* Fill xsave->i387.sw_reserved value for ptrace frame:
1050
-
*/
1051
-
offset = offsetof(struct fxregs_state, sw_reserved);
1052
-
size = sizeof(xstate_fx_sw_bytes);
1053
-
1054
-
__copy_xstate_to_kernel(kbuf, xstate_fx_sw_bytes, offset, size, size_total);
1036
+
fill_gap(size_total, &kbuf, &offset_start, &count);
1055
1037
1056
1038
return 0;
1057
1039
}