aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-08-13 20:20:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-13 20:20:04 -0400
commit7453f33b2e07fc2835e24cda0893de83c78d8d76 (patch)
tree02d82193515fcc94cf39e284fd325c4491913331
parentfd1cf90580289f83f9c972bb367a74d846d281c4 (diff)
parentd0f2dd186133a0241a2ccefb188a0e49e8187859 (diff)
Merge branch 'x86-xsave-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86/xsave changes from Peter Anvin: "This is a patchset to support the XSAVES instruction required to support context switch of supervisor-only features in upcoming silicon. This patchset missed the 3.16 merge window, which is why it is based on 3.15-rc7" * 'x86-xsave-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86, xsave: Add forgotten inline annotation x86/xsaves: Clean up code in xstate offsets computation in xsave area x86/xsave: Make it clear that the XSAVE macros use (%edi)/(%rdi) Define kernel API to get address of each state in xsave area x86/xsaves: Enable xsaves/xrstors x86/xsaves: Call booting time xsaves and xrstors in setup_init_fpu_buf x86/xsaves: Save xstate to task's xsave area in __save_fpu during booting time x86/xsaves: Add xsaves and xrstors support for booting time x86/xsaves: Clear reserved bits in xsave header x86/xsaves: Use xsave/xrstor for saving and restoring user space context x86/xsaves: Use xsaves/xrstors for context switch x86/xsaves: Use xsaves/xrstors to save and restore xsave area x86/xsaves: Define a macro for handling xsave/xrstor instruction fault x86/xsaves: Define macros for xsave instructions x86/xsaves: Change compacted format xsave area header x86/alternative: Add alternative_input_2 to support alternative with two features and input x86/xsaves: Add a kernel parameter noxsaves to disable xsaves/xrstors
-rw-r--r--Documentation/kernel-parameters.txt15
-rw-r--r--arch/x86/include/asm/alternative.h14
-rw-r--r--arch/x86/include/asm/fpu-internal.h9
-rw-r--r--arch/x86/include/asm/processor.h4
-rw-r--r--arch/x86/include/asm/xsave.h223
-rw-r--r--arch/x86/kernel/cpu/common.c8
-rw-r--r--arch/x86/kernel/i387.c2
-rw-r--r--arch/x86/kernel/process.c1
-rw-r--r--arch/x86/kernel/xsave.c118
9 files changed, 324 insertions, 70 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index a8eb6afce6a4..5ae8608ca9f5 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -2200,6 +2200,21 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
2200 and restore using xsave. The kernel will fallback to 2200 and restore using xsave. The kernel will fallback to
2201 enabling legacy floating-point and sse state. 2201 enabling legacy floating-point and sse state.
2202 2202
2203 noxsaveopt [X86] Disables xsaveopt used in saving x86 extended
2204 register states. The kernel will fall back to use
2205 xsave to save the states. By using this parameter,
2206 performance of saving the states is degraded because
2207 xsave doesn't support modified optimization while
2208 xsaveopt supports it on xsaveopt enabled systems.
2209
2210 noxsaves [X86] Disables xsaves and xrstors used in saving and
2211 restoring x86 extended register state in compacted
2212 form of xsave area. The kernel will fall back to use
2213 xsaveopt and xrstor to save and restore the states
2214 in standard form of xsave area. By using this
2215 parameter, xsave area per process might occupy more
2216 memory on xsaves enabled systems.
2217
2203 eagerfpu= [X86] 2218 eagerfpu= [X86]
2204 on enable eager fpu restore 2219 on enable eager fpu restore
2205 off disable eager fpu restore 2220 off disable eager fpu restore
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h
index 0a3f9c9f98d5..473bdbee378a 100644
--- a/arch/x86/include/asm/alternative.h
+++ b/arch/x86/include/asm/alternative.h
@@ -161,6 +161,20 @@ static inline int alternatives_text_reserved(void *start, void *end)
161 asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ 161 asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \
162 : : "i" (0), ## input) 162 : : "i" (0), ## input)
163 163
164/*
165 * This is similar to alternative_input. But it has two features and
166 * respective instructions.
167 *
168 * If CPU has feature2, newinstr2 is used.
169 * Otherwise, if CPU has feature1, newinstr1 is used.
170 * Otherwise, oldinstr is used.
171 */
172#define alternative_input_2(oldinstr, newinstr1, feature1, newinstr2, \
173 feature2, input...) \
174 asm volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, \
175 newinstr2, feature2) \
176 : : "i" (0), ## input)
177
164/* Like alternative_input, but with a single output argument */ 178/* Like alternative_input, but with a single output argument */
165#define alternative_io(oldinstr, newinstr, feature, output, input...) \ 179#define alternative_io(oldinstr, newinstr, feature, output, input...) \
166 asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ 180 asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h
index e3b85422cf12..412ececa00b9 100644
--- a/arch/x86/include/asm/fpu-internal.h
+++ b/arch/x86/include/asm/fpu-internal.h
@@ -508,9 +508,12 @@ static inline void user_fpu_begin(void)
508 508
509static inline void __save_fpu(struct task_struct *tsk) 509static inline void __save_fpu(struct task_struct *tsk)
510{ 510{
511 if (use_xsave()) 511 if (use_xsave()) {
512 xsave_state(&tsk->thread.fpu.state->xsave, -1); 512 if (unlikely(system_state == SYSTEM_BOOTING))
513 else 513 xsave_state_booting(&tsk->thread.fpu.state->xsave, -1);
514 else
515 xsave_state(&tsk->thread.fpu.state->xsave, -1);
516 } else
514 fpu_fxsave(&tsk->thread.fpu); 517 fpu_fxsave(&tsk->thread.fpu);
515} 518}
516 519
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index ee30b9f0b91c..eb71ec794732 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -385,8 +385,8 @@ struct bndcsr_struct {
385 385
386struct xsave_hdr_struct { 386struct xsave_hdr_struct {
387 u64 xstate_bv; 387 u64 xstate_bv;
388 u64 reserved1[2]; 388 u64 xcomp_bv;
389 u64 reserved2[5]; 389 u64 reserved[6];
390} __attribute__((packed)); 390} __attribute__((packed));
391 391
392struct xsave_struct { 392struct xsave_struct {
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h
index d949ef28c48b..7e7a79ada658 100644
--- a/arch/x86/include/asm/xsave.h
+++ b/arch/x86/include/asm/xsave.h
@@ -52,24 +52,170 @@ extern void xsave_init(void);
52extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask); 52extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask);
53extern int init_fpu(struct task_struct *child); 53extern int init_fpu(struct task_struct *child);
54 54
55static inline int fpu_xrstor_checking(struct xsave_struct *fx) 55/* These macros all use (%edi)/(%rdi) as the single memory argument. */
56#define XSAVE ".byte " REX_PREFIX "0x0f,0xae,0x27"
57#define XSAVEOPT ".byte " REX_PREFIX "0x0f,0xae,0x37"
58#define XSAVES ".byte " REX_PREFIX "0x0f,0xc7,0x2f"
59#define XRSTOR ".byte " REX_PREFIX "0x0f,0xae,0x2f"
60#define XRSTORS ".byte " REX_PREFIX "0x0f,0xc7,0x1f"
61
62#define xstate_fault ".section .fixup,\"ax\"\n" \
63 "3: movl $-1,%[err]\n" \
64 " jmp 2b\n" \
65 ".previous\n" \
66 _ASM_EXTABLE(1b, 3b) \
67 : [err] "=r" (err)
68
69/*
70 * This function is called only during boot time when x86 caps are not set
71 * up and alternative can not be used yet.
72 */
73static inline int xsave_state_booting(struct xsave_struct *fx, u64 mask)
56{ 74{
57 int err; 75 u32 lmask = mask;
76 u32 hmask = mask >> 32;
77 int err = 0;
78
79 WARN_ON(system_state != SYSTEM_BOOTING);
80
81 if (boot_cpu_has(X86_FEATURE_XSAVES))
82 asm volatile("1:"XSAVES"\n\t"
83 "2:\n\t"
84 : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
85 : "memory");
86 else
87 asm volatile("1:"XSAVE"\n\t"
88 "2:\n\t"
89 : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
90 : "memory");
91
92 asm volatile(xstate_fault
93 : "0" (0)
94 : "memory");
95
96 return err;
97}
98
99/*
100 * This function is called only during boot time when x86 caps are not set
101 * up and alternative can not be used yet.
102 */
103static inline int xrstor_state_booting(struct xsave_struct *fx, u64 mask)
104{
105 u32 lmask = mask;
106 u32 hmask = mask >> 32;
107 int err = 0;
108
109 WARN_ON(system_state != SYSTEM_BOOTING);
58 110
59 asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n\t" 111 if (boot_cpu_has(X86_FEATURE_XSAVES))
60 "2:\n" 112 asm volatile("1:"XRSTORS"\n\t"
61 ".section .fixup,\"ax\"\n" 113 "2:\n\t"
62 "3: movl $-1,%[err]\n" 114 : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
63 " jmp 2b\n" 115 : "memory");
64 ".previous\n" 116 else
65 _ASM_EXTABLE(1b, 3b) 117 asm volatile("1:"XRSTOR"\n\t"
66 : [err] "=r" (err) 118 "2:\n\t"
67 : "D" (fx), "m" (*fx), "a" (-1), "d" (-1), "0" (0) 119 : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
120 : "memory");
121
122 asm volatile(xstate_fault
123 : "0" (0)
124 : "memory");
125
126 return err;
127}
128
129/*
130 * Save processor xstate to xsave area.
131 */
132static inline int xsave_state(struct xsave_struct *fx, u64 mask)
133{
134 u32 lmask = mask;
135 u32 hmask = mask >> 32;
136 int err = 0;
137
138 /*
139 * If xsaves is enabled, xsaves replaces xsaveopt because
140 * it supports compact format and supervisor states in addition to
141 * modified optimization in xsaveopt.
142 *
143 * Otherwise, if xsaveopt is enabled, xsaveopt replaces xsave
144 * because xsaveopt supports modified optimization which is not
145 * supported by xsave.
146 *
147 * If none of xsaves and xsaveopt is enabled, use xsave.
148 */
149 alternative_input_2(
150 "1:"XSAVE,
151 "1:"XSAVEOPT,
152 X86_FEATURE_XSAVEOPT,
153 "1:"XSAVES,
154 X86_FEATURE_XSAVES,
155 [fx] "D" (fx), "a" (lmask), "d" (hmask) :
156 "memory");
157 asm volatile("2:\n\t"
158 xstate_fault
159 : "0" (0)
68 : "memory"); 160 : "memory");
69 161
70 return err; 162 return err;
71} 163}
72 164
165/*
166 * Restore processor xstate from xsave area.
167 */
168static inline int xrstor_state(struct xsave_struct *fx, u64 mask)
169{
170 int err = 0;
171 u32 lmask = mask;
172 u32 hmask = mask >> 32;
173
174 /*
175 * Use xrstors to restore context if it is enabled. xrstors supports
176 * compacted format of xsave area which is not supported by xrstor.
177 */
178 alternative_input(
179 "1: " XRSTOR,
180 "1: " XRSTORS,
181 X86_FEATURE_XSAVES,
182 "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
183 : "memory");
184
185 asm volatile("2:\n"
186 xstate_fault
187 : "0" (0)
188 : "memory");
189
190 return err;
191}
192
193/*
194 * Save xstate context for old process during context switch.
195 */
196static inline void fpu_xsave(struct fpu *fpu)
197{
198 xsave_state(&fpu->state->xsave, -1);
199}
200
201/*
202 * Restore xstate context for new process during context switch.
203 */
204static inline int fpu_xrstor_checking(struct xsave_struct *fx)
205{
206 return xrstor_state(fx, -1);
207}
208
209/*
210 * Save xstate to user space xsave area.
211 *
212 * We don't use modified optimization because xrstor/xrstors might track
213 * a different application.
214 *
215 * We don't use compacted format xsave area for
216 * backward compatibility for old applications which don't understand
217 * compacted format of xsave area.
218 */
73static inline int xsave_user(struct xsave_struct __user *buf) 219static inline int xsave_user(struct xsave_struct __user *buf)
74{ 220{
75 int err; 221 int err;
@@ -83,69 +229,34 @@ static inline int xsave_user(struct xsave_struct __user *buf)
83 return -EFAULT; 229 return -EFAULT;
84 230
85 __asm__ __volatile__(ASM_STAC "\n" 231 __asm__ __volatile__(ASM_STAC "\n"
86 "1: .byte " REX_PREFIX "0x0f,0xae,0x27\n" 232 "1:"XSAVE"\n"
87 "2: " ASM_CLAC "\n" 233 "2: " ASM_CLAC "\n"
88 ".section .fixup,\"ax\"\n" 234 xstate_fault
89 "3: movl $-1,%[err]\n"
90 " jmp 2b\n"
91 ".previous\n"
92 _ASM_EXTABLE(1b,3b)
93 : [err] "=r" (err)
94 : "D" (buf), "a" (-1), "d" (-1), "0" (0) 235 : "D" (buf), "a" (-1), "d" (-1), "0" (0)
95 : "memory"); 236 : "memory");
96 return err; 237 return err;
97} 238}
98 239
240/*
241 * Restore xstate from user space xsave area.
242 */
99static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask) 243static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask)
100{ 244{
101 int err; 245 int err = 0;
102 struct xsave_struct *xstate = ((__force struct xsave_struct *)buf); 246 struct xsave_struct *xstate = ((__force struct xsave_struct *)buf);
103 u32 lmask = mask; 247 u32 lmask = mask;
104 u32 hmask = mask >> 32; 248 u32 hmask = mask >> 32;
105 249
106 __asm__ __volatile__(ASM_STAC "\n" 250 __asm__ __volatile__(ASM_STAC "\n"
107 "1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n" 251 "1:"XRSTOR"\n"
108 "2: " ASM_CLAC "\n" 252 "2: " ASM_CLAC "\n"
109 ".section .fixup,\"ax\"\n" 253 xstate_fault
110 "3: movl $-1,%[err]\n"
111 " jmp 2b\n"
112 ".previous\n"
113 _ASM_EXTABLE(1b,3b)
114 : [err] "=r" (err)
115 : "D" (xstate), "a" (lmask), "d" (hmask), "0" (0) 254 : "D" (xstate), "a" (lmask), "d" (hmask), "0" (0)
116 : "memory"); /* memory required? */ 255 : "memory"); /* memory required? */
117 return err; 256 return err;
118} 257}
119 258
120static inline void xrstor_state(struct xsave_struct *fx, u64 mask) 259void *get_xsave_addr(struct xsave_struct *xsave, int xstate);
121{ 260void setup_xstate_comp(void);
122 u32 lmask = mask;
123 u32 hmask = mask >> 32;
124
125 asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
126 : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
127 : "memory");
128}
129
130static inline void xsave_state(struct xsave_struct *fx, u64 mask)
131{
132 u32 lmask = mask;
133 u32 hmask = mask >> 32;
134 261
135 asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x27\n\t"
136 : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
137 : "memory");
138}
139
140static inline void fpu_xsave(struct fpu *fpu)
141{
142 /* This, however, we can work around by forcing the compiler to select
143 an addressing mode that doesn't require extended registers. */
144 alternative_input(
145 ".byte " REX_PREFIX "0x0f,0xae,0x27",
146 ".byte " REX_PREFIX "0x0f,0xae,0x37",
147 X86_FEATURE_XSAVEOPT,
148 [fx] "D" (&fpu->state->xsave), "a" (-1), "d" (-1) :
149 "memory");
150}
151#endif 262#endif
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 333fd5209336..e4ab2b42bd6f 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -148,6 +148,7 @@ static int __init x86_xsave_setup(char *s)
148{ 148{
149 setup_clear_cpu_cap(X86_FEATURE_XSAVE); 149 setup_clear_cpu_cap(X86_FEATURE_XSAVE);
150 setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); 150 setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
151 setup_clear_cpu_cap(X86_FEATURE_XSAVES);
151 setup_clear_cpu_cap(X86_FEATURE_AVX); 152 setup_clear_cpu_cap(X86_FEATURE_AVX);
152 setup_clear_cpu_cap(X86_FEATURE_AVX2); 153 setup_clear_cpu_cap(X86_FEATURE_AVX2);
153 return 1; 154 return 1;
@@ -161,6 +162,13 @@ static int __init x86_xsaveopt_setup(char *s)
161} 162}
162__setup("noxsaveopt", x86_xsaveopt_setup); 163__setup("noxsaveopt", x86_xsaveopt_setup);
163 164
165static int __init x86_xsaves_setup(char *s)
166{
167 setup_clear_cpu_cap(X86_FEATURE_XSAVES);
168 return 1;
169}
170__setup("noxsaves", x86_xsaves_setup);
171
164#ifdef CONFIG_X86_32 172#ifdef CONFIG_X86_32
165static int cachesize_override = -1; 173static int cachesize_override = -1;
166static int disable_x86_serial_nr = 1; 174static int disable_x86_serial_nr = 1;
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index d5dd80814419..a9a4229f6161 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -375,7 +375,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
375 /* 375 /*
376 * These bits must be zero. 376 * These bits must be zero.
377 */ 377 */
378 xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0; 378 memset(xsave_hdr->reserved, 0, 48);
379 379
380 return ret; 380 return ret;
381} 381}
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 4505e2a950d8..f804dc935d2a 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -93,6 +93,7 @@ void arch_task_cache_init(void)
93 kmem_cache_create("task_xstate", xstate_size, 93 kmem_cache_create("task_xstate", xstate_size,
94 __alignof__(union thread_xstate), 94 __alignof__(union thread_xstate),
95 SLAB_PANIC | SLAB_NOTRACK, NULL); 95 SLAB_PANIC | SLAB_NOTRACK, NULL);
96 setup_xstate_comp();
96} 97}
97 98
98/* 99/*
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index a4b451c6addf..940b142cc11f 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -8,6 +8,7 @@
8 8
9#include <linux/bootmem.h> 9#include <linux/bootmem.h>
10#include <linux/compat.h> 10#include <linux/compat.h>
11#include <linux/cpu.h>
11#include <asm/i387.h> 12#include <asm/i387.h>
12#include <asm/fpu-internal.h> 13#include <asm/fpu-internal.h>
13#include <asm/sigframe.h> 14#include <asm/sigframe.h>
@@ -24,7 +25,9 @@ u64 pcntxt_mask;
24struct xsave_struct *init_xstate_buf; 25struct xsave_struct *init_xstate_buf;
25 26
26static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32; 27static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32;
27static unsigned int *xstate_offsets, *xstate_sizes, xstate_features; 28static unsigned int *xstate_offsets, *xstate_sizes;
29static unsigned int xstate_comp_offsets[sizeof(pcntxt_mask)*8];
30static unsigned int xstate_features;
28 31
29/* 32/*
30 * If a processor implementation discern that a processor state component is 33 * If a processor implementation discern that a processor state component is
@@ -283,7 +286,7 @@ sanitize_restored_xstate(struct task_struct *tsk,
283 286
284 if (use_xsave()) { 287 if (use_xsave()) {
285 /* These bits must be zero. */ 288 /* These bits must be zero. */
286 xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0; 289 memset(xsave_hdr->reserved, 0, 48);
287 290
288 /* 291 /*
289 * Init the state that is not present in the memory 292 * Init the state that is not present in the memory
@@ -479,6 +482,52 @@ static void __init setup_xstate_features(void)
479} 482}
480 483
481/* 484/*
485 * This function sets up offsets and sizes of all extended states in
486 * xsave area. This supports both standard format and compacted format
487 * of the xsave aread.
488 *
489 * Input: void
490 * Output: void
491 */
492void setup_xstate_comp(void)
493{
494 unsigned int xstate_comp_sizes[sizeof(pcntxt_mask)*8];
495 int i;
496
497 /*
498 * The FP xstates and SSE xstates are legacy states. They are always
499 * in the fixed offsets in the xsave area in either compacted form
500 * or standard form.
501 */
502 xstate_comp_offsets[0] = 0;
503 xstate_comp_offsets[1] = offsetof(struct i387_fxsave_struct, xmm_space);
504
505 if (!cpu_has_xsaves) {
506 for (i = 2; i < xstate_features; i++) {
507 if (test_bit(i, (unsigned long *)&pcntxt_mask)) {
508 xstate_comp_offsets[i] = xstate_offsets[i];
509 xstate_comp_sizes[i] = xstate_sizes[i];
510 }
511 }
512 return;
513 }
514
515 xstate_comp_offsets[2] = FXSAVE_SIZE + XSAVE_HDR_SIZE;
516
517 for (i = 2; i < xstate_features; i++) {
518 if (test_bit(i, (unsigned long *)&pcntxt_mask))
519 xstate_comp_sizes[i] = xstate_sizes[i];
520 else
521 xstate_comp_sizes[i] = 0;
522
523 if (i > 2)
524 xstate_comp_offsets[i] = xstate_comp_offsets[i-1]
525 + xstate_comp_sizes[i-1];
526
527 }
528}
529
530/*
482 * setup the xstate image representing the init state 531 * setup the xstate image representing the init state
483 */ 532 */
484static void __init setup_init_fpu_buf(void) 533static void __init setup_init_fpu_buf(void)
@@ -496,15 +545,21 @@ static void __init setup_init_fpu_buf(void)
496 545
497 setup_xstate_features(); 546 setup_xstate_features();
498 547
548 if (cpu_has_xsaves) {
549 init_xstate_buf->xsave_hdr.xcomp_bv =
550 (u64)1 << 63 | pcntxt_mask;
551 init_xstate_buf->xsave_hdr.xstate_bv = pcntxt_mask;
552 }
553
499 /* 554 /*
500 * Init all the features state with header_bv being 0x0 555 * Init all the features state with header_bv being 0x0
501 */ 556 */
502 xrstor_state(init_xstate_buf, -1); 557 xrstor_state_booting(init_xstate_buf, -1);
503 /* 558 /*
504 * Dump the init state again. This is to identify the init state 559 * Dump the init state again. This is to identify the init state
505 * of any feature which is not represented by all zero's. 560 * of any feature which is not represented by all zero's.
506 */ 561 */
507 xsave_state(init_xstate_buf, -1); 562 xsave_state_booting(init_xstate_buf, -1);
508} 563}
509 564
510static enum { AUTO, ENABLE, DISABLE } eagerfpu = AUTO; 565static enum { AUTO, ENABLE, DISABLE } eagerfpu = AUTO;
@@ -520,6 +575,30 @@ static int __init eager_fpu_setup(char *s)
520} 575}
521__setup("eagerfpu=", eager_fpu_setup); 576__setup("eagerfpu=", eager_fpu_setup);
522 577
578
579/*
580 * Calculate total size of enabled xstates in XCR0/pcntxt_mask.
581 */
582static void __init init_xstate_size(void)
583{
584 unsigned int eax, ebx, ecx, edx;
585 int i;
586
587 if (!cpu_has_xsaves) {
588 cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx);
589 xstate_size = ebx;
590 return;
591 }
592
593 xstate_size = FXSAVE_SIZE + XSAVE_HDR_SIZE;
594 for (i = 2; i < 64; i++) {
595 if (test_bit(i, (unsigned long *)&pcntxt_mask)) {
596 cpuid_count(XSTATE_CPUID, i, &eax, &ebx, &ecx, &edx);
597 xstate_size += eax;
598 }
599 }
600}
601
523/* 602/*
524 * Enable and initialize the xsave feature. 603 * Enable and initialize the xsave feature.
525 */ 604 */
@@ -551,8 +630,7 @@ static void __init xstate_enable_boot_cpu(void)
551 /* 630 /*
552 * Recompute the context size for enabled features 631 * Recompute the context size for enabled features
553 */ 632 */
554 cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx); 633 init_xstate_size();
555 xstate_size = ebx;
556 634
557 update_regset_xstate_info(xstate_size, pcntxt_mask); 635 update_regset_xstate_info(xstate_size, pcntxt_mask);
558 prepare_fx_sw_frame(); 636 prepare_fx_sw_frame();
@@ -572,8 +650,9 @@ static void __init xstate_enable_boot_cpu(void)
572 } 650 }
573 } 651 }
574 652
575 pr_info("enabled xstate_bv 0x%llx, cntxt size 0x%x\n", 653 pr_info("enabled xstate_bv 0x%llx, cntxt size 0x%x using %s\n",
576 pcntxt_mask, xstate_size); 654 pcntxt_mask, xstate_size,
655 cpu_has_xsaves ? "compacted form" : "standard form");
577} 656}
578 657
579/* 658/*
@@ -635,3 +714,26 @@ void eager_fpu_init(void)
635 else 714 else
636 fxrstor_checking(&init_xstate_buf->i387); 715 fxrstor_checking(&init_xstate_buf->i387);
637} 716}
717
718/*
719 * Given the xsave area and a state inside, this function returns the
720 * address of the state.
721 *
722 * This is the API that is called to get xstate address in either
723 * standard format or compacted format of xsave area.
724 *
725 * Inputs:
726 * xsave: base address of the xsave area;
727 * xstate: state which is defined in xsave.h (e.g. XSTATE_FP, XSTATE_SSE,
728 * etc.)
729 * Output:
730 * address of the state in the xsave area.
731 */
732void *get_xsave_addr(struct xsave_struct *xsave, int xstate)
733{
734 int feature = fls64(xstate) - 1;
735 if (!test_bit(feature, (unsigned long *)&pcntxt_mask))
736 return NULL;
737
738 return (void *)xsave + xstate_comp_offsets[feature];
739}