aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2008-07-29 13:29:22 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-30 13:49:26 -0400
commitab5137015fed9b948fe835a2d99a4cfbd50a0c40 (patch)
tree229771c4f5606d56945941c8ada9ae6cf08d1c80 /arch/x86
parent3c1c7f101426cb2ecc79d817a8a65928965fc860 (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.c28
-rw-r--r--arch/x86/kernel/i387.c44
-rw-r--r--arch/x86/kernel/signal_32.c28
-rw-r--r--arch/x86/kernel/signal_64.c83
-rw-r--r--arch/x86/kernel/xsave.c79
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
281badframe:
282 return 1;
283} 269}
284 270
285asmlinkage long sys32_sigreturn(struct pt_regs *regs) 271asmlinkage long sys32_sigreturn(struct pt_regs *regs)
@@ -351,7 +337,7 @@ badframe:
351 */ 337 */
352 338
353static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, 339static 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 */
405static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, 391static 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
458int save_i387_ia32(struct _fpstate_ia32 __user *buf) 456int 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
480static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf) 486static 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
505int restore_i387_ia32(struct _fpstate_ia32 __user *buf) 511int 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
182badframe:
183 return 1;
184} 170}
185 171
186asmlinkage unsigned long sys_sigreturn(unsigned long __unused) 172asmlinkage 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 */
264static int 250static int
265setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, 251setup_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 */
308static inline void __user * 294static inline void __user *
309get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, 295get_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
60static 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 */
92static 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 */
122static int 59static 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
180badframe:
181 return 1;
182} 105}
183 106
184asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) 107asmlinkage 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 */
13unsigned int pcntxt_hmask, pcntxt_lmask; 13unsigned int pcntxt_hmask, pcntxt_lmask;
14 14
15#ifdef CONFIG_X86_64
16/*
17 * Signal frame handlers.
18 */
19
20int 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 */
55int 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 */