diff options
Diffstat (limited to 'arch/x86/kernel/i387.c')
-rw-r--r-- | arch/x86/kernel/i387.c | 71 |
1 files changed, 67 insertions, 4 deletions
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index f2f8540a7f3d..c01a2b846d47 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c | |||
@@ -164,6 +164,11 @@ int init_fpu(struct task_struct *tsk) | |||
164 | return 0; | 164 | return 0; |
165 | } | 165 | } |
166 | 166 | ||
167 | /* | ||
168 | * The xstateregs_active() routine is the same as the fpregs_active() routine, | ||
169 | * as the "regset->n" for the xstate regset will be updated based on the feature | ||
170 | * capabilites supported by the xsave. | ||
171 | */ | ||
167 | int fpregs_active(struct task_struct *target, const struct user_regset *regset) | 172 | int fpregs_active(struct task_struct *target, const struct user_regset *regset) |
168 | { | 173 | { |
169 | return tsk_used_math(target) ? regset->n : 0; | 174 | return tsk_used_math(target) ? regset->n : 0; |
@@ -204,8 +209,6 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset, | |||
204 | if (ret) | 209 | if (ret) |
205 | return ret; | 210 | return ret; |
206 | 211 | ||
207 | set_stopped_child_used_math(target); | ||
208 | |||
209 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | 212 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
210 | &target->thread.xstate->fxsave, 0, -1); | 213 | &target->thread.xstate->fxsave, 0, -1); |
211 | 214 | ||
@@ -224,6 +227,68 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset, | |||
224 | return ret; | 227 | return ret; |
225 | } | 228 | } |
226 | 229 | ||
230 | int xstateregs_get(struct task_struct *target, const struct user_regset *regset, | ||
231 | unsigned int pos, unsigned int count, | ||
232 | void *kbuf, void __user *ubuf) | ||
233 | { | ||
234 | int ret; | ||
235 | |||
236 | if (!cpu_has_xsave) | ||
237 | return -ENODEV; | ||
238 | |||
239 | ret = init_fpu(target); | ||
240 | if (ret) | ||
241 | return ret; | ||
242 | |||
243 | /* | ||
244 | * Copy the 48bytes defined by the software first into the xstate | ||
245 | * memory layout in the thread struct, so that we can copy the entire | ||
246 | * xstateregs to the user using one user_regset_copyout(). | ||
247 | */ | ||
248 | memcpy(&target->thread.xstate->fxsave.sw_reserved, | ||
249 | xstate_fx_sw_bytes, sizeof(xstate_fx_sw_bytes)); | ||
250 | |||
251 | /* | ||
252 | * Copy the xstate memory layout. | ||
253 | */ | ||
254 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
255 | &target->thread.xstate->xsave, 0, -1); | ||
256 | return ret; | ||
257 | } | ||
258 | |||
259 | int xstateregs_set(struct task_struct *target, const struct user_regset *regset, | ||
260 | unsigned int pos, unsigned int count, | ||
261 | const void *kbuf, const void __user *ubuf) | ||
262 | { | ||
263 | int ret; | ||
264 | struct xsave_hdr_struct *xsave_hdr; | ||
265 | |||
266 | if (!cpu_has_xsave) | ||
267 | return -ENODEV; | ||
268 | |||
269 | ret = init_fpu(target); | ||
270 | if (ret) | ||
271 | return ret; | ||
272 | |||
273 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
274 | &target->thread.xstate->xsave, 0, -1); | ||
275 | |||
276 | /* | ||
277 | * mxcsr reserved bits must be masked to zero for security reasons. | ||
278 | */ | ||
279 | target->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; | ||
280 | |||
281 | xsave_hdr = &target->thread.xstate->xsave.xsave_hdr; | ||
282 | |||
283 | xsave_hdr->xstate_bv &= pcntxt_mask; | ||
284 | /* | ||
285 | * These bits must be zero. | ||
286 | */ | ||
287 | xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0; | ||
288 | |||
289 | return ret; | ||
290 | } | ||
291 | |||
227 | #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION | 292 | #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION |
228 | 293 | ||
229 | /* | 294 | /* |
@@ -404,8 +469,6 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, | |||
404 | if (ret) | 469 | if (ret) |
405 | return ret; | 470 | return ret; |
406 | 471 | ||
407 | set_stopped_child_used_math(target); | ||
408 | |||
409 | if (!HAVE_HWFP) | 472 | if (!HAVE_HWFP) |
410 | return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf); | 473 | return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf); |
411 | 474 | ||