1/*
2 *  linux/arch/x86_64/kernel/i387.c
3 *
4 *  Copyright (C) 1994 Linus Torvalds
5 *  Copyright (C) 2002 Andi Kleen, SuSE Labs
6 *
7 *  Pentium III FXSR, SSE support
8 *  General FPU state handling cleanups
9 *	Gareth Hughes <gareth@valinux.com>, May 2000
10 *
11 *  x86-64 rework 2002 Andi Kleen.
12 *  Does direct fxsave in and out of user space now for signal handlers.
13 *  All the FSAVE<->FXSAVE conversion code has been moved to the 32bit emulation,
14 *  the 64bit user space sees a FXSAVE frame directly.
15 */
16
17#include <linux/config.h>
18#include <linux/sched.h>
19#include <asm/processor.h>
20#include <asm/i387.h>
21#include <asm/sigcontext.h>
22#include <asm/user.h>
23#include <asm/ptrace.h>
24#include <asm/uaccess.h>
25
26extern int exception_trace;
27
28/*
29 * The _current_ task is using the FPU for the first time
30 * so initialize it and set the mxcsr to its default
31 * value at reset if we support XMM instructions and then
32 * remeber the current task has used the FPU.
33 */
34void init_fpu(void)
35{
36	struct task_struct *me = current;
37	memset(&me->thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct));
38	me->thread.i387.fxsave.cwd = 0x37f;
39	me->thread.i387.fxsave.mxcsr = 0x1f80;
40	me->used_math = 1;
41}
42
43/*
44 * Signal frame handlers.
45 */
46
47int save_i387(struct _fpstate *buf)
48{
49	struct task_struct *tsk = current;
50	int err = 0;
51
52	{
53		extern void bad_user_i387_struct(void);
54		if (sizeof(struct user_i387_struct) != sizeof(tsk->thread.i387.fxsave))
55			bad_user_i387_struct();
56	}
57
58	if (!tsk->used_math)
59		return 0;
60	tsk->used_math = 0; /* trigger finit */
61	if (tsk->flags & PF_USEDFPU) {
62		err = save_i387_checking((struct i387_fxsave_struct *)buf);
63		if (err) {
64			if (exception_trace)
65				printk("%s[%d] unaligned signal floating point context %p\n",
66					tsk->comm, tsk->pid, buf);
67			return err;
68		}
69		stts();
70	} else {
71		if (__copy_to_user(buf, &tsk->thread.i387.fxsave,
72				   sizeof(struct i387_fxsave_struct)))
73			return -1;
74	}
75	return 1;
76}
77
78/*
79 * ptrace request handlers.
80 */
81
82int get_fpregs(struct user_i387_struct *buf, struct task_struct *tsk)
83{
84	empty_fpu(tsk);
85	return __copy_to_user((void *)buf, &tsk->thread.i387.fxsave,
86			       sizeof(struct user_i387_struct)) ? -EFAULT : 0;
87}
88
89int set_fpregs(struct task_struct *tsk, struct user_i387_struct *buf)
90{
91	if (__copy_from_user(&tsk->thread.i387.fxsave, buf,
92			     sizeof(struct user_i387_struct)))
93		return -EFAULT;
94	/* mxcsr bit 6 and 31-16 must be zero for security reasons. */
95	tsk->thread.i387.fxsave.mxcsr &= 0xffbf;
96	return 0;
97}
98
99/*
100 * FPU state for core dumps.
101 */
102
103int dump_fpu( struct pt_regs *regs, struct user_i387_struct *fpu )
104{
105	struct task_struct *tsk = current;
106
107	if (!tsk->used_math)
108		return 0;
109	unlazy_fpu(tsk);
110
111	memcpy(fpu, &tsk->thread.i387.fxsave, sizeof(struct user_i387_struct));
112	return 1;
113}
114