• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <asm/xcr.h>
13 
14 /*
15  * Supported feature mask by the CPU and the kernel.
16  */
17 u64 pcntxt_mask;
18 
19 struct _fpx_sw_bytes fx_sw_reserved;
20 #ifdef CONFIG_IA32_EMULATION
21 struct _fpx_sw_bytes fx_sw_reserved_ia32;
22 #endif
23 
24 /*
25  * Check for the presence of extended state information in the
26  * user fpstate pointer in the sigcontext.
27  */
check_for_xstate(struct i387_fxsave_struct __user * buf,void __user * fpstate,struct _fpx_sw_bytes * fx_sw_user)28 int check_for_xstate(struct i387_fxsave_struct __user *buf,
29 		     void __user *fpstate,
30 		     struct _fpx_sw_bytes *fx_sw_user)
31 {
32 	int min_xstate_size = sizeof(struct i387_fxsave_struct) +
33 			      sizeof(struct xsave_hdr_struct);
34 	unsigned int magic2;
35 	int err;
36 
37 	err = __copy_from_user(fx_sw_user, &buf->sw_reserved[0],
38 			       sizeof(struct _fpx_sw_bytes));
39 
40 	if (err)
41 		return err;
42 
43 	/*
44 	 * First Magic check failed.
45 	 */
46 	if (fx_sw_user->magic1 != FP_XSTATE_MAGIC1)
47 		return -1;
48 
49 	/*
50 	 * Check for error scenarios.
51 	 */
52 	if (fx_sw_user->xstate_size < min_xstate_size ||
53 	    fx_sw_user->xstate_size > xstate_size ||
54 	    fx_sw_user->xstate_size > fx_sw_user->extended_size)
55 		return -1;
56 
57 	err = __get_user(magic2, (__u32 *) (((void *)fpstate) +
58 					    fx_sw_user->extended_size -
59 					    FP_XSTATE_MAGIC2_SIZE));
60 	/*
61 	 * Check for the presence of second magic word at the end of memory
62 	 * layout. This detects the case where the user just copied the legacy
63 	 * fpstate layout with out copying the extended state information
64 	 * in the memory layout.
65 	 */
66 	if (err || magic2 != FP_XSTATE_MAGIC2)
67 		return -1;
68 
69 	return 0;
70 }
71 
72 #ifdef CONFIG_X86_64
73 /*
74  * Signal frame handlers.
75  */
76 
save_i387_xstate(void __user * buf)77 int save_i387_xstate(void __user *buf)
78 {
79 	struct task_struct *tsk = current;
80 	int err = 0;
81 
82 	if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size))
83 		return -EACCES;
84 
85 	BUG_ON(sig_xstate_size < xstate_size);
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 		/*
95 	 	 * Start with clearing the user buffer. This will present a
96 	 	 * clean context for the bytes not touched by the fxsave/xsave.
97 		 */
98 		err = __clear_user(buf, sig_xstate_size);
99 		if (err)
100 			return err;
101 
102 		if (task_thread_info(tsk)->status & TS_XSAVE)
103 			err = xsave_user(buf);
104 		else
105 			err = fxsave_user(buf);
106 
107 		if (err)
108 			return err;
109 		task_thread_info(tsk)->status &= ~TS_USEDFPU;
110 		stts();
111 	} else {
112 		if (__copy_to_user(buf, &tsk->thread.xstate->fxsave,
113 				   xstate_size))
114 			return -1;
115 	}
116 
117 	if (task_thread_info(tsk)->status & TS_XSAVE) {
118 		struct _fpstate __user *fx = buf;
119 		struct _xstate __user *x = buf;
120 		u64 xstate_bv;
121 
122 		err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved,
123 				     sizeof(struct _fpx_sw_bytes));
124 
125 		err |= __put_user(FP_XSTATE_MAGIC2,
126 				  (__u32 __user *) (buf + sig_xstate_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;
153 	}
154 
155 	return 1;
156 }
157 
158 /*
159  * Restore the extended state if present. Otherwise, restore the FP/SSE
160  * state.
161  */
restore_user_xstate(void __user * buf)162 static int restore_user_xstate(void __user *buf)
163 {
164 	struct _fpx_sw_bytes fx_sw_user;
165 	u64 mask;
166 	int err;
167 
168 	if (((unsigned long)buf % 64) ||
169 	     check_for_xstate(buf, buf, &fx_sw_user))
170 		goto fx_only;
171 
172 	mask = fx_sw_user.xstate_bv;
173 
174 	/*
175 	 * restore the state passed by the user.
176 	 */
177 	err = xrestore_user(buf, mask);
178 	if (err)
179 		return err;
180 
181 	/*
182 	 * init the state skipped by the user.
183 	 */
184 	mask = pcntxt_mask & ~mask;
185 
186 	xrstor_state(init_xstate_buf, mask);
187 
188 	return 0;
189 
190 fx_only:
191 	/*
192 	 * couldn't find the extended state information in the
193 	 * memory layout. Restore just the FP/SSE and init all
194 	 * the other extended state.
195 	 */
196 	xrstor_state(init_xstate_buf, pcntxt_mask & ~XSTATE_FPSSE);
197 	return fxrstor_checking((__force struct i387_fxsave_struct *)buf);
198 }
199 
200 /*
201  * This restores directly out of user space. Exceptions are handled.
202  */
restore_i387_xstate(void __user * buf)203 int restore_i387_xstate(void __user *buf)
204 {
205 	struct task_struct *tsk = current;
206 	int err = 0;
207 
208 	if (!buf) {
209 		if (used_math())
210 			goto clear;
211 		return 0;
212 	} else
213 		if (!access_ok(VERIFY_READ, buf, sig_xstate_size))
214 			return -EACCES;
215 
216 	if (!used_math()) {
217 		err = init_fpu(tsk);
218 		if (err)
219 			return err;
220 	}
221 
222 	if (!(task_thread_info(current)->status & TS_USEDFPU)) {
223 		clts();
224 		task_thread_info(current)->status |= TS_USEDFPU;
225 	}
226 	if (task_thread_info(tsk)->status & TS_XSAVE)
227 		err = restore_user_xstate(buf);
228 	else
229 		err = fxrstor_checking((__force struct i387_fxsave_struct *)
230 				       buf);
231 	if (unlikely(err)) {
232 		/*
233 		 * Encountered an error while doing the restore from the
234 		 * user buffer, clear the fpu state.
235 		 */
236 clear:
237 		clear_fpu(tsk);
238 		clear_used_math();
239 	}
240 	return err;
241 }
242 #endif
243 
244 /*
245  * Prepare the SW reserved portion of the fxsave memory layout, indicating
246  * the presence of the extended state information in the memory layout
247  * pointed by the fpstate pointer in the sigcontext.
248  * This will be saved when ever the FP and extended state context is
249  * saved on the user stack during the signal handler delivery to the user.
250  */
prepare_fx_sw_frame(void)251 static void prepare_fx_sw_frame(void)
252 {
253 	int size_extended = (xstate_size - sizeof(struct i387_fxsave_struct)) +
254 			     FP_XSTATE_MAGIC2_SIZE;
255 
256 	sig_xstate_size = sizeof(struct _fpstate) + size_extended;
257 
258 #ifdef CONFIG_IA32_EMULATION
259 	sig_xstate_ia32_size = sizeof(struct _fpstate_ia32) + size_extended;
260 #endif
261 
262 	memset(&fx_sw_reserved, 0, sizeof(fx_sw_reserved));
263 
264 	fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
265 	fx_sw_reserved.extended_size = sig_xstate_size;
266 	fx_sw_reserved.xstate_bv = pcntxt_mask;
267 	fx_sw_reserved.xstate_size = xstate_size;
268 #ifdef CONFIG_IA32_EMULATION
269 	memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved,
270 	       sizeof(struct _fpx_sw_bytes));
271 	fx_sw_reserved_ia32.extended_size = sig_xstate_ia32_size;
272 #endif
273 }
274 
275 /*
276  * Represents init state for the supported extended state.
277  */
278 struct xsave_struct *init_xstate_buf;
279 
280 #ifdef CONFIG_X86_64
281 unsigned int sig_xstate_size = sizeof(struct _fpstate);
282 #endif
283 
284 /*
285  * Enable the extended processor state save/restore feature
286  */
xsave_init(void)287 void __cpuinit xsave_init(void)
288 {
289 	if (!cpu_has_xsave)
290 		return;
291 
292 	set_in_cr4(X86_CR4_OSXSAVE);
293 
294 	/*
295 	 * Enable all the features that the HW is capable of
296 	 * and the Linux kernel is aware of.
297 	 */
298 	xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
299 }
300 
301 /*
302  * setup the xstate image representing the init state
303  */
setup_xstate_init(void)304 static void __init setup_xstate_init(void)
305 {
306 	init_xstate_buf = alloc_bootmem(xstate_size);
307 	init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
308 }
309 
310 /*
311  * Enable and initialize the xsave feature.
312  */
xsave_cntxt_init(void)313 void __ref xsave_cntxt_init(void)
314 {
315 	unsigned int eax, ebx, ecx, edx;
316 
317 	cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
318 	pcntxt_mask = eax + ((u64)edx << 32);
319 
320 	if ((pcntxt_mask & XSTATE_FPSSE) != XSTATE_FPSSE) {
321 		printk(KERN_ERR "FP/SSE not shown under xsave features 0x%llx\n",
322 		       pcntxt_mask);
323 		BUG();
324 	}
325 
326 	/*
327 	 * for now OS knows only about FP/SSE
328 	 */
329 	pcntxt_mask = pcntxt_mask & XCNTXT_MASK;
330 	xsave_init();
331 
332 	/*
333 	 * Recompute the context size for enabled features
334 	 */
335 	cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
336 	xstate_size = ebx;
337 
338 	prepare_fx_sw_frame();
339 
340 	setup_xstate_init();
341 
342 	printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%llx, "
343 	       "cntxt size 0x%x\n",
344 	       pcntxt_mask, xstate_size);
345 }
346