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