diff options
Diffstat (limited to 'arch/x86/kernel/xsave.c')
-rw-r--r-- | arch/x86/kernel/xsave.c | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index 07713d64debe..9abac8a9d823 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c | |||
@@ -95,7 +95,9 @@ int save_i387_xstate(void __user *buf) | |||
95 | * Start with clearing the user buffer. This will present a | 95 | * Start with clearing the user buffer. This will present a |
96 | * clean context for the bytes not touched by the fxsave/xsave. | 96 | * clean context for the bytes not touched by the fxsave/xsave. |
97 | */ | 97 | */ |
98 | __clear_user(buf, sig_xstate_size); | 98 | err = __clear_user(buf, sig_xstate_size); |
99 | if (err) | ||
100 | return err; | ||
99 | 101 | ||
100 | if (task_thread_info(tsk)->status & TS_XSAVE) | 102 | if (task_thread_info(tsk)->status & TS_XSAVE) |
101 | err = xsave_user(buf); | 103 | err = xsave_user(buf); |
@@ -114,6 +116,8 @@ int save_i387_xstate(void __user *buf) | |||
114 | 116 | ||
115 | if (task_thread_info(tsk)->status & TS_XSAVE) { | 117 | if (task_thread_info(tsk)->status & TS_XSAVE) { |
116 | struct _fpstate __user *fx = buf; | 118 | struct _fpstate __user *fx = buf; |
119 | struct _xstate __user *x = buf; | ||
120 | u64 xstate_bv; | ||
117 | 121 | ||
118 | err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved, | 122 | err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved, |
119 | sizeof(struct _fpx_sw_bytes)); | 123 | sizeof(struct _fpx_sw_bytes)); |
@@ -121,6 +125,31 @@ int save_i387_xstate(void __user *buf) | |||
121 | err |= __put_user(FP_XSTATE_MAGIC2, | 125 | err |= __put_user(FP_XSTATE_MAGIC2, |
122 | (__u32 __user *) (buf + sig_xstate_size | 126 | (__u32 __user *) (buf + sig_xstate_size |
123 | - FP_XSTATE_MAGIC2_SIZE)); | 127 | - FP_XSTATE_MAGIC2_SIZE)); |
128 | |||
129 | /* | ||
130 | * Read the xstate_bv which we copied (directly from the cpu or | ||
131 | * from the state in task struct) to the user buffers and | ||
132 | * set the FP/SSE bits. | ||
133 | */ | ||
134 | err |= __get_user(xstate_bv, &x->xstate_hdr.xstate_bv); | ||
135 | |||
136 | /* | ||
137 | * For legacy compatible, we always set FP/SSE bits in the bit | ||
138 | * vector while saving the state to the user context. This will | ||
139 | * enable us capturing any changes(during sigreturn) to | ||
140 | * the FP/SSE bits by the legacy applications which don't touch | ||
141 | * xstate_bv in the xsave header. | ||
142 | * | ||
143 | * xsave aware apps can change the xstate_bv in the xsave | ||
144 | * header as well as change any contents in the memory layout. | ||
145 | * xrestore as part of sigreturn will capture all the changes. | ||
146 | */ | ||
147 | xstate_bv |= XSTATE_FPSSE; | ||
148 | |||
149 | err |= __put_user(xstate_bv, &x->xstate_hdr.xstate_bv); | ||
150 | |||
151 | if (err) | ||
152 | return err; | ||
124 | } | 153 | } |
125 | 154 | ||
126 | return 1; | 155 | return 1; |
@@ -272,7 +301,7 @@ void __cpuinit xsave_init(void) | |||
272 | /* | 301 | /* |
273 | * setup the xstate image representing the init state | 302 | * setup the xstate image representing the init state |
274 | */ | 303 | */ |
275 | void setup_xstate_init(void) | 304 | static void __init setup_xstate_init(void) |
276 | { | 305 | { |
277 | init_xstate_buf = alloc_bootmem(xstate_size); | 306 | init_xstate_buf = alloc_bootmem(xstate_size); |
278 | init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT; | 307 | init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT; |