Blame view

arch/x86/kernel/xsave.c 11.1 KB
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
1
2
3
4
5
6
7
8
  /*
   * xsave/xrstor support.
   *
   * Author: Suresh Siddha <suresh.b.siddha@intel.com>
   */
  #include <linux/bootmem.h>
  #include <linux/compat.h>
  #include <asm/i387.h>
c37b5efea   Suresh Siddha   x86, xsave: save/...
9
10
11
  #ifdef CONFIG_IA32_EMULATION
  #include <asm/sigcontext32.h>
  #endif
6152e4b1c   H. Peter Anvin   x86, xsave: keep ...
12
  #include <asm/xcr.h>
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
13
14
15
16
  
  /*
   * Supported feature mask by the CPU and the kernel.
   */
6152e4b1c   H. Peter Anvin   x86, xsave: keep ...
17
  u64 pcntxt_mask;
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
18

45c2d7f46   Robert Richter   x86, xsave: Make ...
19
20
21
22
  /*
   * Represents init state for the supported extended state.
   */
  static struct xsave_struct *init_xstate_buf;
c37b5efea   Suresh Siddha   x86, xsave: save/...
23
24
25
26
  struct _fpx_sw_bytes fx_sw_reserved;
  #ifdef CONFIG_IA32_EMULATION
  struct _fpx_sw_bytes fx_sw_reserved_ia32;
  #endif
a1488f8bf   Suresh Siddha   x86, xsave: Track...
27
  static unsigned int *xstate_offsets, *xstate_sizes, xstate_features;
c37b5efea   Suresh Siddha   x86, xsave: save/...
28
  /*
29104e101   Suresh Siddha   x86, xsave: Sync ...
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
   * If a processor implementation discern that a processor state component is
   * in its initialized state it may modify the corresponding bit in the
   * xsave_hdr.xstate_bv as '0', with out modifying the corresponding memory
   * layout in the case of xsaveopt. While presenting the xstate information to
   * the user, we always ensure that the memory layout of a feature will be in
   * the init state if the corresponding header bit is zero. This is to ensure
   * that the user doesn't see some stale state in the memory layout during
   * signal handling, debugging etc.
   */
  void __sanitize_i387_state(struct task_struct *tsk)
  {
  	u64 xstate_bv;
  	int feature_bit = 0x2;
  	struct i387_fxsave_struct *fx = &tsk->thread.fpu.state->fxsave;
  
  	if (!fx)
  		return;
  
  	BUG_ON(task_thread_info(tsk)->status & TS_USEDFPU);
  
  	xstate_bv = tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv;
  
  	/*
  	 * None of the feature bits are in init state. So nothing else
0d2eb44f6   Lucas De Marchi   x86: Fix common m...
53
  	 * to do for us, as the memory layout is up to date.
29104e101   Suresh Siddha   x86, xsave: Sync ...
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  	 */
  	if ((xstate_bv & pcntxt_mask) == pcntxt_mask)
  		return;
  
  	/*
  	 * FP is in init state
  	 */
  	if (!(xstate_bv & XSTATE_FP)) {
  		fx->cwd = 0x37f;
  		fx->swd = 0;
  		fx->twd = 0;
  		fx->fop = 0;
  		fx->rip = 0;
  		fx->rdp = 0;
  		memset(&fx->st_space[0], 0, 128);
  	}
  
  	/*
  	 * SSE is in init state
  	 */
  	if (!(xstate_bv & XSTATE_SSE))
  		memset(&fx->xmm_space[0], 0, 256);
  
  	xstate_bv = (pcntxt_mask & ~xstate_bv) >> 2;
  
  	/*
  	 * Update all the other memory layouts for which the corresponding
  	 * header bit is in the init state.
  	 */
  	while (xstate_bv) {
  		if (xstate_bv & 0x1) {
  			int offset = xstate_offsets[feature_bit];
  			int size = xstate_sizes[feature_bit];
  
  			memcpy(((void *) fx) + offset,
  			       ((void *) init_xstate_buf) + offset,
  			       size);
  		}
  
  		xstate_bv >>= 1;
  		feature_bit++;
  	}
  }
c37b5efea   Suresh Siddha   x86, xsave: save/...
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  /*
   * Check for the presence of extended state information in the
   * user fpstate pointer in the sigcontext.
   */
  int check_for_xstate(struct i387_fxsave_struct __user *buf,
  		     void __user *fpstate,
  		     struct _fpx_sw_bytes *fx_sw_user)
  {
  	int min_xstate_size = sizeof(struct i387_fxsave_struct) +
  			      sizeof(struct xsave_hdr_struct);
  	unsigned int magic2;
  	int err;
  
  	err = __copy_from_user(fx_sw_user, &buf->sw_reserved[0],
  			       sizeof(struct _fpx_sw_bytes));
c37b5efea   Suresh Siddha   x86, xsave: save/...
112
  	if (err)
d6d4d4205   Dan Carpenter   x86, xsave: Clean...
113
  		return -EFAULT;
c37b5efea   Suresh Siddha   x86, xsave: save/...
114
115
116
117
118
  
  	/*
  	 * First Magic check failed.
  	 */
  	if (fx_sw_user->magic1 != FP_XSTATE_MAGIC1)
d6d4d4205   Dan Carpenter   x86, xsave: Clean...
119
  		return -EINVAL;
c37b5efea   Suresh Siddha   x86, xsave: save/...
120
121
122
123
124
125
126
  
  	/*
  	 * Check for error scenarios.
  	 */
  	if (fx_sw_user->xstate_size < min_xstate_size ||
  	    fx_sw_user->xstate_size > xstate_size ||
  	    fx_sw_user->xstate_size > fx_sw_user->extended_size)
d6d4d4205   Dan Carpenter   x86, xsave: Clean...
127
  		return -EINVAL;
c37b5efea   Suresh Siddha   x86, xsave: save/...
128
129
130
131
  
  	err = __get_user(magic2, (__u32 *) (((void *)fpstate) +
  					    fx_sw_user->extended_size -
  					    FP_XSTATE_MAGIC2_SIZE));
d6d4d4205   Dan Carpenter   x86, xsave: Clean...
132
133
  	if (err)
  		return err;
c37b5efea   Suresh Siddha   x86, xsave: save/...
134
135
136
137
138
139
  	/*
  	 * Check for the presence of second magic word at the end of memory
  	 * layout. This detects the case where the user just copied the legacy
  	 * fpstate layout with out copying the extended state information
  	 * in the memory layout.
  	 */
d6d4d4205   Dan Carpenter   x86, xsave: Clean...
140
141
  	if (magic2 != FP_XSTATE_MAGIC2)
  		return -EFAULT;
c37b5efea   Suresh Siddha   x86, xsave: save/...
142
143
144
  
  	return 0;
  }
ab5137015   Suresh Siddha   x86, xsave: reorg...
145
146
147
148
149
150
151
152
153
154
155
156
  #ifdef CONFIG_X86_64
  /*
   * Signal frame handlers.
   */
  
  int save_i387_xstate(void __user *buf)
  {
  	struct task_struct *tsk = current;
  	int err = 0;
  
  	if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size))
  		return -EACCES;
f65bc214e   Suresh Siddha   x86, xsave: use B...
157
  	BUG_ON(sig_xstate_size < xstate_size);
ab5137015   Suresh Siddha   x86, xsave: reorg...
158

c37b5efea   Suresh Siddha   x86, xsave: save/...
159
  	if ((unsigned long)buf % 64)
ab5137015   Suresh Siddha   x86, xsave: reorg...
160
161
162
163
164
  		printk("save_i387_xstate: bad fpstate %p
  ", buf);
  
  	if (!used_math())
  		return 0;
06c38d5e3   Suresh Siddha   x86-64: fix FPU c...
165

ab5137015   Suresh Siddha   x86, xsave: reorg...
166
  	if (task_thread_info(tsk)->status & TS_USEDFPU) {
c9ad48828   Avi Kivity   x86: Eliminate TS...
167
  		if (use_xsave())
c37b5efea   Suresh Siddha   x86, xsave: save/...
168
169
170
  			err = xsave_user(buf);
  		else
  			err = fxsave_user(buf);
ab5137015   Suresh Siddha   x86, xsave: reorg...
171
172
173
174
175
  		if (err)
  			return err;
  		task_thread_info(tsk)->status &= ~TS_USEDFPU;
  		stts();
  	} else {
29104e101   Suresh Siddha   x86, xsave: Sync ...
176
  		sanitize_i387_state(tsk);
866032833   Avi Kivity   x86: Introduce 's...
177
  		if (__copy_to_user(buf, &tsk->thread.fpu.state->fxsave,
ab5137015   Suresh Siddha   x86, xsave: reorg...
178
179
180
  				   xstate_size))
  			return -1;
  	}
c37b5efea   Suresh Siddha   x86, xsave: save/...
181

06c38d5e3   Suresh Siddha   x86-64: fix FPU c...
182
  	clear_used_math(); /* trigger finit */
c9ad48828   Avi Kivity   x86: Eliminate TS...
183
  	if (use_xsave()) {
c37b5efea   Suresh Siddha   x86, xsave: save/...
184
  		struct _fpstate __user *fx = buf;
04944b793   Suresh Siddha   x86: xsave: set F...
185
186
  		struct _xstate __user *x = buf;
  		u64 xstate_bv;
c37b5efea   Suresh Siddha   x86, xsave: save/...
187
188
189
190
191
192
193
  
  		err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved,
  				     sizeof(struct _fpx_sw_bytes));
  
  		err |= __put_user(FP_XSTATE_MAGIC2,
  				  (__u32 __user *) (buf + sig_xstate_size
  						    - FP_XSTATE_MAGIC2_SIZE));
04944b793   Suresh Siddha   x86: xsave: set F...
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
  
  		/*
  		 * Read the xstate_bv which we copied (directly from the cpu or
  		 * from the state in task struct) to the user buffers and
  		 * set the FP/SSE bits.
  		 */
  		err |= __get_user(xstate_bv, &x->xstate_hdr.xstate_bv);
  
  		/*
  		 * For legacy compatible, we always set FP/SSE bits in the bit
  		 * vector while saving the state to the user context. This will
  		 * enable us capturing any changes(during sigreturn) to
  		 * the FP/SSE bits by the legacy applications which don't touch
  		 * xstate_bv in the xsave header.
  		 *
  		 * xsave aware apps can change the xstate_bv in the xsave
  		 * header as well as change any contents in the memory layout.
  		 * xrestore as part of sigreturn will capture all the changes.
  		 */
  		xstate_bv |= XSTATE_FPSSE;
  
  		err |= __put_user(xstate_bv, &x->xstate_hdr.xstate_bv);
f364eadab   Suresh Siddha   x86: xsave: fix e...
216
217
  		if (err)
  			return err;
c37b5efea   Suresh Siddha   x86, xsave: save/...
218
  	}
ab5137015   Suresh Siddha   x86, xsave: reorg...
219
220
221
222
  	return 1;
  }
  
  /*
c37b5efea   Suresh Siddha   x86, xsave: save/...
223
224
225
   * Restore the extended state if present. Otherwise, restore the FP/SSE
   * state.
   */
7820b7564   Jaswinder Singh Rajput   x86: xsave.c: res...
226
  static int restore_user_xstate(void __user *buf)
c37b5efea   Suresh Siddha   x86, xsave: save/...
227
228
  {
  	struct _fpx_sw_bytes fx_sw_user;
6152e4b1c   H. Peter Anvin   x86, xsave: keep ...
229
  	u64 mask;
c37b5efea   Suresh Siddha   x86, xsave: save/...
230
231
232
233
234
  	int err;
  
  	if (((unsigned long)buf % 64) ||
  	     check_for_xstate(buf, buf, &fx_sw_user))
  		goto fx_only;
6152e4b1c   H. Peter Anvin   x86, xsave: keep ...
235
  	mask = fx_sw_user.xstate_bv;
c37b5efea   Suresh Siddha   x86, xsave: save/...
236
237
238
239
  
  	/*
  	 * restore the state passed by the user.
  	 */
6152e4b1c   H. Peter Anvin   x86, xsave: keep ...
240
  	err = xrestore_user(buf, mask);
c37b5efea   Suresh Siddha   x86, xsave: save/...
241
242
243
244
245
246
  	if (err)
  		return err;
  
  	/*
  	 * init the state skipped by the user.
  	 */
6152e4b1c   H. Peter Anvin   x86, xsave: keep ...
247
  	mask = pcntxt_mask & ~mask;
8e221b6db   Suresh Siddha   x86: Avoid unnece...
248
249
  	if (unlikely(mask))
  		xrstor_state(init_xstate_buf, mask);
c37b5efea   Suresh Siddha   x86, xsave: save/...
250
251
252
253
254
255
256
257
258
  
  	return 0;
  
  fx_only:
  	/*
  	 * couldn't find the extended state information in the
  	 * memory layout. Restore just the FP/SSE and init all
  	 * the other extended state.
  	 */
6152e4b1c   H. Peter Anvin   x86, xsave: keep ...
259
  	xrstor_state(init_xstate_buf, pcntxt_mask & ~XSTATE_FPSSE);
c37b5efea   Suresh Siddha   x86, xsave: save/...
260
261
262
263
  	return fxrstor_checking((__force struct i387_fxsave_struct *)buf);
  }
  
  /*
ab5137015   Suresh Siddha   x86, xsave: reorg...
264
265
266
267
268
   * This restores directly out of user space. Exceptions are handled.
   */
  int restore_i387_xstate(void __user *buf)
  {
  	struct task_struct *tsk = current;
c37b5efea   Suresh Siddha   x86, xsave: save/...
269
  	int err = 0;
ab5137015   Suresh Siddha   x86, xsave: reorg...
270
271
  
  	if (!buf) {
c37b5efea   Suresh Siddha   x86, xsave: save/...
272
273
  		if (used_math())
  			goto clear;
ab5137015   Suresh Siddha   x86, xsave: reorg...
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
  		return 0;
  	} else
  		if (!access_ok(VERIFY_READ, buf, sig_xstate_size))
  			return -EACCES;
  
  	if (!used_math()) {
  		err = init_fpu(tsk);
  		if (err)
  			return err;
  	}
  
  	if (!(task_thread_info(current)->status & TS_USEDFPU)) {
  		clts();
  		task_thread_info(current)->status |= TS_USEDFPU;
  	}
c9ad48828   Avi Kivity   x86: Eliminate TS...
289
  	if (use_xsave())
c37b5efea   Suresh Siddha   x86, xsave: save/...
290
291
292
293
  		err = restore_user_xstate(buf);
  	else
  		err = fxrstor_checking((__force struct i387_fxsave_struct *)
  				       buf);
ab5137015   Suresh Siddha   x86, xsave: reorg...
294
295
296
297
298
  	if (unlikely(err)) {
  		/*
  		 * Encountered an error while doing the restore from the
  		 * user buffer, clear the fpu state.
  		 */
c37b5efea   Suresh Siddha   x86, xsave: save/...
299
  clear:
ab5137015   Suresh Siddha   x86, xsave: reorg...
300
301
302
303
304
305
  		clear_fpu(tsk);
  		clear_used_math();
  	}
  	return err;
  }
  #endif
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
306
  /*
c37b5efea   Suresh Siddha   x86, xsave: save/...
307
308
309
310
311
312
   * Prepare the SW reserved portion of the fxsave memory layout, indicating
   * the presence of the extended state information in the memory layout
   * pointed by the fpstate pointer in the sigcontext.
   * This will be saved when ever the FP and extended state context is
   * saved on the user stack during the signal handler delivery to the user.
   */
8bcad30f2   roel kluin   x86: make variabl...
313
  static void prepare_fx_sw_frame(void)
c37b5efea   Suresh Siddha   x86, xsave: save/...
314
315
316
317
318
319
320
321
322
323
324
325
326
327
  {
  	int size_extended = (xstate_size - sizeof(struct i387_fxsave_struct)) +
  			     FP_XSTATE_MAGIC2_SIZE;
  
  	sig_xstate_size = sizeof(struct _fpstate) + size_extended;
  
  #ifdef CONFIG_IA32_EMULATION
  	sig_xstate_ia32_size = sizeof(struct _fpstate_ia32) + size_extended;
  #endif
  
  	memset(&fx_sw_reserved, 0, sizeof(fx_sw_reserved));
  
  	fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
  	fx_sw_reserved.extended_size = sig_xstate_size;
6152e4b1c   H. Peter Anvin   x86, xsave: keep ...
328
  	fx_sw_reserved.xstate_bv = pcntxt_mask;
c37b5efea   Suresh Siddha   x86, xsave: save/...
329
330
331
332
333
334
335
  	fx_sw_reserved.xstate_size = xstate_size;
  #ifdef CONFIG_IA32_EMULATION
  	memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved,
  	       sizeof(struct _fpx_sw_bytes));
  	fx_sw_reserved_ia32.extended_size = sig_xstate_ia32_size;
  #endif
  }
3c1c7f101   Suresh Siddha   x86, xsave: dynam...
336
337
338
  #ifdef CONFIG_X86_64
  unsigned int sig_xstate_size = sizeof(struct _fpstate);
  #endif
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
339
340
341
  /*
   * Enable the extended processor state save/restore feature
   */
1cff92d8f   H. Peter Anvin   x86, xsave: Make ...
342
  static inline void xstate_enable(void)
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
343
  {
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
344
  	set_in_cr4(X86_CR4_OSXSAVE);
6152e4b1c   H. Peter Anvin   x86, xsave: keep ...
345
  	xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
346
347
348
  }
  
  /*
a1488f8bf   Suresh Siddha   x86, xsave: Track...
349
350
351
   * Record the offsets and sizes of different state managed by the xsave
   * memory layout.
   */
4995b9dba   Robert Richter   x86, xsave: Add _...
352
  static void __init setup_xstate_features(void)
a1488f8bf   Suresh Siddha   x86, xsave: Track...
353
354
355
356
357
358
359
360
  {
  	int eax, ebx, ecx, edx, leaf = 0x2;
  
  	xstate_features = fls64(pcntxt_mask);
  	xstate_offsets = alloc_bootmem(xstate_features * sizeof(int));
  	xstate_sizes = alloc_bootmem(xstate_features * sizeof(int));
  
  	do {
ee813d53a   Robert Richter   x86, xsave: Check...
361
  		cpuid_count(XSTATE_CPUID, leaf, &eax, &ebx, &ecx, &edx);
a1488f8bf   Suresh Siddha   x86, xsave: Track...
362
363
364
365
366
367
368
369
370
371
372
373
  
  		if (eax == 0)
  			break;
  
  		xstate_offsets[leaf] = ebx;
  		xstate_sizes[leaf] = eax;
  
  		leaf++;
  	} while (1);
  }
  
  /*
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
374
375
   * setup the xstate image representing the init state
   */
a19aac854   Alexey Dobriyan   x86: make setup_x...
376
  static void __init setup_xstate_init(void)
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
377
  {
29104e101   Suresh Siddha   x86, xsave: Sync ...
378
379
380
381
382
383
  	setup_xstate_features();
  
  	/*
  	 * Setup init_xstate_buf to represent the init state of
  	 * all the features managed by the xsave
  	 */
10340ae13   Suresh Siddha   x86, xsave: Use a...
384
385
  	init_xstate_buf = alloc_bootmem_align(xstate_size,
  					      __alignof__(struct xsave_struct));
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
386
  	init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
a1488f8bf   Suresh Siddha   x86, xsave: Track...
387

29104e101   Suresh Siddha   x86, xsave: Sync ...
388
389
390
391
392
393
394
395
396
397
398
  	clts();
  	/*
  	 * Init all the features state with header_bv being 0x0
  	 */
  	xrstor_state(init_xstate_buf, -1);
  	/*
  	 * Dump the init state again. This is to identify the init state
  	 * of any feature which is not represented by all zero's.
  	 */
  	xsave_state(init_xstate_buf, -1);
  	stts();
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
399
400
401
402
403
  }
  
  /*
   * Enable and initialize the xsave feature.
   */
1cff92d8f   H. Peter Anvin   x86, xsave: Make ...
404
  static void __init xstate_enable_boot_cpu(void)
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
405
406
  {
  	unsigned int eax, ebx, ecx, edx;
ee813d53a   Robert Richter   x86, xsave: Check...
407
408
409
410
411
412
413
  	if (boot_cpu_data.cpuid_level < XSTATE_CPUID) {
  		WARN(1, KERN_ERR "XSTATE_CPUID missing
  ");
  		return;
  	}
  
  	cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx);
6152e4b1c   H. Peter Anvin   x86, xsave: keep ...
414
  	pcntxt_mask = eax + ((u64)edx << 32);
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
415

6152e4b1c   H. Peter Anvin   x86, xsave: keep ...
416
417
418
419
  	if ((pcntxt_mask & XSTATE_FPSSE) != XSTATE_FPSSE) {
  		printk(KERN_ERR "FP/SSE not shown under xsave features 0x%llx
  ",
  		       pcntxt_mask);
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
420
421
422
423
  		BUG();
  	}
  
  	/*
a30469e79   Suresh Siddha   x86: add linux ke...
424
  	 * Support only the state known to OS.
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
425
  	 */
6152e4b1c   H. Peter Anvin   x86, xsave: keep ...
426
  	pcntxt_mask = pcntxt_mask & XCNTXT_MASK;
97e80a70d   Robert Richter   x86, xsave: Intro...
427

1cff92d8f   H. Peter Anvin   x86, xsave: Make ...
428
  	xstate_enable();
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
429
430
431
432
  
  	/*
  	 * Recompute the context size for enabled features
  	 */
ee813d53a   Robert Richter   x86, xsave: Check...
433
  	cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx);
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
434
  	xstate_size = ebx;
5b3efd500   Suresh Siddha   x86, ptrace: regs...
435
  	update_regset_xstate_info(xstate_size, pcntxt_mask);
c37b5efea   Suresh Siddha   x86, xsave: save/...
436
  	prepare_fx_sw_frame();
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
437
  	setup_xstate_init();
6152e4b1c   H. Peter Anvin   x86, xsave: keep ...
438
  	printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%llx, "
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
439
440
  	       "cntxt size 0x%x
  ",
6152e4b1c   H. Peter Anvin   x86, xsave: keep ...
441
  	       pcntxt_mask, xstate_size);
dc1e35c6e   Suresh Siddha   x86, xsave: enabl...
442
  }
82d4150ce   Robert Richter   x86, xsave: Move ...
443

1cff92d8f   H. Peter Anvin   x86, xsave: Make ...
444
445
446
447
448
449
450
  /*
   * For the very first instance, this calls xstate_enable_boot_cpu();
   * for all subsequent instances, this calls xstate_enable().
   *
   * This is somewhat obfuscated due to the lack of powerful enough
   * overrides for the section checks.
   */
82d4150ce   Robert Richter   x86, xsave: Move ...
451
452
  void __cpuinit xsave_init(void)
  {
1cff92d8f   H. Peter Anvin   x86, xsave: Make ...
453
454
  	static __refdata void (*next_func)(void) = xstate_enable_boot_cpu;
  	void (*this_func)(void);
0e49bf66d   Robert Richter   x86, xsave: Separ...
455
456
  	if (!cpu_has_xsave)
  		return;
1cff92d8f   H. Peter Anvin   x86, xsave: Make ...
457
458
459
  	this_func = next_func;
  	next_func = xstate_enable;
  	this_func();
82d4150ce   Robert Richter   x86, xsave: Move ...
460
  }