]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/x86/kernel/xsave.c
608e72d7ca64f72e7ea414d05c4c64cbe43bd9f7
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / xsave.c
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
10 /*
11  * Supported feature mask by the CPU and the kernel.
12  */
13 unsigned int pcntxt_hmask, pcntxt_lmask;
14
15 #ifdef CONFIG_X86_64
16 /*
17  * Signal frame handlers.
18  */
19
20 int save_i387_xstate(void __user *buf)
21 {
22         struct task_struct *tsk = current;
23         int err = 0;
24
25         if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size))
26                 return -EACCES;
27
28         BUILD_BUG_ON(sizeof(struct user_i387_struct) !=
29                         sizeof(tsk->thread.xstate->fxsave));
30
31         if ((unsigned long)buf % 16)
32                 printk("save_i387_xstate: bad fpstate %p\n", buf);
33
34         if (!used_math())
35                 return 0;
36         clear_used_math(); /* trigger finit */
37         if (task_thread_info(tsk)->status & TS_USEDFPU) {
38                 err = save_i387_checking((struct i387_fxsave_struct __user *)
39                                          buf);
40                 if (err)
41                         return err;
42                 task_thread_info(tsk)->status &= ~TS_USEDFPU;
43                 stts();
44         } else {
45                 if (__copy_to_user(buf, &tsk->thread.xstate->fxsave,
46                                    xstate_size))
47                         return -1;
48         }
49         return 1;
50 }
51
52 /*
53  * This restores directly out of user space. Exceptions are handled.
54  */
55 int restore_i387_xstate(void __user *buf)
56 {
57         struct task_struct *tsk = current;
58         int err;
59
60         if (!buf) {
61                 if (used_math()) {
62                         clear_fpu(tsk);
63                         clear_used_math();
64                 }
65
66                 return 0;
67         } else
68                 if (!access_ok(VERIFY_READ, buf, sig_xstate_size))
69                         return -EACCES;
70
71         if (!used_math()) {
72                 err = init_fpu(tsk);
73                 if (err)
74                         return err;
75         }
76
77         if (!(task_thread_info(current)->status & TS_USEDFPU)) {
78                 clts();
79                 task_thread_info(current)->status |= TS_USEDFPU;
80         }
81         err = fxrstor_checking((__force struct i387_fxsave_struct *)buf);
82         if (unlikely(err)) {
83                 /*
84                  * Encountered an error while doing the restore from the
85                  * user buffer, clear the fpu state.
86                  */
87                 clear_fpu(tsk);
88                 clear_used_math();
89         }
90         return err;
91 }
92 #endif
93
94 /*
95  * Represents init state for the supported extended state.
96  */
97 struct xsave_struct *init_xstate_buf;
98
99 #ifdef CONFIG_X86_64
100 unsigned int sig_xstate_size = sizeof(struct _fpstate);
101 #endif
102
103 /*
104  * Enable the extended processor state save/restore feature
105  */
106 void __cpuinit xsave_init(void)
107 {
108         if (!cpu_has_xsave)
109                 return;
110
111         set_in_cr4(X86_CR4_OSXSAVE);
112
113         /*
114          * Enable all the features that the HW is capable of
115          * and the Linux kernel is aware of.
116          *
117          * xsetbv();
118          */
119         asm volatile(".byte 0x0f,0x01,0xd1" : : "c" (0),
120                      "a" (pcntxt_lmask), "d" (pcntxt_hmask));
121 }
122
123 /*
124  * setup the xstate image representing the init state
125  */
126 void setup_xstate_init(void)
127 {
128         init_xstate_buf = alloc_bootmem(xstate_size);
129         init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
130 }
131
132 /*
133  * Enable and initialize the xsave feature.
134  */
135 void __init xsave_cntxt_init(void)
136 {
137         unsigned int eax, ebx, ecx, edx;
138
139         cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
140
141         pcntxt_lmask = eax;
142         pcntxt_hmask = edx;
143
144         if ((pcntxt_lmask & XSTATE_FPSSE) != XSTATE_FPSSE) {
145                 printk(KERN_ERR "FP/SSE not shown under xsave features %x\n",
146                        pcntxt_lmask);
147                 BUG();
148         }
149
150         /*
151          * for now OS knows only about FP/SSE
152          */
153         pcntxt_lmask = pcntxt_lmask & XCNTXT_LMASK;
154         pcntxt_hmask = pcntxt_hmask & XCNTXT_HMASK;
155
156         xsave_init();
157
158         /*
159          * Recompute the context size for enabled features
160          */
161         cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
162
163         xstate_size = ebx;
164
165         setup_xstate_init();
166
167         printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%Lx, "
168                "cntxt size 0x%x\n",
169                (pcntxt_lmask | ((u64) pcntxt_hmask << 32)), xstate_size);
170 }