]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/x86/kernel/xsave.c
dd66d0714c1820a17aae498e14b67aa746cbd65f
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / xsave.c
1 /*
2  * xsave/xrstor support.
3  *
4  * Author: Suresh Siddha <suresh.b.siddha@intel.com>
5  */
6 #include <linux/bootmem.h>
7 #include <linux/compat.h>
8 #include <asm/i387.h>
9 #ifdef CONFIG_IA32_EMULATION
10 #include <asm/sigcontext32.h>
11 #endif
12
13 /*
14  * Supported feature mask by the CPU and the kernel.
15  */
16 unsigned int pcntxt_hmask, pcntxt_lmask;
17
18 struct _fpx_sw_bytes fx_sw_reserved;
19 #ifdef CONFIG_IA32_EMULATION
20 struct _fpx_sw_bytes fx_sw_reserved_ia32;
21 #endif
22
23 /*
24  * Check for the presence of extended state information in the
25  * user fpstate pointer in the sigcontext.
26  */
27 int check_for_xstate(struct i387_fxsave_struct __user *buf,
28                      void __user *fpstate,
29                      struct _fpx_sw_bytes *fx_sw_user)
30 {
31         int min_xstate_size = sizeof(struct i387_fxsave_struct) +
32                               sizeof(struct xsave_hdr_struct);
33         unsigned int magic2;
34         int err;
35
36         err = __copy_from_user(fx_sw_user, &buf->sw_reserved[0],
37                                sizeof(struct _fpx_sw_bytes));
38
39         if (err)
40                 return err;
41
42         /*
43          * First Magic check failed.
44          */
45         if (fx_sw_user->magic1 != FP_XSTATE_MAGIC1)
46                 return -1;
47
48         /*
49          * Check for error scenarios.
50          */
51         if (fx_sw_user->xstate_size < min_xstate_size ||
52             fx_sw_user->xstate_size > xstate_size ||
53             fx_sw_user->xstate_size > fx_sw_user->extended_size)
54                 return -1;
55
56         err = __get_user(magic2, (__u32 *) (((void *)fpstate) +
57                                             fx_sw_user->extended_size -
58                                             FP_XSTATE_MAGIC2_SIZE));
59         /*
60          * Check for the presence of second magic word at the end of memory
61          * layout. This detects the case where the user just copied the legacy
62          * fpstate layout with out copying the extended state information
63          * in the memory layout.
64          */
65         if (err || magic2 != FP_XSTATE_MAGIC2)
66                 return -1;
67
68         return 0;
69 }
70
71 #ifdef CONFIG_X86_64
72 /*
73  * Signal frame handlers.
74  */
75
76 int save_i387_xstate(void __user *buf)
77 {
78         struct task_struct *tsk = current;
79         int err = 0;
80
81         if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size))
82                 return -EACCES;
83
84         BUILD_BUG_ON(sizeof(struct user_i387_struct) !=
85                         sizeof(tsk->thread.xstate->fxsave));
86
87         if ((unsigned long)buf % 64)
88                 printk("save_i387_xstate: bad fpstate %p\n", buf);
89
90         if (!used_math())
91                 return 0;
92         clear_used_math(); /* trigger finit */
93         if (task_thread_info(tsk)->status & TS_USEDFPU) {
94                 if (task_thread_info(tsk)->status & TS_XSAVE)
95                         err = xsave_user(buf);
96                 else
97                         err = fxsave_user(buf);
98
99                 if (err)
100                         return err;
101                 task_thread_info(tsk)->status &= ~TS_USEDFPU;
102                 stts();
103         } else {
104                 if (__copy_to_user(buf, &tsk->thread.xstate->fxsave,
105                                    xstate_size))
106                         return -1;
107         }
108
109         if (task_thread_info(tsk)->status & TS_XSAVE) {
110                 struct _fpstate __user *fx = buf;
111
112                 err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved,
113                                      sizeof(struct _fpx_sw_bytes));
114
115                 err |= __put_user(FP_XSTATE_MAGIC2,
116                                   (__u32 __user *) (buf + sig_xstate_size
117                                                     - FP_XSTATE_MAGIC2_SIZE));
118         }
119
120         return 1;
121 }
122
123 /*
124  * Restore the extended state if present. Otherwise, restore the FP/SSE
125  * state.
126  */
127 int restore_user_xstate(void __user *buf)
128 {
129         struct _fpx_sw_bytes fx_sw_user;
130         unsigned int lmask, hmask;
131         int err;
132
133         if (((unsigned long)buf % 64) ||
134              check_for_xstate(buf, buf, &fx_sw_user))
135                 goto fx_only;
136
137         lmask = fx_sw_user.xstate_bv;
138         hmask = fx_sw_user.xstate_bv >> 32;
139
140         /*
141          * restore the state passed by the user.
142          */
143         err = xrestore_user(buf, lmask, hmask);
144         if (err)
145                 return err;
146
147         /*
148          * init the state skipped by the user.
149          */
150         lmask = pcntxt_lmask & ~lmask;
151         hmask = pcntxt_hmask & ~hmask;
152
153         xrstor_state(init_xstate_buf, lmask, hmask);
154
155         return 0;
156
157 fx_only:
158         /*
159          * couldn't find the extended state information in the
160          * memory layout. Restore just the FP/SSE and init all
161          * the other extended state.
162          */
163         xrstor_state(init_xstate_buf, pcntxt_lmask & ~XSTATE_FPSSE,
164                      pcntxt_hmask);
165         return fxrstor_checking((__force struct i387_fxsave_struct *)buf);
166 }
167
168 /*
169  * This restores directly out of user space. Exceptions are handled.
170  */
171 int restore_i387_xstate(void __user *buf)
172 {
173         struct task_struct *tsk = current;
174         int err = 0;
175
176         if (!buf) {
177                 if (used_math())
178                         goto clear;
179                 return 0;
180         } else
181                 if (!access_ok(VERIFY_READ, buf, sig_xstate_size))
182                         return -EACCES;
183
184         if (!used_math()) {
185                 err = init_fpu(tsk);
186                 if (err)
187                         return err;
188         }
189
190         if (!(task_thread_info(current)->status & TS_USEDFPU)) {
191                 clts();
192                 task_thread_info(current)->status |= TS_USEDFPU;
193         }
194         if (task_thread_info(tsk)->status & TS_XSAVE)
195                 err = restore_user_xstate(buf);
196         else
197                 err = fxrstor_checking((__force struct i387_fxsave_struct *)
198                                        buf);
199         if (unlikely(err)) {
200                 /*
201                  * Encountered an error while doing the restore from the
202                  * user buffer, clear the fpu state.
203                  */
204 clear:
205                 clear_fpu(tsk);
206                 clear_used_math();
207         }
208         return err;
209 }
210 #endif
211
212 /*
213  * Prepare the SW reserved portion of the fxsave memory layout, indicating
214  * the presence of the extended state information in the memory layout
215  * pointed by the fpstate pointer in the sigcontext.
216  * This will be saved when ever the FP and extended state context is
217  * saved on the user stack during the signal handler delivery to the user.
218  */
219 void prepare_fx_sw_frame(void)
220 {
221         int size_extended = (xstate_size - sizeof(struct i387_fxsave_struct)) +
222                              FP_XSTATE_MAGIC2_SIZE;
223
224         sig_xstate_size = sizeof(struct _fpstate) + size_extended;
225
226 #ifdef CONFIG_IA32_EMULATION
227         sig_xstate_ia32_size = sizeof(struct _fpstate_ia32) + size_extended;
228 #endif
229
230         memset(&fx_sw_reserved, 0, sizeof(fx_sw_reserved));
231
232         fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
233         fx_sw_reserved.extended_size = sig_xstate_size;
234         fx_sw_reserved.xstate_bv = pcntxt_lmask |
235                                          (((u64) (pcntxt_hmask)) << 32);
236         fx_sw_reserved.xstate_size = xstate_size;
237 #ifdef CONFIG_IA32_EMULATION
238         memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved,
239                sizeof(struct _fpx_sw_bytes));
240         fx_sw_reserved_ia32.extended_size = sig_xstate_ia32_size;
241 #endif
242 }
243
244 /*
245  * Represents init state for the supported extended state.
246  */
247 struct xsave_struct *init_xstate_buf;
248
249 #ifdef CONFIG_X86_64
250 unsigned int sig_xstate_size = sizeof(struct _fpstate);
251 #endif
252
253 /*
254  * Enable the extended processor state save/restore feature
255  */
256 void __cpuinit xsave_init(void)
257 {
258         if (!cpu_has_xsave)
259                 return;
260
261         set_in_cr4(X86_CR4_OSXSAVE);
262
263         /*
264          * Enable all the features that the HW is capable of
265          * and the Linux kernel is aware of.
266          *
267          * xsetbv();
268          */
269         asm volatile(".byte 0x0f,0x01,0xd1" : : "c" (0),
270                      "a" (pcntxt_lmask), "d" (pcntxt_hmask));
271 }
272
273 /*
274  * setup the xstate image representing the init state
275  */
276 void setup_xstate_init(void)
277 {
278         init_xstate_buf = alloc_bootmem(xstate_size);
279         init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
280 }
281
282 /*
283  * Enable and initialize the xsave feature.
284  */
285 void __init xsave_cntxt_init(void)
286 {
287         unsigned int eax, ebx, ecx, edx;
288
289         cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
290
291         pcntxt_lmask = eax;
292         pcntxt_hmask = edx;
293
294         if ((pcntxt_lmask & XSTATE_FPSSE) != XSTATE_FPSSE) {
295                 printk(KERN_ERR "FP/SSE not shown under xsave features %x\n",
296                        pcntxt_lmask);
297                 BUG();
298         }
299
300         /*
301          * for now OS knows only about FP/SSE
302          */
303         pcntxt_lmask = pcntxt_lmask & XCNTXT_LMASK;
304         pcntxt_hmask = pcntxt_hmask & XCNTXT_HMASK;
305
306         xsave_init();
307
308         /*
309          * Recompute the context size for enabled features
310          */
311         cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
312
313         xstate_size = ebx;
314
315         prepare_fx_sw_frame();
316
317         setup_xstate_init();
318
319         printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%Lx, "
320                "cntxt size 0x%x\n",
321                (pcntxt_lmask | ((u64) pcntxt_hmask << 32)), xstate_size);
322 }