diff options
-rw-r--r-- | arch/x86/ia32/ia32_signal.c | 24 | ||||
-rw-r--r-- | arch/x86/kernel/i387.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/sigframe.h | 14 | ||||
-rw-r--r-- | arch/x86/kernel/signal_32.c | 18 | ||||
-rw-r--r-- | arch/x86/kernel/signal_64.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/xsave.c | 4 | ||||
-rw-r--r-- | include/asm-x86/i387.h | 2 |
7 files changed, 50 insertions, 16 deletions
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 20af4c79579a..a05bf0fb7415 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c | |||
@@ -179,9 +179,10 @@ struct sigframe | |||
179 | u32 pretcode; | 179 | u32 pretcode; |
180 | int sig; | 180 | int sig; |
181 | struct sigcontext_ia32 sc; | 181 | struct sigcontext_ia32 sc; |
182 | struct _fpstate_ia32 fpstate; | 182 | struct _fpstate_ia32 fpstate_unused; /* look at kernel/sigframe.h */ |
183 | unsigned int extramask[_COMPAT_NSIG_WORDS-1]; | 183 | unsigned int extramask[_COMPAT_NSIG_WORDS-1]; |
184 | char retcode[8]; | 184 | char retcode[8]; |
185 | /* fp state follows here */ | ||
185 | }; | 186 | }; |
186 | 187 | ||
187 | struct rt_sigframe | 188 | struct rt_sigframe |
@@ -192,8 +193,8 @@ struct rt_sigframe | |||
192 | u32 puc; | 193 | u32 puc; |
193 | compat_siginfo_t info; | 194 | compat_siginfo_t info; |
194 | struct ucontext_ia32 uc; | 195 | struct ucontext_ia32 uc; |
195 | struct _fpstate_ia32 fpstate; | ||
196 | char retcode[8]; | 196 | char retcode[8]; |
197 | /* fp state follows here */ | ||
197 | }; | 198 | }; |
198 | 199 | ||
199 | #define COPY(x) { \ | 200 | #define COPY(x) { \ |
@@ -402,7 +403,8 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, | |||
402 | * Determine which stack to use.. | 403 | * Determine which stack to use.. |
403 | */ | 404 | */ |
404 | static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | 405 | static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, |
405 | size_t frame_size) | 406 | size_t frame_size, |
407 | struct _fpstate_ia32 **fpstate) | ||
406 | { | 408 | { |
407 | unsigned long sp; | 409 | unsigned long sp; |
408 | 410 | ||
@@ -421,6 +423,11 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | |||
421 | ka->sa.sa_restorer) | 423 | ka->sa.sa_restorer) |
422 | sp = (unsigned long) ka->sa.sa_restorer; | 424 | sp = (unsigned long) ka->sa.sa_restorer; |
423 | 425 | ||
426 | if (used_math()) { | ||
427 | sp = sp - sig_xstate_ia32_size; | ||
428 | *fpstate = (struct _fpstate_ia32 *) sp; | ||
429 | } | ||
430 | |||
424 | sp -= frame_size; | 431 | sp -= frame_size; |
425 | /* Align the stack pointer according to the i386 ABI, | 432 | /* Align the stack pointer according to the i386 ABI, |
426 | * i.e. so that on function entry ((sp + 4) & 15) == 0. */ | 433 | * i.e. so that on function entry ((sp + 4) & 15) == 0. */ |
@@ -434,6 +441,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
434 | struct sigframe __user *frame; | 441 | struct sigframe __user *frame; |
435 | void __user *restorer; | 442 | void __user *restorer; |
436 | int err = 0; | 443 | int err = 0; |
444 | struct _fpstate_ia32 __user *fpstate = NULL; | ||
437 | 445 | ||
438 | /* copy_to_user optimizes that into a single 8 byte store */ | 446 | /* copy_to_user optimizes that into a single 8 byte store */ |
439 | static const struct { | 447 | static const struct { |
@@ -448,7 +456,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
448 | 0, | 456 | 0, |
449 | }; | 457 | }; |
450 | 458 | ||
451 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 459 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
452 | 460 | ||
453 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 461 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
454 | goto give_sigsegv; | 462 | goto give_sigsegv; |
@@ -457,8 +465,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
457 | if (err) | 465 | if (err) |
458 | goto give_sigsegv; | 466 | goto give_sigsegv; |
459 | 467 | ||
460 | err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs, | 468 | err |= ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]); |
461 | set->sig[0]); | ||
462 | if (err) | 469 | if (err) |
463 | goto give_sigsegv; | 470 | goto give_sigsegv; |
464 | 471 | ||
@@ -522,6 +529,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
522 | struct rt_sigframe __user *frame; | 529 | struct rt_sigframe __user *frame; |
523 | void __user *restorer; | 530 | void __user *restorer; |
524 | int err = 0; | 531 | int err = 0; |
532 | struct _fpstate_ia32 __user *fpstate = NULL; | ||
525 | 533 | ||
526 | /* __copy_to_user optimizes that into a single 8 byte store */ | 534 | /* __copy_to_user optimizes that into a single 8 byte store */ |
527 | static const struct { | 535 | static const struct { |
@@ -537,7 +545,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
537 | 0, | 545 | 0, |
538 | }; | 546 | }; |
539 | 547 | ||
540 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 548 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
541 | 549 | ||
542 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 550 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
543 | goto give_sigsegv; | 551 | goto give_sigsegv; |
@@ -556,7 +564,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
556 | err |= __put_user(sas_ss_flags(regs->sp), | 564 | err |= __put_user(sas_ss_flags(regs->sp), |
557 | &frame->uc.uc_stack.ss_flags); | 565 | &frame->uc.uc_stack.ss_flags); |
558 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 566 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
559 | err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, | 567 | err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate, |
560 | regs, set->sig[0]); | 568 | regs, set->sig[0]); |
561 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 569 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
562 | if (err) | 570 | if (err) |
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index b778e17e4b01..51fb288a2c97 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c | |||
@@ -24,6 +24,7 @@ | |||
24 | # define save_i387_ia32 save_i387 | 24 | # define save_i387_ia32 save_i387 |
25 | # define restore_i387_ia32 restore_i387 | 25 | # define restore_i387_ia32 restore_i387 |
26 | # define _fpstate_ia32 _fpstate | 26 | # define _fpstate_ia32 _fpstate |
27 | # define sig_xstate_ia32_size sig_xstate_size | ||
27 | # define user_i387_ia32_struct user_i387_struct | 28 | # define user_i387_ia32_struct user_i387_struct |
28 | # define user32_fxsr_struct user_fxsr_struct | 29 | # define user32_fxsr_struct user_fxsr_struct |
29 | #endif | 30 | #endif |
@@ -36,6 +37,7 @@ | |||
36 | 37 | ||
37 | static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; | 38 | static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; |
38 | unsigned int xstate_size; | 39 | unsigned int xstate_size; |
40 | unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32); | ||
39 | static struct i387_fxsave_struct fx_scratch __cpuinitdata; | 41 | static struct i387_fxsave_struct fx_scratch __cpuinitdata; |
40 | 42 | ||
41 | void __cpuinit mxcsr_feature_mask_init(void) | 43 | void __cpuinit mxcsr_feature_mask_init(void) |
diff --git a/arch/x86/kernel/sigframe.h b/arch/x86/kernel/sigframe.h index 72bbb519d2dc..6dd7e2b70a4b 100644 --- a/arch/x86/kernel/sigframe.h +++ b/arch/x86/kernel/sigframe.h | |||
@@ -3,9 +3,18 @@ struct sigframe { | |||
3 | char __user *pretcode; | 3 | char __user *pretcode; |
4 | int sig; | 4 | int sig; |
5 | struct sigcontext sc; | 5 | struct sigcontext sc; |
6 | struct _fpstate fpstate; | 6 | /* |
7 | * fpstate is unused. fpstate is moved/allocated after | ||
8 | * retcode[] below. This movement allows to have the FP state and the | ||
9 | * future state extensions (xsave) stay together. | ||
10 | * And at the same time retaining the unused fpstate, prevents changing | ||
11 | * the offset of extramask[] in the sigframe and thus prevent any | ||
12 | * legacy application accessing/modifying it. | ||
13 | */ | ||
14 | struct _fpstate fpstate_unused; | ||
7 | unsigned long extramask[_NSIG_WORDS-1]; | 15 | unsigned long extramask[_NSIG_WORDS-1]; |
8 | char retcode[8]; | 16 | char retcode[8]; |
17 | /* fp state follows here */ | ||
9 | }; | 18 | }; |
10 | 19 | ||
11 | struct rt_sigframe { | 20 | struct rt_sigframe { |
@@ -15,13 +24,14 @@ struct rt_sigframe { | |||
15 | void __user *puc; | 24 | void __user *puc; |
16 | struct siginfo info; | 25 | struct siginfo info; |
17 | struct ucontext uc; | 26 | struct ucontext uc; |
18 | struct _fpstate fpstate; | ||
19 | char retcode[8]; | 27 | char retcode[8]; |
28 | /* fp state follows here */ | ||
20 | }; | 29 | }; |
21 | #else | 30 | #else |
22 | struct rt_sigframe { | 31 | struct rt_sigframe { |
23 | char __user *pretcode; | 32 | char __user *pretcode; |
24 | struct ucontext uc; | 33 | struct ucontext uc; |
25 | struct siginfo info; | 34 | struct siginfo info; |
35 | /* fp state follows here */ | ||
26 | }; | 36 | }; |
27 | #endif | 37 | #endif |
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c index 6fb5bcdd8933..19a7a5669b5b 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal_32.c | |||
@@ -306,7 +306,8 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, | |||
306 | * Determine which stack to use.. | 306 | * Determine which stack to use.. |
307 | */ | 307 | */ |
308 | static inline void __user * | 308 | static inline void __user * |
309 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | 309 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, |
310 | struct _fpstate **fpstate) | ||
310 | { | 311 | { |
311 | unsigned long sp; | 312 | unsigned long sp; |
312 | 313 | ||
@@ -332,6 +333,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | |||
332 | sp = (unsigned long) ka->sa.sa_restorer; | 333 | sp = (unsigned long) ka->sa.sa_restorer; |
333 | } | 334 | } |
334 | 335 | ||
336 | if (used_math()) { | ||
337 | sp = sp - sig_xstate_size; | ||
338 | *fpstate = (struct _fpstate *) sp; | ||
339 | } | ||
340 | |||
335 | sp -= frame_size; | 341 | sp -= frame_size; |
336 | /* | 342 | /* |
337 | * Align the stack pointer according to the i386 ABI, | 343 | * Align the stack pointer according to the i386 ABI, |
@@ -350,8 +356,9 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
350 | void __user *restorer; | 356 | void __user *restorer; |
351 | int err = 0; | 357 | int err = 0; |
352 | int usig; | 358 | int usig; |
359 | struct _fpstate __user *fpstate = NULL; | ||
353 | 360 | ||
354 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 361 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
355 | 362 | ||
356 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 363 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
357 | goto give_sigsegv; | 364 | goto give_sigsegv; |
@@ -366,7 +373,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
366 | if (err) | 373 | if (err) |
367 | goto give_sigsegv; | 374 | goto give_sigsegv; |
368 | 375 | ||
369 | err = setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]); | 376 | err = setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]); |
370 | if (err) | 377 | if (err) |
371 | goto give_sigsegv; | 378 | goto give_sigsegv; |
372 | 379 | ||
@@ -427,8 +434,9 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
427 | void __user *restorer; | 434 | void __user *restorer; |
428 | int err = 0; | 435 | int err = 0; |
429 | int usig; | 436 | int usig; |
437 | struct _fpstate __user *fpstate = NULL; | ||
430 | 438 | ||
431 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 439 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
432 | 440 | ||
433 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 441 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
434 | goto give_sigsegv; | 442 | goto give_sigsegv; |
@@ -453,7 +461,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
453 | err |= __put_user(sas_ss_flags(regs->sp), | 461 | err |= __put_user(sas_ss_flags(regs->sp), |
454 | &frame->uc.uc_stack.ss_flags); | 462 | &frame->uc.uc_stack.ss_flags); |
455 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 463 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
456 | err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, | 464 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, |
457 | regs, set->sig[0]); | 465 | regs, set->sig[0]); |
458 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 466 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
459 | if (err) | 467 | if (err) |
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index ca316b5b742c..0deab8eff33f 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c | |||
@@ -281,7 +281,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
281 | struct task_struct *me = current; | 281 | struct task_struct *me = current; |
282 | 282 | ||
283 | if (used_math()) { | 283 | if (used_math()) { |
284 | fp = get_stack(ka, regs, sizeof(struct _fpstate)); | 284 | fp = get_stack(ka, regs, sig_xstate_size); |
285 | frame = (void __user *)round_down( | 285 | frame = (void __user *)round_down( |
286 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; | 286 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; |
287 | 287 | ||
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index c68b7c4ca249..7ad169e33528 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c | |||
@@ -17,6 +17,10 @@ unsigned int pcntxt_hmask, pcntxt_lmask; | |||
17 | */ | 17 | */ |
18 | struct xsave_struct *init_xstate_buf; | 18 | struct xsave_struct *init_xstate_buf; |
19 | 19 | ||
20 | #ifdef CONFIG_X86_64 | ||
21 | unsigned int sig_xstate_size = sizeof(struct _fpstate); | ||
22 | #endif | ||
23 | |||
20 | /* | 24 | /* |
21 | * Enable the extended processor state save/restore feature | 25 | * Enable the extended processor state save/restore feature |
22 | */ | 26 | */ |
diff --git a/include/asm-x86/i387.h b/include/asm-x86/i387.h index a6d256f4ac81..36dca8db1660 100644 --- a/include/asm-x86/i387.h +++ b/include/asm-x86/i387.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <asm/uaccess.h> | 20 | #include <asm/uaccess.h> |
21 | #include <asm/xsave.h> | 21 | #include <asm/xsave.h> |
22 | 22 | ||
23 | extern unsigned int sig_xstate_size; | ||
23 | extern void fpu_init(void); | 24 | extern void fpu_init(void); |
24 | extern void mxcsr_feature_mask_init(void); | 25 | extern void mxcsr_feature_mask_init(void); |
25 | extern int init_fpu(struct task_struct *child); | 26 | extern int init_fpu(struct task_struct *child); |
@@ -31,6 +32,7 @@ extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get; | |||
31 | extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set; | 32 | extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set; |
32 | 33 | ||
33 | #ifdef CONFIG_IA32_EMULATION | 34 | #ifdef CONFIG_IA32_EMULATION |
35 | extern unsigned int sig_xstate_ia32_size; | ||
34 | struct _fpstate_ia32; | 36 | struct _fpstate_ia32; |
35 | extern int save_i387_ia32(struct _fpstate_ia32 __user *buf); | 37 | extern int save_i387_ia32(struct _fpstate_ia32 __user *buf); |
36 | extern int restore_i387_ia32(struct _fpstate_ia32 __user *buf); | 38 | extern int restore_i387_ia32(struct _fpstate_ia32 __user *buf); |