@@ -920,6 +920,23 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
920
920
}
921
921
#endif /* ! CONFIG_ARCH_HAS_PKEYS */
922
922
923
+ /*
924
+ * Weird legacy quirk: SSE and YMM states store information in the
925
+ * MXCSR and MXCSR_FLAGS fields of the FP area. That means if the FP
926
+ * area is marked as unused in the xfeatures header, we need to copy
927
+ * MXCSR and MXCSR_FLAGS if either SSE or YMM are in use.
928
+ */
929
+ static inline bool xfeatures_mxcsr_quirk (u64 xfeatures )
930
+ {
931
+ if (!(xfeatures & (XFEATURE_MASK_SSE |XFEATURE_MASK_YMM )))
932
+ return 0 ;
933
+
934
+ if (xfeatures & XFEATURE_MASK_FP )
935
+ return 0 ;
936
+
937
+ return 1 ;
938
+ }
939
+
923
940
/*
924
941
* This is similar to user_regset_copyout(), but will not add offset to
925
942
* the source data pointer or increment pos, count, kbuf, and ubuf.
@@ -988,6 +1005,12 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of
988
1005
989
1006
}
990
1007
1008
+ if (xfeatures_mxcsr_quirk (header .xfeatures )) {
1009
+ offset = offsetof(struct fxregs_state , mxcsr );
1010
+ size = MXCSR_AND_FLAGS_SIZE ;
1011
+ __copy_xstate_to_kernel (kbuf , & xsave -> i387 .mxcsr , offset , size , size_total );
1012
+ }
1013
+
991
1014
/*
992
1015
* Fill xsave->i387.sw_reserved value for ptrace frame:
993
1016
*/
@@ -1070,6 +1093,12 @@ int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned i
1070
1093
1071
1094
}
1072
1095
1096
+ if (xfeatures_mxcsr_quirk (header .xfeatures )) {
1097
+ offset = offsetof(struct fxregs_state , mxcsr );
1098
+ size = MXCSR_AND_FLAGS_SIZE ;
1099
+ __copy_xstate_to_user (ubuf , & xsave -> i387 .mxcsr , offset , size , size_total );
1100
+ }
1101
+
1073
1102
/*
1074
1103
* Fill xsave->i387.sw_reserved value for ptrace frame:
1075
1104
*/
@@ -1122,6 +1151,12 @@ int copy_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf)
1122
1151
}
1123
1152
}
1124
1153
1154
+ if (xfeatures_mxcsr_quirk (xfeatures )) {
1155
+ offset = offsetof(struct fxregs_state , mxcsr );
1156
+ size = MXCSR_AND_FLAGS_SIZE ;
1157
+ memcpy (& xsave -> i387 .mxcsr , kbuf + offset , size );
1158
+ }
1159
+
1125
1160
/*
1126
1161
* The state that came in from userspace was user-state only.
1127
1162
* Mask all the user states out of 'xfeatures':
@@ -1177,6 +1212,13 @@ int copy_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf)
1177
1212
}
1178
1213
}
1179
1214
1215
+ if (xfeatures_mxcsr_quirk (xfeatures )) {
1216
+ offset = offsetof(struct fxregs_state , mxcsr );
1217
+ size = MXCSR_AND_FLAGS_SIZE ;
1218
+ if (__copy_from_user (& xsave -> i387 .mxcsr , ubuf + offset , size ))
1219
+ return - EFAULT ;
1220
+ }
1221
+
1180
1222
/*
1181
1223
* The state that came in from userspace was user-state only.
1182
1224
* Mask all the user states out of 'xfeatures':
0 commit comments