aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/xsave.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/xsave.c')
-rw-r--r--arch/x86/kernel/xsave.c172
1 files changed, 162 insertions, 10 deletions
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index 608e72d7ca64..dd66d0714c18 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -6,12 +6,68 @@
6#include <linux/bootmem.h> 6#include <linux/bootmem.h>
7#include <linux/compat.h> 7#include <linux/compat.h>
8#include <asm/i387.h> 8#include <asm/i387.h>
9#ifdef CONFIG_IA32_EMULATION
10#include <asm/sigcontext32.h>
11#endif
9 12
10/* 13/*
11 * Supported feature mask by the CPU and the kernel. 14 * Supported feature mask by the CPU and the kernel.
12 */ 15 */
13unsigned int pcntxt_hmask, pcntxt_lmask; 16unsigned int pcntxt_hmask, pcntxt_lmask;
14 17
18struct _fpx_sw_bytes fx_sw_reserved;
19#ifdef CONFIG_IA32_EMULATION
20struct _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 */
27int 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
15#ifdef CONFIG_X86_64 71#ifdef CONFIG_X86_64
16/* 72/*
17 * Signal frame handlers. 73 * Signal frame handlers.
@@ -28,15 +84,18 @@ int save_i387_xstate(void __user *buf)
28 BUILD_BUG_ON(sizeof(struct user_i387_struct) != 84 BUILD_BUG_ON(sizeof(struct user_i387_struct) !=
29 sizeof(tsk->thread.xstate->fxsave)); 85 sizeof(tsk->thread.xstate->fxsave));
30 86
31 if ((unsigned long)buf % 16) 87 if ((unsigned long)buf % 64)
32 printk("save_i387_xstate: bad fpstate %p\n", buf); 88 printk("save_i387_xstate: bad fpstate %p\n", buf);
33 89
34 if (!used_math()) 90 if (!used_math())
35 return 0; 91 return 0;
36 clear_used_math(); /* trigger finit */ 92 clear_used_math(); /* trigger finit */
37 if (task_thread_info(tsk)->status & TS_USEDFPU) { 93 if (task_thread_info(tsk)->status & TS_USEDFPU) {
38 err = save_i387_checking((struct i387_fxsave_struct __user *) 94 if (task_thread_info(tsk)->status & TS_XSAVE)
39 buf); 95 err = xsave_user(buf);
96 else
97 err = fxsave_user(buf);
98
40 if (err) 99 if (err)
41 return err; 100 return err;
42 task_thread_info(tsk)->status &= ~TS_USEDFPU; 101 task_thread_info(tsk)->status &= ~TS_USEDFPU;
@@ -46,23 +105,77 @@ int save_i387_xstate(void __user *buf)
46 xstate_size)) 105 xstate_size))
47 return -1; 106 return -1;
48 } 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
49 return 1; 120 return 1;
50} 121}
51 122
52/* 123/*
124 * Restore the extended state if present. Otherwise, restore the FP/SSE
125 * state.
126 */
127int 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
157fx_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/*
53 * This restores directly out of user space. Exceptions are handled. 169 * This restores directly out of user space. Exceptions are handled.
54 */ 170 */
55int restore_i387_xstate(void __user *buf) 171int restore_i387_xstate(void __user *buf)
56{ 172{
57 struct task_struct *tsk = current; 173 struct task_struct *tsk = current;
58 int err; 174 int err = 0;
59 175
60 if (!buf) { 176 if (!buf) {
61 if (used_math()) { 177 if (used_math())
62 clear_fpu(tsk); 178 goto clear;
63 clear_used_math();
64 }
65
66 return 0; 179 return 0;
67 } else 180 } else
68 if (!access_ok(VERIFY_READ, buf, sig_xstate_size)) 181 if (!access_ok(VERIFY_READ, buf, sig_xstate_size))
@@ -78,12 +191,17 @@ int restore_i387_xstate(void __user *buf)
78 clts(); 191 clts();
79 task_thread_info(current)->status |= TS_USEDFPU; 192 task_thread_info(current)->status |= TS_USEDFPU;
80 } 193 }
81 err = fxrstor_checking((__force struct i387_fxsave_struct *)buf); 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);
82 if (unlikely(err)) { 199 if (unlikely(err)) {
83 /* 200 /*
84 * Encountered an error while doing the restore from the 201 * Encountered an error while doing the restore from the
85 * user buffer, clear the fpu state. 202 * user buffer, clear the fpu state.
86 */ 203 */
204clear:
87 clear_fpu(tsk); 205 clear_fpu(tsk);
88 clear_used_math(); 206 clear_used_math();
89 } 207 }
@@ -92,6 +210,38 @@ int restore_i387_xstate(void __user *buf)
92#endif 210#endif
93 211
94/* 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 */
219void 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/*
95 * Represents init state for the supported extended state. 245 * Represents init state for the supported extended state.
96 */ 246 */
97struct xsave_struct *init_xstate_buf; 247struct xsave_struct *init_xstate_buf;
@@ -162,6 +312,8 @@ void __init xsave_cntxt_init(void)
162 312
163 xstate_size = ebx; 313 xstate_size = ebx;
164 314
315 prepare_fx_sw_frame();
316
165 setup_xstate_init(); 317 setup_xstate_init();
166 318
167 printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%Lx, " 319 printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%Lx, "