Commit 3c1c7f10 authored by Suresh Siddha's avatar Suresh Siddha Committed by Ingo Molnar

x86, xsave: dynamically allocate sigframes fpstate instead of static allocation

dynamically allocate fpstate on the stack, instead of static allocation
in the current sigframe layout on the user stack. This will allow the
fpstate structure to grow in the future, which includes extended state
information supporting xsave/xrstor.

signal handlers will be able to access the fpstate pointer from the
sigcontext structure asusual, with no change. For the non RT sigframe's
(which are supported only for 32bit apps), current static fpstate layout
in the sigframe will be unused(so that we don't change the extramask[]
offset in the sigframe and thus prevent breaking app's which modify
extramask[]).
Signed-off-by: default avatarSuresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: default avatarH. Peter Anvin <hpa@zytor.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent b359e8a4
...@@ -179,9 +179,10 @@ struct sigframe ...@@ -179,9 +179,10 @@ struct sigframe
u32 pretcode; u32 pretcode;
int sig; int sig;
struct sigcontext_ia32 sc; struct sigcontext_ia32 sc;
struct _fpstate_ia32 fpstate; struct _fpstate_ia32 fpstate_unused; /* look at kernel/sigframe.h */
unsigned int extramask[_COMPAT_NSIG_WORDS-1]; unsigned int extramask[_COMPAT_NSIG_WORDS-1];
char retcode[8]; char retcode[8];
/* fp state follows here */
}; };
struct rt_sigframe struct rt_sigframe
...@@ -192,8 +193,8 @@ struct rt_sigframe ...@@ -192,8 +193,8 @@ struct rt_sigframe
u32 puc; u32 puc;
compat_siginfo_t info; compat_siginfo_t info;
struct ucontext_ia32 uc; struct ucontext_ia32 uc;
struct _fpstate_ia32 fpstate;
char retcode[8]; char retcode[8];
/* fp state follows here */
}; };
#define COPY(x) { \ #define COPY(x) { \
...@@ -402,7 +403,8 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, ...@@ -402,7 +403,8 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
* Determine which stack to use.. * Determine which stack to use..
*/ */
static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
size_t frame_size) size_t frame_size,
struct _fpstate_ia32 **fpstate)
{ {
unsigned long sp; unsigned long sp;
...@@ -421,6 +423,11 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, ...@@ -421,6 +423,11 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
ka->sa.sa_restorer) ka->sa.sa_restorer)
sp = (unsigned long) ka->sa.sa_restorer; sp = (unsigned long) ka->sa.sa_restorer;
if (used_math()) {
sp = sp - sig_xstate_ia32_size;
*fpstate = (struct _fpstate_ia32 *) sp;
}
sp -= frame_size; sp -= frame_size;
/* Align the stack pointer according to the i386 ABI, /* Align the stack pointer according to the i386 ABI,
* i.e. so that on function entry ((sp + 4) & 15) == 0. */ * 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,6 +441,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
struct sigframe __user *frame; struct sigframe __user *frame;
void __user *restorer; void __user *restorer;
int err = 0; int err = 0;
struct _fpstate_ia32 __user *fpstate = NULL;
/* copy_to_user optimizes that into a single 8 byte store */ /* copy_to_user optimizes that into a single 8 byte store */
static const struct { static const struct {
...@@ -448,7 +456,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, ...@@ -448,7 +456,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
0, 0,
}; };
frame = get_sigframe(ka, regs, sizeof(*frame)); frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv; goto give_sigsegv;
...@@ -457,8 +465,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, ...@@ -457,8 +465,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
if (err) if (err)
goto give_sigsegv; goto give_sigsegv;
err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs, err |= ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]);
set->sig[0]);
if (err) if (err)
goto give_sigsegv; goto give_sigsegv;
...@@ -522,6 +529,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -522,6 +529,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
struct rt_sigframe __user *frame; struct rt_sigframe __user *frame;
void __user *restorer; void __user *restorer;
int err = 0; int err = 0;
struct _fpstate_ia32 __user *fpstate = NULL;
/* __copy_to_user optimizes that into a single 8 byte store */ /* __copy_to_user optimizes that into a single 8 byte store */
static const struct { static const struct {
...@@ -537,7 +545,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -537,7 +545,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
0, 0,
}; };
frame = get_sigframe(ka, regs, sizeof(*frame)); frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv; goto give_sigsegv;
...@@ -556,7 +564,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -556,7 +564,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(sas_ss_flags(regs->sp), err |= __put_user(sas_ss_flags(regs->sp),
&frame->uc.uc_stack.ss_flags); &frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
regs, set->sig[0]); regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err) if (err)
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
# define save_i387_ia32 save_i387 # define save_i387_ia32 save_i387
# define restore_i387_ia32 restore_i387 # define restore_i387_ia32 restore_i387
# define _fpstate_ia32 _fpstate # define _fpstate_ia32 _fpstate
# define sig_xstate_ia32_size sig_xstate_size
# define user_i387_ia32_struct user_i387_struct # define user_i387_ia32_struct user_i387_struct
# define user32_fxsr_struct user_fxsr_struct # define user32_fxsr_struct user_fxsr_struct
#endif #endif
...@@ -36,6 +37,7 @@ ...@@ -36,6 +37,7 @@
static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
unsigned int xstate_size; unsigned int xstate_size;
unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32);
static struct i387_fxsave_struct fx_scratch __cpuinitdata; static struct i387_fxsave_struct fx_scratch __cpuinitdata;
void __cpuinit mxcsr_feature_mask_init(void) void __cpuinit mxcsr_feature_mask_init(void)
......
...@@ -3,9 +3,18 @@ struct sigframe { ...@@ -3,9 +3,18 @@ struct sigframe {
char __user *pretcode; char __user *pretcode;
int sig; int sig;
struct sigcontext sc; struct sigcontext sc;
struct _fpstate fpstate; /*
* fpstate is unused. fpstate is moved/allocated after
* retcode[] below. This movement allows to have the FP state and the
* future state extensions (xsave) stay together.
* And at the same time retaining the unused fpstate, prevents changing
* the offset of extramask[] in the sigframe and thus prevent any
* legacy application accessing/modifying it.
*/
struct _fpstate fpstate_unused;
unsigned long extramask[_NSIG_WORDS-1]; unsigned long extramask[_NSIG_WORDS-1];
char retcode[8]; char retcode[8];
/* fp state follows here */
}; };
struct rt_sigframe { struct rt_sigframe {
...@@ -15,13 +24,14 @@ struct rt_sigframe { ...@@ -15,13 +24,14 @@ struct rt_sigframe {
void __user *puc; void __user *puc;
struct siginfo info; struct siginfo info;
struct ucontext uc; struct ucontext uc;
struct _fpstate fpstate;
char retcode[8]; char retcode[8];
/* fp state follows here */
}; };
#else #else
struct rt_sigframe { struct rt_sigframe {
char __user *pretcode; char __user *pretcode;
struct ucontext uc; struct ucontext uc;
struct siginfo info; struct siginfo info;
/* fp state follows here */
}; };
#endif #endif
...@@ -306,7 +306,8 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, ...@@ -306,7 +306,8 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
* Determine which stack to use.. * Determine which stack to use..
*/ */
static inline void __user * static inline void __user *
get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
struct _fpstate **fpstate)
{ {
unsigned long sp; unsigned long sp;
...@@ -332,6 +333,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) ...@@ -332,6 +333,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
sp = (unsigned long) ka->sa.sa_restorer; sp = (unsigned long) ka->sa.sa_restorer;
} }
if (used_math()) {
sp = sp - sig_xstate_size;
*fpstate = (struct _fpstate *) sp;
}
sp -= frame_size; sp -= frame_size;
/* /*
* Align the stack pointer according to the i386 ABI, * 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,8 +356,9 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
void __user *restorer; void __user *restorer;
int err = 0; int err = 0;
int usig; int usig;
struct _fpstate __user *fpstate = NULL;
frame = get_sigframe(ka, regs, sizeof(*frame)); frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv; goto give_sigsegv;
...@@ -366,7 +373,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, ...@@ -366,7 +373,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
if (err) if (err)
goto give_sigsegv; goto give_sigsegv;
err = setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]); err = setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]);
if (err) if (err)
goto give_sigsegv; goto give_sigsegv;
...@@ -427,8 +434,9 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -427,8 +434,9 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
void __user *restorer; void __user *restorer;
int err = 0; int err = 0;
int usig; int usig;
struct _fpstate __user *fpstate = NULL;
frame = get_sigframe(ka, regs, sizeof(*frame)); frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv; goto give_sigsegv;
...@@ -453,7 +461,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -453,7 +461,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(sas_ss_flags(regs->sp), err |= __put_user(sas_ss_flags(regs->sp),
&frame->uc.uc_stack.ss_flags); &frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
regs, set->sig[0]); regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err) if (err)
......
...@@ -281,7 +281,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -281,7 +281,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
struct task_struct *me = current; struct task_struct *me = current;
if (used_math()) { if (used_math()) {
fp = get_stack(ka, regs, sizeof(struct _fpstate)); fp = get_stack(ka, regs, sig_xstate_size);
frame = (void __user *)round_down( frame = (void __user *)round_down(
(unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
......
...@@ -17,6 +17,10 @@ unsigned int pcntxt_hmask, pcntxt_lmask; ...@@ -17,6 +17,10 @@ unsigned int pcntxt_hmask, pcntxt_lmask;
*/ */
struct xsave_struct *init_xstate_buf; struct xsave_struct *init_xstate_buf;
#ifdef CONFIG_X86_64
unsigned int sig_xstate_size = sizeof(struct _fpstate);
#endif
/* /*
* Enable the extended processor state save/restore feature * Enable the extended processor state save/restore feature
*/ */
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/xsave.h> #include <asm/xsave.h>
extern unsigned int sig_xstate_size;
extern void fpu_init(void); extern void fpu_init(void);
extern void mxcsr_feature_mask_init(void); extern void mxcsr_feature_mask_init(void);
extern int init_fpu(struct task_struct *child); 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,6 +32,7 @@ extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get;
extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set; extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set;
#ifdef CONFIG_IA32_EMULATION #ifdef CONFIG_IA32_EMULATION
extern unsigned int sig_xstate_ia32_size;
struct _fpstate_ia32; struct _fpstate_ia32;
extern int save_i387_ia32(struct _fpstate_ia32 __user *buf); extern int save_i387_ia32(struct _fpstate_ia32 __user *buf);
extern int restore_i387_ia32(struct _fpstate_ia32 __user *buf); extern int restore_i387_ia32(struct _fpstate_ia32 __user *buf);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment