Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/x86/kernel/i387.c
10817 views
1
/*
2
* Copyright (C) 1994 Linus Torvalds
3
*
4
* Pentium III FXSR, SSE support
5
* General FPU state handling cleanups
6
* Gareth Hughes <[email protected]>, May 2000
7
*/
8
#include <linux/module.h>
9
#include <linux/regset.h>
10
#include <linux/sched.h>
11
#include <linux/slab.h>
12
13
#include <asm/sigcontext.h>
14
#include <asm/processor.h>
15
#include <asm/math_emu.h>
16
#include <asm/uaccess.h>
17
#include <asm/ptrace.h>
18
#include <asm/i387.h>
19
#include <asm/user.h>
20
21
#ifdef CONFIG_X86_64
22
# include <asm/sigcontext32.h>
23
# include <asm/user32.h>
24
#else
25
# define save_i387_xstate_ia32 save_i387_xstate
26
# define restore_i387_xstate_ia32 restore_i387_xstate
27
# define _fpstate_ia32 _fpstate
28
# define _xstate_ia32 _xstate
29
# define sig_xstate_ia32_size sig_xstate_size
30
# define fx_sw_reserved_ia32 fx_sw_reserved
31
# define user_i387_ia32_struct user_i387_struct
32
# define user32_fxsr_struct user_fxsr_struct
33
#endif
34
35
#ifdef CONFIG_MATH_EMULATION
36
# define HAVE_HWFP (boot_cpu_data.hard_math)
37
#else
38
# define HAVE_HWFP 1
39
#endif
40
41
static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
42
unsigned int xstate_size;
43
EXPORT_SYMBOL_GPL(xstate_size);
44
unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32);
45
static struct i387_fxsave_struct fx_scratch __cpuinitdata;
46
47
void __cpuinit mxcsr_feature_mask_init(void)
48
{
49
unsigned long mask = 0;
50
51
clts();
52
if (cpu_has_fxsr) {
53
memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct));
54
asm volatile("fxsave %0" : : "m" (fx_scratch));
55
mask = fx_scratch.mxcsr_mask;
56
if (mask == 0)
57
mask = 0x0000ffbf;
58
}
59
mxcsr_feature_mask &= mask;
60
stts();
61
}
62
63
static void __cpuinit init_thread_xstate(void)
64
{
65
/*
66
* Note that xstate_size might be overwriten later during
67
* xsave_init().
68
*/
69
70
if (!HAVE_HWFP) {
71
/*
72
* Disable xsave as we do not support it if i387
73
* emulation is enabled.
74
*/
75
setup_clear_cpu_cap(X86_FEATURE_XSAVE);
76
setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
77
xstate_size = sizeof(struct i387_soft_struct);
78
return;
79
}
80
81
if (cpu_has_fxsr)
82
xstate_size = sizeof(struct i387_fxsave_struct);
83
else
84
xstate_size = sizeof(struct i387_fsave_struct);
85
}
86
87
/*
88
* Called at bootup to set up the initial FPU state that is later cloned
89
* into all processes.
90
*/
91
92
void __cpuinit fpu_init(void)
93
{
94
unsigned long cr0;
95
unsigned long cr4_mask = 0;
96
97
if (cpu_has_fxsr)
98
cr4_mask |= X86_CR4_OSFXSR;
99
if (cpu_has_xmm)
100
cr4_mask |= X86_CR4_OSXMMEXCPT;
101
if (cr4_mask)
102
set_in_cr4(cr4_mask);
103
104
cr0 = read_cr0();
105
cr0 &= ~(X86_CR0_TS|X86_CR0_EM); /* clear TS and EM */
106
if (!HAVE_HWFP)
107
cr0 |= X86_CR0_EM;
108
write_cr0(cr0);
109
110
if (!smp_processor_id())
111
init_thread_xstate();
112
113
mxcsr_feature_mask_init();
114
/* clean state in init */
115
current_thread_info()->status = 0;
116
clear_used_math();
117
}
118
119
void fpu_finit(struct fpu *fpu)
120
{
121
if (!HAVE_HWFP) {
122
finit_soft_fpu(&fpu->state->soft);
123
return;
124
}
125
126
if (cpu_has_fxsr) {
127
struct i387_fxsave_struct *fx = &fpu->state->fxsave;
128
129
memset(fx, 0, xstate_size);
130
fx->cwd = 0x37f;
131
if (cpu_has_xmm)
132
fx->mxcsr = MXCSR_DEFAULT;
133
} else {
134
struct i387_fsave_struct *fp = &fpu->state->fsave;
135
memset(fp, 0, xstate_size);
136
fp->cwd = 0xffff037fu;
137
fp->swd = 0xffff0000u;
138
fp->twd = 0xffffffffu;
139
fp->fos = 0xffff0000u;
140
}
141
}
142
EXPORT_SYMBOL_GPL(fpu_finit);
143
144
/*
145
* The _current_ task is using the FPU for the first time
146
* so initialize it and set the mxcsr to its default
147
* value at reset if we support XMM instructions and then
148
* remember the current task has used the FPU.
149
*/
150
int init_fpu(struct task_struct *tsk)
151
{
152
int ret;
153
154
if (tsk_used_math(tsk)) {
155
if (HAVE_HWFP && tsk == current)
156
unlazy_fpu(tsk);
157
return 0;
158
}
159
160
/*
161
* Memory allocation at the first usage of the FPU and other state.
162
*/
163
ret = fpu_alloc(&tsk->thread.fpu);
164
if (ret)
165
return ret;
166
167
fpu_finit(&tsk->thread.fpu);
168
169
set_stopped_child_used_math(tsk);
170
return 0;
171
}
172
EXPORT_SYMBOL_GPL(init_fpu);
173
174
/*
175
* The xstateregs_active() routine is the same as the fpregs_active() routine,
176
* as the "regset->n" for the xstate regset will be updated based on the feature
177
* capabilites supported by the xsave.
178
*/
179
int fpregs_active(struct task_struct *target, const struct user_regset *regset)
180
{
181
return tsk_used_math(target) ? regset->n : 0;
182
}
183
184
int xfpregs_active(struct task_struct *target, const struct user_regset *regset)
185
{
186
return (cpu_has_fxsr && tsk_used_math(target)) ? regset->n : 0;
187
}
188
189
int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
190
unsigned int pos, unsigned int count,
191
void *kbuf, void __user *ubuf)
192
{
193
int ret;
194
195
if (!cpu_has_fxsr)
196
return -ENODEV;
197
198
ret = init_fpu(target);
199
if (ret)
200
return ret;
201
202
sanitize_i387_state(target);
203
204
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
205
&target->thread.fpu.state->fxsave, 0, -1);
206
}
207
208
int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
209
unsigned int pos, unsigned int count,
210
const void *kbuf, const void __user *ubuf)
211
{
212
int ret;
213
214
if (!cpu_has_fxsr)
215
return -ENODEV;
216
217
ret = init_fpu(target);
218
if (ret)
219
return ret;
220
221
sanitize_i387_state(target);
222
223
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
224
&target->thread.fpu.state->fxsave, 0, -1);
225
226
/*
227
* mxcsr reserved bits must be masked to zero for security reasons.
228
*/
229
target->thread.fpu.state->fxsave.mxcsr &= mxcsr_feature_mask;
230
231
/*
232
* update the header bits in the xsave header, indicating the
233
* presence of FP and SSE state.
234
*/
235
if (cpu_has_xsave)
236
target->thread.fpu.state->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE;
237
238
return ret;
239
}
240
241
int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
242
unsigned int pos, unsigned int count,
243
void *kbuf, void __user *ubuf)
244
{
245
int ret;
246
247
if (!cpu_has_xsave)
248
return -ENODEV;
249
250
ret = init_fpu(target);
251
if (ret)
252
return ret;
253
254
/*
255
* Copy the 48bytes defined by the software first into the xstate
256
* memory layout in the thread struct, so that we can copy the entire
257
* xstateregs to the user using one user_regset_copyout().
258
*/
259
memcpy(&target->thread.fpu.state->fxsave.sw_reserved,
260
xstate_fx_sw_bytes, sizeof(xstate_fx_sw_bytes));
261
262
/*
263
* Copy the xstate memory layout.
264
*/
265
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
266
&target->thread.fpu.state->xsave, 0, -1);
267
return ret;
268
}
269
270
int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
271
unsigned int pos, unsigned int count,
272
const void *kbuf, const void __user *ubuf)
273
{
274
int ret;
275
struct xsave_hdr_struct *xsave_hdr;
276
277
if (!cpu_has_xsave)
278
return -ENODEV;
279
280
ret = init_fpu(target);
281
if (ret)
282
return ret;
283
284
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
285
&target->thread.fpu.state->xsave, 0, -1);
286
287
/*
288
* mxcsr reserved bits must be masked to zero for security reasons.
289
*/
290
target->thread.fpu.state->fxsave.mxcsr &= mxcsr_feature_mask;
291
292
xsave_hdr = &target->thread.fpu.state->xsave.xsave_hdr;
293
294
xsave_hdr->xstate_bv &= pcntxt_mask;
295
/*
296
* These bits must be zero.
297
*/
298
xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
299
300
return ret;
301
}
302
303
#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
304
305
/*
306
* FPU tag word conversions.
307
*/
308
309
static inline unsigned short twd_i387_to_fxsr(unsigned short twd)
310
{
311
unsigned int tmp; /* to avoid 16 bit prefixes in the code */
312
313
/* Transform each pair of bits into 01 (valid) or 00 (empty) */
314
tmp = ~twd;
315
tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
316
/* and move the valid bits to the lower byte. */
317
tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
318
tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
319
tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
320
321
return tmp;
322
}
323
324
#define FPREG_ADDR(f, n) ((void *)&(f)->st_space + (n) * 16);
325
#define FP_EXP_TAG_VALID 0
326
#define FP_EXP_TAG_ZERO 1
327
#define FP_EXP_TAG_SPECIAL 2
328
#define FP_EXP_TAG_EMPTY 3
329
330
static inline u32 twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
331
{
332
struct _fpxreg *st;
333
u32 tos = (fxsave->swd >> 11) & 7;
334
u32 twd = (unsigned long) fxsave->twd;
335
u32 tag;
336
u32 ret = 0xffff0000u;
337
int i;
338
339
for (i = 0; i < 8; i++, twd >>= 1) {
340
if (twd & 0x1) {
341
st = FPREG_ADDR(fxsave, (i - tos) & 7);
342
343
switch (st->exponent & 0x7fff) {
344
case 0x7fff:
345
tag = FP_EXP_TAG_SPECIAL;
346
break;
347
case 0x0000:
348
if (!st->significand[0] &&
349
!st->significand[1] &&
350
!st->significand[2] &&
351
!st->significand[3])
352
tag = FP_EXP_TAG_ZERO;
353
else
354
tag = FP_EXP_TAG_SPECIAL;
355
break;
356
default:
357
if (st->significand[3] & 0x8000)
358
tag = FP_EXP_TAG_VALID;
359
else
360
tag = FP_EXP_TAG_SPECIAL;
361
break;
362
}
363
} else {
364
tag = FP_EXP_TAG_EMPTY;
365
}
366
ret |= tag << (2 * i);
367
}
368
return ret;
369
}
370
371
/*
372
* FXSR floating point environment conversions.
373
*/
374
375
static void
376
convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
377
{
378
struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave;
379
struct _fpreg *to = (struct _fpreg *) &env->st_space[0];
380
struct _fpxreg *from = (struct _fpxreg *) &fxsave->st_space[0];
381
int i;
382
383
env->cwd = fxsave->cwd | 0xffff0000u;
384
env->swd = fxsave->swd | 0xffff0000u;
385
env->twd = twd_fxsr_to_i387(fxsave);
386
387
#ifdef CONFIG_X86_64
388
env->fip = fxsave->rip;
389
env->foo = fxsave->rdp;
390
/*
391
* should be actually ds/cs at fpu exception time, but
392
* that information is not available in 64bit mode.
393
*/
394
env->fcs = task_pt_regs(tsk)->cs;
395
if (tsk == current) {
396
savesegment(ds, env->fos);
397
} else {
398
env->fos = tsk->thread.ds;
399
}
400
env->fos |= 0xffff0000;
401
#else
402
env->fip = fxsave->fip;
403
env->fcs = (u16) fxsave->fcs | ((u32) fxsave->fop << 16);
404
env->foo = fxsave->foo;
405
env->fos = fxsave->fos;
406
#endif
407
408
for (i = 0; i < 8; ++i)
409
memcpy(&to[i], &from[i], sizeof(to[0]));
410
}
411
412
static void convert_to_fxsr(struct task_struct *tsk,
413
const struct user_i387_ia32_struct *env)
414
415
{
416
struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave;
417
struct _fpreg *from = (struct _fpreg *) &env->st_space[0];
418
struct _fpxreg *to = (struct _fpxreg *) &fxsave->st_space[0];
419
int i;
420
421
fxsave->cwd = env->cwd;
422
fxsave->swd = env->swd;
423
fxsave->twd = twd_i387_to_fxsr(env->twd);
424
fxsave->fop = (u16) ((u32) env->fcs >> 16);
425
#ifdef CONFIG_X86_64
426
fxsave->rip = env->fip;
427
fxsave->rdp = env->foo;
428
/* cs and ds ignored */
429
#else
430
fxsave->fip = env->fip;
431
fxsave->fcs = (env->fcs & 0xffff);
432
fxsave->foo = env->foo;
433
fxsave->fos = env->fos;
434
#endif
435
436
for (i = 0; i < 8; ++i)
437
memcpy(&to[i], &from[i], sizeof(from[0]));
438
}
439
440
int fpregs_get(struct task_struct *target, const struct user_regset *regset,
441
unsigned int pos, unsigned int count,
442
void *kbuf, void __user *ubuf)
443
{
444
struct user_i387_ia32_struct env;
445
int ret;
446
447
ret = init_fpu(target);
448
if (ret)
449
return ret;
450
451
if (!HAVE_HWFP)
452
return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf);
453
454
if (!cpu_has_fxsr) {
455
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
456
&target->thread.fpu.state->fsave, 0,
457
-1);
458
}
459
460
sanitize_i387_state(target);
461
462
if (kbuf && pos == 0 && count == sizeof(env)) {
463
convert_from_fxsr(kbuf, target);
464
return 0;
465
}
466
467
convert_from_fxsr(&env, target);
468
469
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &env, 0, -1);
470
}
471
472
int fpregs_set(struct task_struct *target, const struct user_regset *regset,
473
unsigned int pos, unsigned int count,
474
const void *kbuf, const void __user *ubuf)
475
{
476
struct user_i387_ia32_struct env;
477
int ret;
478
479
ret = init_fpu(target);
480
if (ret)
481
return ret;
482
483
sanitize_i387_state(target);
484
485
if (!HAVE_HWFP)
486
return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf);
487
488
if (!cpu_has_fxsr) {
489
return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
490
&target->thread.fpu.state->fsave, 0, -1);
491
}
492
493
if (pos > 0 || count < sizeof(env))
494
convert_from_fxsr(&env, target);
495
496
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &env, 0, -1);
497
if (!ret)
498
convert_to_fxsr(target, &env);
499
500
/*
501
* update the header bit in the xsave header, indicating the
502
* presence of FP.
503
*/
504
if (cpu_has_xsave)
505
target->thread.fpu.state->xsave.xsave_hdr.xstate_bv |= XSTATE_FP;
506
return ret;
507
}
508
509
/*
510
* Signal frame handlers.
511
*/
512
513
static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf)
514
{
515
struct task_struct *tsk = current;
516
struct i387_fsave_struct *fp = &tsk->thread.fpu.state->fsave;
517
518
fp->status = fp->swd;
519
if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct)))
520
return -1;
521
return 1;
522
}
523
524
static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
525
{
526
struct task_struct *tsk = current;
527
struct i387_fxsave_struct *fx = &tsk->thread.fpu.state->fxsave;
528
struct user_i387_ia32_struct env;
529
int err = 0;
530
531
convert_from_fxsr(&env, tsk);
532
if (__copy_to_user(buf, &env, sizeof(env)))
533
return -1;
534
535
err |= __put_user(fx->swd, &buf->status);
536
err |= __put_user(X86_FXSR_MAGIC, &buf->magic);
537
if (err)
538
return -1;
539
540
if (__copy_to_user(&buf->_fxsr_env[0], fx, xstate_size))
541
return -1;
542
return 1;
543
}
544
545
static int save_i387_xsave(void __user *buf)
546
{
547
struct task_struct *tsk = current;
548
struct _fpstate_ia32 __user *fx = buf;
549
int err = 0;
550
551
552
sanitize_i387_state(tsk);
553
554
/*
555
* For legacy compatible, we always set FP/SSE bits in the bit
556
* vector while saving the state to the user context.
557
* This will enable us capturing any changes(during sigreturn) to
558
* the FP/SSE bits by the legacy applications which don't touch
559
* xstate_bv in the xsave header.
560
*
561
* xsave aware applications can change the xstate_bv in the xsave
562
* header as well as change any contents in the memory layout.
563
* xrestore as part of sigreturn will capture all the changes.
564
*/
565
tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE;
566
567
if (save_i387_fxsave(fx) < 0)
568
return -1;
569
570
err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved_ia32,
571
sizeof(struct _fpx_sw_bytes));
572
err |= __put_user(FP_XSTATE_MAGIC2,
573
(__u32 __user *) (buf + sig_xstate_ia32_size
574
- FP_XSTATE_MAGIC2_SIZE));
575
if (err)
576
return -1;
577
578
return 1;
579
}
580
581
int save_i387_xstate_ia32(void __user *buf)
582
{
583
struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
584
struct task_struct *tsk = current;
585
586
if (!used_math())
587
return 0;
588
589
if (!access_ok(VERIFY_WRITE, buf, sig_xstate_ia32_size))
590
return -EACCES;
591
/*
592
* This will cause a "finit" to be triggered by the next
593
* attempted FPU operation by the 'current' process.
594
*/
595
clear_used_math();
596
597
if (!HAVE_HWFP) {
598
return fpregs_soft_get(current, NULL,
599
0, sizeof(struct user_i387_ia32_struct),
600
NULL, fp) ? -1 : 1;
601
}
602
603
unlazy_fpu(tsk);
604
605
if (cpu_has_xsave)
606
return save_i387_xsave(fp);
607
if (cpu_has_fxsr)
608
return save_i387_fxsave(fp);
609
else
610
return save_i387_fsave(fp);
611
}
612
613
static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
614
{
615
struct task_struct *tsk = current;
616
617
return __copy_from_user(&tsk->thread.fpu.state->fsave, buf,
618
sizeof(struct i387_fsave_struct));
619
}
620
621
static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf,
622
unsigned int size)
623
{
624
struct task_struct *tsk = current;
625
struct user_i387_ia32_struct env;
626
int err;
627
628
err = __copy_from_user(&tsk->thread.fpu.state->fxsave, &buf->_fxsr_env[0],
629
size);
630
/* mxcsr reserved bits must be masked to zero for security reasons */
631
tsk->thread.fpu.state->fxsave.mxcsr &= mxcsr_feature_mask;
632
if (err || __copy_from_user(&env, buf, sizeof(env)))
633
return 1;
634
convert_to_fxsr(tsk, &env);
635
636
return 0;
637
}
638
639
static int restore_i387_xsave(void __user *buf)
640
{
641
struct _fpx_sw_bytes fx_sw_user;
642
struct _fpstate_ia32 __user *fx_user =
643
((struct _fpstate_ia32 __user *) buf);
644
struct i387_fxsave_struct __user *fx =
645
(struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0];
646
struct xsave_hdr_struct *xsave_hdr =
647
&current->thread.fpu.state->xsave.xsave_hdr;
648
u64 mask;
649
int err;
650
651
if (check_for_xstate(fx, buf, &fx_sw_user))
652
goto fx_only;
653
654
mask = fx_sw_user.xstate_bv;
655
656
err = restore_i387_fxsave(buf, fx_sw_user.xstate_size);
657
658
xsave_hdr->xstate_bv &= pcntxt_mask;
659
/*
660
* These bits must be zero.
661
*/
662
xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
663
664
/*
665
* Init the state that is not present in the memory layout
666
* and enabled by the OS.
667
*/
668
mask = ~(pcntxt_mask & ~mask);
669
xsave_hdr->xstate_bv &= mask;
670
671
return err;
672
fx_only:
673
/*
674
* Couldn't find the extended state information in the memory
675
* layout. Restore the FP/SSE and init the other extended state
676
* enabled by the OS.
677
*/
678
xsave_hdr->xstate_bv = XSTATE_FPSSE;
679
return restore_i387_fxsave(buf, sizeof(struct i387_fxsave_struct));
680
}
681
682
int restore_i387_xstate_ia32(void __user *buf)
683
{
684
int err;
685
struct task_struct *tsk = current;
686
struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
687
688
if (HAVE_HWFP)
689
clear_fpu(tsk);
690
691
if (!buf) {
692
if (used_math()) {
693
clear_fpu(tsk);
694
clear_used_math();
695
}
696
697
return 0;
698
} else
699
if (!access_ok(VERIFY_READ, buf, sig_xstate_ia32_size))
700
return -EACCES;
701
702
if (!used_math()) {
703
err = init_fpu(tsk);
704
if (err)
705
return err;
706
}
707
708
if (HAVE_HWFP) {
709
if (cpu_has_xsave)
710
err = restore_i387_xsave(buf);
711
else if (cpu_has_fxsr)
712
err = restore_i387_fxsave(fp, sizeof(struct
713
i387_fxsave_struct));
714
else
715
err = restore_i387_fsave(fp);
716
} else {
717
err = fpregs_soft_set(current, NULL,
718
0, sizeof(struct user_i387_ia32_struct),
719
NULL, fp) != 0;
720
}
721
set_used_math();
722
723
return err;
724
}
725
726
/*
727
* FPU state for core dumps.
728
* This is only used for a.out dumps now.
729
* It is declared generically using elf_fpregset_t (which is
730
* struct user_i387_struct) but is in fact only used for 32-bit
731
* dumps, so on 64-bit it is really struct user_i387_ia32_struct.
732
*/
733
int dump_fpu(struct pt_regs *regs, struct user_i387_struct *fpu)
734
{
735
struct task_struct *tsk = current;
736
int fpvalid;
737
738
fpvalid = !!used_math();
739
if (fpvalid)
740
fpvalid = !fpregs_get(tsk, NULL,
741
0, sizeof(struct user_i387_ia32_struct),
742
fpu, NULL);
743
744
return fpvalid;
745
}
746
EXPORT_SYMBOL(dump_fpu);
747
748
#endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
749
750