diff options
author | Suresh Siddha <suresh.b.siddha@intel.com> | 2008-07-29 13:29:22 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-30 13:49:26 -0400 |
commit | ab5137015fed9b948fe835a2d99a4cfbd50a0c40 (patch) | |
tree | 229771c4f5606d56945941c8ada9ae6cf08d1c80 /arch/x86 | |
parent | 3c1c7f101426cb2ecc79d817a8a65928965fc860 (diff) |
x86, xsave: reorganization of signal save/restore fpstate code layout
move 64bit routines that saves/restores fpstate in/from user stack from
signal_64.c to xsave.c
restore_i387_xstate() now handles the condition when user passes
NULL fpstate.
Other misc changes for prepartion of xsave/xrstor sigcontext support.
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/ia32/ia32_signal.c | 28 | ||||
-rw-r--r-- | arch/x86/kernel/i387.c | 44 | ||||
-rw-r--r-- | arch/x86/kernel/signal_32.c | 28 | ||||
-rw-r--r-- | arch/x86/kernel/signal_64.c | 83 | ||||
-rw-r--r-- | arch/x86/kernel/xsave.c | 79 |
5 files changed, 127 insertions, 135 deletions
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index a05bf0fb7415..c596eabbe98b 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c | |||
@@ -216,7 +216,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, | |||
216 | unsigned int *peax) | 216 | unsigned int *peax) |
217 | { | 217 | { |
218 | unsigned int tmpflags, gs, oldgs, err = 0; | 218 | unsigned int tmpflags, gs, oldgs, err = 0; |
219 | struct _fpstate_ia32 __user *buf; | 219 | void __user *buf; |
220 | u32 tmp; | 220 | u32 tmp; |
221 | 221 | ||
222 | /* Always make any pending restarted system calls return -EINTR */ | 222 | /* Always make any pending restarted system calls return -EINTR */ |
@@ -260,26 +260,12 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, | |||
260 | 260 | ||
261 | err |= __get_user(tmp, &sc->fpstate); | 261 | err |= __get_user(tmp, &sc->fpstate); |
262 | buf = compat_ptr(tmp); | 262 | buf = compat_ptr(tmp); |
263 | if (buf) { | 263 | err |= restore_i387_xstate_ia32(buf); |
264 | if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) | ||
265 | goto badframe; | ||
266 | err |= restore_i387_ia32(buf); | ||
267 | } else { | ||
268 | struct task_struct *me = current; | ||
269 | |||
270 | if (used_math()) { | ||
271 | clear_fpu(me); | ||
272 | clear_used_math(); | ||
273 | } | ||
274 | } | ||
275 | 264 | ||
276 | err |= __get_user(tmp, &sc->ax); | 265 | err |= __get_user(tmp, &sc->ax); |
277 | *peax = tmp; | 266 | *peax = tmp; |
278 | 267 | ||
279 | return err; | 268 | return err; |
280 | |||
281 | badframe: | ||
282 | return 1; | ||
283 | } | 269 | } |
284 | 270 | ||
285 | asmlinkage long sys32_sigreturn(struct pt_regs *regs) | 271 | asmlinkage long sys32_sigreturn(struct pt_regs *regs) |
@@ -351,7 +337,7 @@ badframe: | |||
351 | */ | 337 | */ |
352 | 338 | ||
353 | static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, | 339 | static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, |
354 | struct _fpstate_ia32 __user *fpstate, | 340 | void __user *fpstate, |
355 | struct pt_regs *regs, unsigned int mask) | 341 | struct pt_regs *regs, unsigned int mask) |
356 | { | 342 | { |
357 | int tmp, err = 0; | 343 | int tmp, err = 0; |
@@ -382,7 +368,7 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, | |||
382 | err |= __put_user((u32)regs->flags, &sc->flags); | 368 | err |= __put_user((u32)regs->flags, &sc->flags); |
383 | err |= __put_user((u32)regs->sp, &sc->sp_at_signal); | 369 | err |= __put_user((u32)regs->sp, &sc->sp_at_signal); |
384 | 370 | ||
385 | tmp = save_i387_ia32(fpstate); | 371 | tmp = save_i387_xstate_ia32(fpstate); |
386 | if (tmp < 0) | 372 | if (tmp < 0) |
387 | err = -EFAULT; | 373 | err = -EFAULT; |
388 | else { | 374 | else { |
@@ -404,7 +390,7 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, | |||
404 | */ | 390 | */ |
405 | static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | 391 | static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, |
406 | size_t frame_size, | 392 | size_t frame_size, |
407 | struct _fpstate_ia32 **fpstate) | 393 | void **fpstate) |
408 | { | 394 | { |
409 | unsigned long sp; | 395 | unsigned long sp; |
410 | 396 | ||
@@ -441,7 +427,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
441 | struct sigframe __user *frame; | 427 | struct sigframe __user *frame; |
442 | void __user *restorer; | 428 | void __user *restorer; |
443 | int err = 0; | 429 | int err = 0; |
444 | struct _fpstate_ia32 __user *fpstate = NULL; | 430 | void __user *fpstate = NULL; |
445 | 431 | ||
446 | /* copy_to_user optimizes that into a single 8 byte store */ | 432 | /* copy_to_user optimizes that into a single 8 byte store */ |
447 | static const struct { | 433 | static const struct { |
@@ -529,7 +515,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
529 | struct rt_sigframe __user *frame; | 515 | struct rt_sigframe __user *frame; |
530 | void __user *restorer; | 516 | void __user *restorer; |
531 | int err = 0; | 517 | int err = 0; |
532 | struct _fpstate_ia32 __user *fpstate = NULL; | 518 | void __user *fpstate = NULL; |
533 | 519 | ||
534 | /* __copy_to_user optimizes that into a single 8 byte store */ | 520 | /* __copy_to_user optimizes that into a single 8 byte store */ |
535 | static const struct { | 521 | static const struct { |
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index 51fb288a2c97..7daf3a011dd9 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c | |||
@@ -21,9 +21,10 @@ | |||
21 | # include <asm/sigcontext32.h> | 21 | # include <asm/sigcontext32.h> |
22 | # include <asm/user32.h> | 22 | # include <asm/user32.h> |
23 | #else | 23 | #else |
24 | # define save_i387_ia32 save_i387 | 24 | # define save_i387_xstate_ia32 save_i387_xstate |
25 | # define restore_i387_ia32 restore_i387 | 25 | # define restore_i387_xstate_ia32 restore_i387_xstate |
26 | # define _fpstate_ia32 _fpstate | 26 | # define _fpstate_ia32 _fpstate |
27 | # define _xstate_ia32 _xstate | ||
27 | # define sig_xstate_ia32_size sig_xstate_size | 28 | # define sig_xstate_ia32_size sig_xstate_size |
28 | # define user_i387_ia32_struct user_i387_struct | 29 | # define user_i387_ia32_struct user_i387_struct |
29 | # define user32_fxsr_struct user_fxsr_struct | 30 | # define user32_fxsr_struct user_fxsr_struct |
@@ -424,7 +425,6 @@ static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf) | |||
424 | struct task_struct *tsk = current; | 425 | struct task_struct *tsk = current; |
425 | struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave; | 426 | struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave; |
426 | 427 | ||
427 | unlazy_fpu(tsk); | ||
428 | fp->status = fp->swd; | 428 | fp->status = fp->swd; |
429 | if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct))) | 429 | if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct))) |
430 | return -1; | 430 | return -1; |
@@ -438,8 +438,6 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf) | |||
438 | struct user_i387_ia32_struct env; | 438 | struct user_i387_ia32_struct env; |
439 | int err = 0; | 439 | int err = 0; |
440 | 440 | ||
441 | unlazy_fpu(tsk); | ||
442 | |||
443 | convert_from_fxsr(&env, tsk); | 441 | convert_from_fxsr(&env, tsk); |
444 | if (__copy_to_user(buf, &env, sizeof(env))) | 442 | if (__copy_to_user(buf, &env, sizeof(env))) |
445 | return -1; | 443 | return -1; |
@@ -455,10 +453,16 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf) | |||
455 | return 1; | 453 | return 1; |
456 | } | 454 | } |
457 | 455 | ||
458 | int save_i387_ia32(struct _fpstate_ia32 __user *buf) | 456 | int save_i387_xstate_ia32(void __user *buf) |
459 | { | 457 | { |
458 | struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf; | ||
459 | struct task_struct *tsk = current; | ||
460 | |||
460 | if (!used_math()) | 461 | if (!used_math()) |
461 | return 0; | 462 | return 0; |
463 | |||
464 | if (!access_ok(VERIFY_WRITE, buf, sig_xstate_ia32_size)) | ||
465 | return -EACCES; | ||
462 | /* | 466 | /* |
463 | * This will cause a "finit" to be triggered by the next | 467 | * This will cause a "finit" to be triggered by the next |
464 | * attempted FPU operation by the 'current' process. | 468 | * attempted FPU operation by the 'current' process. |
@@ -468,13 +472,15 @@ int save_i387_ia32(struct _fpstate_ia32 __user *buf) | |||
468 | if (!HAVE_HWFP) { | 472 | if (!HAVE_HWFP) { |
469 | return fpregs_soft_get(current, NULL, | 473 | return fpregs_soft_get(current, NULL, |
470 | 0, sizeof(struct user_i387_ia32_struct), | 474 | 0, sizeof(struct user_i387_ia32_struct), |
471 | NULL, buf) ? -1 : 1; | 475 | NULL, fp) ? -1 : 1; |
472 | } | 476 | } |
473 | 477 | ||
478 | unlazy_fpu(tsk); | ||
479 | |||
474 | if (cpu_has_fxsr) | 480 | if (cpu_has_fxsr) |
475 | return save_i387_fxsave(buf); | 481 | return save_i387_fxsave(fp); |
476 | else | 482 | else |
477 | return save_i387_fsave(buf); | 483 | return save_i387_fsave(fp); |
478 | } | 484 | } |
479 | 485 | ||
480 | static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf) | 486 | static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf) |
@@ -502,14 +508,26 @@ static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf) | |||
502 | return 0; | 508 | return 0; |
503 | } | 509 | } |
504 | 510 | ||
505 | int restore_i387_ia32(struct _fpstate_ia32 __user *buf) | 511 | int restore_i387_xstate_ia32(void __user *buf) |
506 | { | 512 | { |
507 | int err; | 513 | int err; |
508 | struct task_struct *tsk = current; | 514 | struct task_struct *tsk = current; |
515 | struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf; | ||
509 | 516 | ||
510 | if (HAVE_HWFP) | 517 | if (HAVE_HWFP) |
511 | clear_fpu(tsk); | 518 | clear_fpu(tsk); |
512 | 519 | ||
520 | if (!buf) { | ||
521 | if (used_math()) { | ||
522 | clear_fpu(tsk); | ||
523 | clear_used_math(); | ||
524 | } | ||
525 | |||
526 | return 0; | ||
527 | } else | ||
528 | if (!access_ok(VERIFY_READ, buf, sig_xstate_ia32_size)) | ||
529 | return -EACCES; | ||
530 | |||
513 | if (!used_math()) { | 531 | if (!used_math()) { |
514 | err = init_fpu(tsk); | 532 | err = init_fpu(tsk); |
515 | if (err) | 533 | if (err) |
@@ -518,13 +536,13 @@ int restore_i387_ia32(struct _fpstate_ia32 __user *buf) | |||
518 | 536 | ||
519 | if (HAVE_HWFP) { | 537 | if (HAVE_HWFP) { |
520 | if (cpu_has_fxsr) | 538 | if (cpu_has_fxsr) |
521 | err = restore_i387_fxsave(buf); | 539 | err = restore_i387_fxsave(fp); |
522 | else | 540 | else |
523 | err = restore_i387_fsave(buf); | 541 | err = restore_i387_fsave(fp); |
524 | } else { | 542 | } else { |
525 | err = fpregs_soft_set(current, NULL, | 543 | err = fpregs_soft_set(current, NULL, |
526 | 0, sizeof(struct user_i387_ia32_struct), | 544 | 0, sizeof(struct user_i387_ia32_struct), |
527 | NULL, buf) != 0; | 545 | NULL, fp) != 0; |
528 | } | 546 | } |
529 | set_used_math(); | 547 | set_used_math(); |
530 | 548 | ||
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c index 19a7a5669b5b..690cc616ac07 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal_32.c | |||
@@ -159,28 +159,14 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
159 | } | 159 | } |
160 | 160 | ||
161 | { | 161 | { |
162 | struct _fpstate __user *buf; | 162 | void __user *buf; |
163 | 163 | ||
164 | err |= __get_user(buf, &sc->fpstate); | 164 | err |= __get_user(buf, &sc->fpstate); |
165 | if (buf) { | 165 | err |= restore_i387_xstate(buf); |
166 | if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) | ||
167 | goto badframe; | ||
168 | err |= restore_i387(buf); | ||
169 | } else { | ||
170 | struct task_struct *me = current; | ||
171 | |||
172 | if (used_math()) { | ||
173 | clear_fpu(me); | ||
174 | clear_used_math(); | ||
175 | } | ||
176 | } | ||
177 | } | 166 | } |
178 | 167 | ||
179 | err |= __get_user(*pax, &sc->ax); | 168 | err |= __get_user(*pax, &sc->ax); |
180 | return err; | 169 | return err; |
181 | |||
182 | badframe: | ||
183 | return 1; | ||
184 | } | 170 | } |
185 | 171 | ||
186 | asmlinkage unsigned long sys_sigreturn(unsigned long __unused) | 172 | asmlinkage unsigned long sys_sigreturn(unsigned long __unused) |
@@ -262,7 +248,7 @@ badframe: | |||
262 | * Set up a signal frame. | 248 | * Set up a signal frame. |
263 | */ | 249 | */ |
264 | static int | 250 | static int |
265 | setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, | 251 | setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, |
266 | struct pt_regs *regs, unsigned long mask) | 252 | struct pt_regs *regs, unsigned long mask) |
267 | { | 253 | { |
268 | int tmp, err = 0; | 254 | int tmp, err = 0; |
@@ -289,7 +275,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, | |||
289 | err |= __put_user(regs->sp, &sc->sp_at_signal); | 275 | err |= __put_user(regs->sp, &sc->sp_at_signal); |
290 | err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); | 276 | err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); |
291 | 277 | ||
292 | tmp = save_i387(fpstate); | 278 | tmp = save_i387_xstate(fpstate); |
293 | if (tmp < 0) | 279 | if (tmp < 0) |
294 | err = 1; | 280 | err = 1; |
295 | else | 281 | else |
@@ -307,7 +293,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, | |||
307 | */ | 293 | */ |
308 | static inline void __user * | 294 | static inline void __user * |
309 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, | 295 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, |
310 | struct _fpstate **fpstate) | 296 | void **fpstate) |
311 | { | 297 | { |
312 | unsigned long sp; | 298 | unsigned long sp; |
313 | 299 | ||
@@ -356,7 +342,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
356 | void __user *restorer; | 342 | void __user *restorer; |
357 | int err = 0; | 343 | int err = 0; |
358 | int usig; | 344 | int usig; |
359 | struct _fpstate __user *fpstate = NULL; | 345 | void __user *fpstate = NULL; |
360 | 346 | ||
361 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); | 347 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
362 | 348 | ||
@@ -434,7 +420,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
434 | void __user *restorer; | 420 | void __user *restorer; |
435 | int err = 0; | 421 | int err = 0; |
436 | int usig; | 422 | int usig; |
437 | struct _fpstate __user *fpstate = NULL; | 423 | void __user *fpstate = NULL; |
438 | 424 | ||
439 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); | 425 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
440 | 426 | ||
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index 0deab8eff33f..ddf6123a55c8 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c | |||
@@ -54,69 +54,6 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | |||
54 | } | 54 | } |
55 | 55 | ||
56 | /* | 56 | /* |
57 | * Signal frame handlers. | ||
58 | */ | ||
59 | |||
60 | static inline int save_i387(struct _fpstate __user *buf) | ||
61 | { | ||
62 | struct task_struct *tsk = current; | ||
63 | int err = 0; | ||
64 | |||
65 | BUILD_BUG_ON(sizeof(struct user_i387_struct) != | ||
66 | sizeof(tsk->thread.xstate->fxsave)); | ||
67 | |||
68 | if ((unsigned long)buf % 16) | ||
69 | printk("save_i387: bad fpstate %p\n", buf); | ||
70 | |||
71 | if (!used_math()) | ||
72 | return 0; | ||
73 | clear_used_math(); /* trigger finit */ | ||
74 | if (task_thread_info(tsk)->status & TS_USEDFPU) { | ||
75 | err = save_i387_checking((struct i387_fxsave_struct __user *) | ||
76 | buf); | ||
77 | if (err) | ||
78 | return err; | ||
79 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | ||
80 | stts(); | ||
81 | } else { | ||
82 | if (__copy_to_user(buf, &tsk->thread.xstate->fxsave, | ||
83 | sizeof(struct i387_fxsave_struct))) | ||
84 | return -1; | ||
85 | } | ||
86 | return 1; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * This restores directly out of user space. Exceptions are handled. | ||
91 | */ | ||
92 | static inline int restore_i387(struct _fpstate __user *buf) | ||
93 | { | ||
94 | struct task_struct *tsk = current; | ||
95 | int err; | ||
96 | |||
97 | if (!used_math()) { | ||
98 | err = init_fpu(tsk); | ||
99 | if (err) | ||
100 | return err; | ||
101 | } | ||
102 | |||
103 | if (!(task_thread_info(current)->status & TS_USEDFPU)) { | ||
104 | clts(); | ||
105 | task_thread_info(current)->status |= TS_USEDFPU; | ||
106 | } | ||
107 | err = restore_fpu_checking((__force struct i387_fxsave_struct *)buf); | ||
108 | if (unlikely(err)) { | ||
109 | /* | ||
110 | * Encountered an error while doing the restore from the | ||
111 | * user buffer, clear the fpu state. | ||
112 | */ | ||
113 | clear_fpu(tsk); | ||
114 | clear_used_math(); | ||
115 | } | ||
116 | return err; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * Do a signal return; undo the signal stack. | 57 | * Do a signal return; undo the signal stack. |
121 | */ | 58 | */ |
122 | static int | 59 | static int |
@@ -160,25 +97,11 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
160 | { | 97 | { |
161 | struct _fpstate __user * buf; | 98 | struct _fpstate __user * buf; |
162 | err |= __get_user(buf, &sc->fpstate); | 99 | err |= __get_user(buf, &sc->fpstate); |
163 | 100 | err |= restore_i387_xstate(buf); | |
164 | if (buf) { | ||
165 | if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) | ||
166 | goto badframe; | ||
167 | err |= restore_i387(buf); | ||
168 | } else { | ||
169 | struct task_struct *me = current; | ||
170 | if (used_math()) { | ||
171 | clear_fpu(me); | ||
172 | clear_used_math(); | ||
173 | } | ||
174 | } | ||
175 | } | 101 | } |
176 | 102 | ||
177 | err |= __get_user(*pax, &sc->ax); | 103 | err |= __get_user(*pax, &sc->ax); |
178 | return err; | 104 | return err; |
179 | |||
180 | badframe: | ||
181 | return 1; | ||
182 | } | 105 | } |
183 | 106 | ||
184 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | 107 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) |
@@ -276,7 +199,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
276 | sigset_t *set, struct pt_regs * regs) | 199 | sigset_t *set, struct pt_regs * regs) |
277 | { | 200 | { |
278 | struct rt_sigframe __user *frame; | 201 | struct rt_sigframe __user *frame; |
279 | struct _fpstate __user *fp = NULL; | 202 | void __user *fp = NULL; |
280 | int err = 0; | 203 | int err = 0; |
281 | struct task_struct *me = current; | 204 | struct task_struct *me = current; |
282 | 205 | ||
@@ -288,7 +211,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
288 | if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) | 211 | if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) |
289 | goto give_sigsegv; | 212 | goto give_sigsegv; |
290 | 213 | ||
291 | if (save_i387(fp) < 0) | 214 | if (save_i387_xstate(fp) < 0) |
292 | err |= -1; | 215 | err |= -1; |
293 | } else | 216 | } else |
294 | frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; | 217 | frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; |
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index 7ad169e33528..608e72d7ca64 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c | |||
@@ -12,6 +12,85 @@ | |||
12 | */ | 12 | */ |
13 | unsigned int pcntxt_hmask, pcntxt_lmask; | 13 | unsigned int pcntxt_hmask, pcntxt_lmask; |
14 | 14 | ||
15 | #ifdef CONFIG_X86_64 | ||
16 | /* | ||
17 | * Signal frame handlers. | ||
18 | */ | ||
19 | |||
20 | int save_i387_xstate(void __user *buf) | ||
21 | { | ||
22 | struct task_struct *tsk = current; | ||
23 | int err = 0; | ||
24 | |||
25 | if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size)) | ||
26 | return -EACCES; | ||
27 | |||
28 | BUILD_BUG_ON(sizeof(struct user_i387_struct) != | ||
29 | sizeof(tsk->thread.xstate->fxsave)); | ||
30 | |||
31 | if ((unsigned long)buf % 16) | ||
32 | printk("save_i387_xstate: bad fpstate %p\n", buf); | ||
33 | |||
34 | if (!used_math()) | ||
35 | return 0; | ||
36 | clear_used_math(); /* trigger finit */ | ||
37 | if (task_thread_info(tsk)->status & TS_USEDFPU) { | ||
38 | err = save_i387_checking((struct i387_fxsave_struct __user *) | ||
39 | buf); | ||
40 | if (err) | ||
41 | return err; | ||
42 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | ||
43 | stts(); | ||
44 | } else { | ||
45 | if (__copy_to_user(buf, &tsk->thread.xstate->fxsave, | ||
46 | xstate_size)) | ||
47 | return -1; | ||
48 | } | ||
49 | return 1; | ||
50 | } | ||
51 | |||
52 | /* | ||
53 | * This restores directly out of user space. Exceptions are handled. | ||
54 | */ | ||
55 | int restore_i387_xstate(void __user *buf) | ||
56 | { | ||
57 | struct task_struct *tsk = current; | ||
58 | int err; | ||
59 | |||
60 | if (!buf) { | ||
61 | if (used_math()) { | ||
62 | clear_fpu(tsk); | ||
63 | clear_used_math(); | ||
64 | } | ||
65 | |||
66 | return 0; | ||
67 | } else | ||
68 | if (!access_ok(VERIFY_READ, buf, sig_xstate_size)) | ||
69 | return -EACCES; | ||
70 | |||
71 | if (!used_math()) { | ||
72 | err = init_fpu(tsk); | ||
73 | if (err) | ||
74 | return err; | ||
75 | } | ||
76 | |||
77 | if (!(task_thread_info(current)->status & TS_USEDFPU)) { | ||
78 | clts(); | ||
79 | task_thread_info(current)->status |= TS_USEDFPU; | ||
80 | } | ||
81 | err = fxrstor_checking((__force struct i387_fxsave_struct *)buf); | ||
82 | if (unlikely(err)) { | ||
83 | /* | ||
84 | * Encountered an error while doing the restore from the | ||
85 | * user buffer, clear the fpu state. | ||
86 | */ | ||
87 | clear_fpu(tsk); | ||
88 | clear_used_math(); | ||
89 | } | ||
90 | return err; | ||
91 | } | ||
92 | #endif | ||
93 | |||
15 | /* | 94 | /* |
16 | * Represents init state for the supported extended state. | 95 | * Represents init state for the supported extended state. |
17 | */ | 96 | */ |