diff options
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r-- | arch/x86/kernel/fpu/core.c | 25 | ||||
-rw-r--r-- | arch/x86/kernel/fpu/init.c | 21 | ||||
-rw-r--r-- | arch/x86/kernel/fpu/signal.c | 35 | ||||
-rw-r--r-- | arch/x86/kernel/fpu/xstate.c | 92 |
4 files changed, 116 insertions, 57 deletions
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 97027545a72d..c759bd01ec99 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c | |||
@@ -12,6 +12,9 @@ | |||
12 | 12 | ||
13 | #include <linux/hardirq.h> | 13 | #include <linux/hardirq.h> |
14 | 14 | ||
15 | #define CREATE_TRACE_POINTS | ||
16 | #include <asm/trace/fpu.h> | ||
17 | |||
15 | /* | 18 | /* |
16 | * Represents the initial FPU state. It's mostly (but not completely) zeroes, | 19 | * Represents the initial FPU state. It's mostly (but not completely) zeroes, |
17 | * depending on the FPU hardware format: | 20 | * depending on the FPU hardware format: |
@@ -192,6 +195,7 @@ void fpu__save(struct fpu *fpu) | |||
192 | WARN_ON_FPU(fpu != ¤t->thread.fpu); | 195 | WARN_ON_FPU(fpu != ¤t->thread.fpu); |
193 | 196 | ||
194 | preempt_disable(); | 197 | preempt_disable(); |
198 | trace_x86_fpu_before_save(fpu); | ||
195 | if (fpu->fpregs_active) { | 199 | if (fpu->fpregs_active) { |
196 | if (!copy_fpregs_to_fpstate(fpu)) { | 200 | if (!copy_fpregs_to_fpstate(fpu)) { |
197 | if (use_eager_fpu()) | 201 | if (use_eager_fpu()) |
@@ -200,6 +204,7 @@ void fpu__save(struct fpu *fpu) | |||
200 | fpregs_deactivate(fpu); | 204 | fpregs_deactivate(fpu); |
201 | } | 205 | } |
202 | } | 206 | } |
207 | trace_x86_fpu_after_save(fpu); | ||
203 | preempt_enable(); | 208 | preempt_enable(); |
204 | } | 209 | } |
205 | EXPORT_SYMBOL_GPL(fpu__save); | 210 | EXPORT_SYMBOL_GPL(fpu__save); |
@@ -222,7 +227,7 @@ void fpstate_init(union fpregs_state *state) | |||
222 | return; | 227 | return; |
223 | } | 228 | } |
224 | 229 | ||
225 | memset(state, 0, xstate_size); | 230 | memset(state, 0, fpu_kernel_xstate_size); |
226 | 231 | ||
227 | if (static_cpu_has(X86_FEATURE_FXSR)) | 232 | if (static_cpu_has(X86_FEATURE_FXSR)) |
228 | fpstate_init_fxstate(&state->fxsave); | 233 | fpstate_init_fxstate(&state->fxsave); |
@@ -247,7 +252,7 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) | |||
247 | * leak into the child task: | 252 | * leak into the child task: |
248 | */ | 253 | */ |
249 | if (use_eager_fpu()) | 254 | if (use_eager_fpu()) |
250 | memset(&dst_fpu->state.xsave, 0, xstate_size); | 255 | memset(&dst_fpu->state.xsave, 0, fpu_kernel_xstate_size); |
251 | 256 | ||
252 | /* | 257 | /* |
253 | * Save current FPU registers directly into the child | 258 | * Save current FPU registers directly into the child |
@@ -266,7 +271,8 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) | |||
266 | */ | 271 | */ |
267 | preempt_disable(); | 272 | preempt_disable(); |
268 | if (!copy_fpregs_to_fpstate(dst_fpu)) { | 273 | if (!copy_fpregs_to_fpstate(dst_fpu)) { |
269 | memcpy(&src_fpu->state, &dst_fpu->state, xstate_size); | 274 | memcpy(&src_fpu->state, &dst_fpu->state, |
275 | fpu_kernel_xstate_size); | ||
270 | 276 | ||
271 | if (use_eager_fpu()) | 277 | if (use_eager_fpu()) |
272 | copy_kernel_to_fpregs(&src_fpu->state); | 278 | copy_kernel_to_fpregs(&src_fpu->state); |
@@ -275,6 +281,9 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) | |||
275 | } | 281 | } |
276 | preempt_enable(); | 282 | preempt_enable(); |
277 | 283 | ||
284 | trace_x86_fpu_copy_src(src_fpu); | ||
285 | trace_x86_fpu_copy_dst(dst_fpu); | ||
286 | |||
278 | return 0; | 287 | return 0; |
279 | } | 288 | } |
280 | 289 | ||
@@ -288,7 +297,9 @@ void fpu__activate_curr(struct fpu *fpu) | |||
288 | 297 | ||
289 | if (!fpu->fpstate_active) { | 298 | if (!fpu->fpstate_active) { |
290 | fpstate_init(&fpu->state); | 299 | fpstate_init(&fpu->state); |
300 | trace_x86_fpu_init_state(fpu); | ||
291 | 301 | ||
302 | trace_x86_fpu_activate_state(fpu); | ||
292 | /* Safe to do for the current task: */ | 303 | /* Safe to do for the current task: */ |
293 | fpu->fpstate_active = 1; | 304 | fpu->fpstate_active = 1; |
294 | } | 305 | } |
@@ -314,7 +325,9 @@ void fpu__activate_fpstate_read(struct fpu *fpu) | |||
314 | } else { | 325 | } else { |
315 | if (!fpu->fpstate_active) { | 326 | if (!fpu->fpstate_active) { |
316 | fpstate_init(&fpu->state); | 327 | fpstate_init(&fpu->state); |
328 | trace_x86_fpu_init_state(fpu); | ||
317 | 329 | ||
330 | trace_x86_fpu_activate_state(fpu); | ||
318 | /* Safe to do for current and for stopped child tasks: */ | 331 | /* Safe to do for current and for stopped child tasks: */ |
319 | fpu->fpstate_active = 1; | 332 | fpu->fpstate_active = 1; |
320 | } | 333 | } |
@@ -347,7 +360,9 @@ void fpu__activate_fpstate_write(struct fpu *fpu) | |||
347 | fpu->last_cpu = -1; | 360 | fpu->last_cpu = -1; |
348 | } else { | 361 | } else { |
349 | fpstate_init(&fpu->state); | 362 | fpstate_init(&fpu->state); |
363 | trace_x86_fpu_init_state(fpu); | ||
350 | 364 | ||
365 | trace_x86_fpu_activate_state(fpu); | ||
351 | /* Safe to do for stopped child tasks: */ | 366 | /* Safe to do for stopped child tasks: */ |
352 | fpu->fpstate_active = 1; | 367 | fpu->fpstate_active = 1; |
353 | } | 368 | } |
@@ -432,9 +447,11 @@ void fpu__restore(struct fpu *fpu) | |||
432 | 447 | ||
433 | /* Avoid __kernel_fpu_begin() right after fpregs_activate() */ | 448 | /* Avoid __kernel_fpu_begin() right after fpregs_activate() */ |
434 | kernel_fpu_disable(); | 449 | kernel_fpu_disable(); |
450 | trace_x86_fpu_before_restore(fpu); | ||
435 | fpregs_activate(fpu); | 451 | fpregs_activate(fpu); |
436 | copy_kernel_to_fpregs(&fpu->state); | 452 | copy_kernel_to_fpregs(&fpu->state); |
437 | fpu->counter++; | 453 | fpu->counter++; |
454 | trace_x86_fpu_after_restore(fpu); | ||
438 | kernel_fpu_enable(); | 455 | kernel_fpu_enable(); |
439 | } | 456 | } |
440 | EXPORT_SYMBOL_GPL(fpu__restore); | 457 | EXPORT_SYMBOL_GPL(fpu__restore); |
@@ -463,6 +480,8 @@ void fpu__drop(struct fpu *fpu) | |||
463 | 480 | ||
464 | fpu->fpstate_active = 0; | 481 | fpu->fpstate_active = 0; |
465 | 482 | ||
483 | trace_x86_fpu_dropped(fpu); | ||
484 | |||
466 | preempt_enable(); | 485 | preempt_enable(); |
467 | } | 486 | } |
468 | 487 | ||
diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index aacfd7a82cec..60f3839c5bfa 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c | |||
@@ -145,8 +145,8 @@ static void __init fpu__init_system_generic(void) | |||
145 | * This is inherent to the XSAVE architecture which puts all state | 145 | * This is inherent to the XSAVE architecture which puts all state |
146 | * components into a single, continuous memory block: | 146 | * components into a single, continuous memory block: |
147 | */ | 147 | */ |
148 | unsigned int xstate_size; | 148 | unsigned int fpu_kernel_xstate_size; |
149 | EXPORT_SYMBOL_GPL(xstate_size); | 149 | EXPORT_SYMBOL_GPL(fpu_kernel_xstate_size); |
150 | 150 | ||
151 | /* Get alignment of the TYPE. */ | 151 | /* Get alignment of the TYPE. */ |
152 | #define TYPE_ALIGN(TYPE) offsetof(struct { char x; TYPE test; }, test) | 152 | #define TYPE_ALIGN(TYPE) offsetof(struct { char x; TYPE test; }, test) |
@@ -178,7 +178,7 @@ static void __init fpu__init_task_struct_size(void) | |||
178 | * Add back the dynamically-calculated register state | 178 | * Add back the dynamically-calculated register state |
179 | * size. | 179 | * size. |
180 | */ | 180 | */ |
181 | task_size += xstate_size; | 181 | task_size += fpu_kernel_xstate_size; |
182 | 182 | ||
183 | /* | 183 | /* |
184 | * We dynamically size 'struct fpu', so we require that | 184 | * We dynamically size 'struct fpu', so we require that |
@@ -195,7 +195,7 @@ static void __init fpu__init_task_struct_size(void) | |||
195 | } | 195 | } |
196 | 196 | ||
197 | /* | 197 | /* |
198 | * Set up the xstate_size based on the legacy FPU context size. | 198 | * Set up the user and kernel xstate sizes based on the legacy FPU context size. |
199 | * | 199 | * |
200 | * We set this up first, and later it will be overwritten by | 200 | * We set this up first, and later it will be overwritten by |
201 | * fpu__init_system_xstate() if the CPU knows about xstates. | 201 | * fpu__init_system_xstate() if the CPU knows about xstates. |
@@ -208,7 +208,7 @@ static void __init fpu__init_system_xstate_size_legacy(void) | |||
208 | on_boot_cpu = 0; | 208 | on_boot_cpu = 0; |
209 | 209 | ||
210 | /* | 210 | /* |
211 | * Note that xstate_size might be overwriten later during | 211 | * Note that xstate sizes might be overwritten later during |
212 | * fpu__init_system_xstate(). | 212 | * fpu__init_system_xstate(). |
213 | */ | 213 | */ |
214 | 214 | ||
@@ -219,13 +219,18 @@ static void __init fpu__init_system_xstate_size_legacy(void) | |||
219 | */ | 219 | */ |
220 | setup_clear_cpu_cap(X86_FEATURE_XSAVE); | 220 | setup_clear_cpu_cap(X86_FEATURE_XSAVE); |
221 | setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); | 221 | setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); |
222 | xstate_size = sizeof(struct swregs_state); | 222 | fpu_kernel_xstate_size = sizeof(struct swregs_state); |
223 | } else { | 223 | } else { |
224 | if (boot_cpu_has(X86_FEATURE_FXSR)) | 224 | if (boot_cpu_has(X86_FEATURE_FXSR)) |
225 | xstate_size = sizeof(struct fxregs_state); | 225 | fpu_kernel_xstate_size = |
226 | sizeof(struct fxregs_state); | ||
226 | else | 227 | else |
227 | xstate_size = sizeof(struct fregs_state); | 228 | fpu_kernel_xstate_size = |
229 | sizeof(struct fregs_state); | ||
228 | } | 230 | } |
231 | |||
232 | fpu_user_xstate_size = fpu_kernel_xstate_size; | ||
233 | |||
229 | /* | 234 | /* |
230 | * Quirk: we don't yet handle the XSAVES* instructions | 235 | * Quirk: we don't yet handle the XSAVES* instructions |
231 | * correctly, as we don't correctly convert between | 236 | * correctly, as we don't correctly convert between |
diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 31c6a60505e6..8aa96cbb5dfb 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c | |||
@@ -8,8 +8,10 @@ | |||
8 | #include <asm/fpu/internal.h> | 8 | #include <asm/fpu/internal.h> |
9 | #include <asm/fpu/signal.h> | 9 | #include <asm/fpu/signal.h> |
10 | #include <asm/fpu/regset.h> | 10 | #include <asm/fpu/regset.h> |
11 | #include <asm/fpu/xstate.h> | ||
11 | 12 | ||
12 | #include <asm/sigframe.h> | 13 | #include <asm/sigframe.h> |
14 | #include <asm/trace/fpu.h> | ||
13 | 15 | ||
14 | static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32; | 16 | static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32; |
15 | 17 | ||
@@ -31,7 +33,7 @@ static inline int check_for_xstate(struct fxregs_state __user *buf, | |||
31 | /* Check for the first magic field and other error scenarios. */ | 33 | /* Check for the first magic field and other error scenarios. */ |
32 | if (fx_sw->magic1 != FP_XSTATE_MAGIC1 || | 34 | if (fx_sw->magic1 != FP_XSTATE_MAGIC1 || |
33 | fx_sw->xstate_size < min_xstate_size || | 35 | fx_sw->xstate_size < min_xstate_size || |
34 | fx_sw->xstate_size > xstate_size || | 36 | fx_sw->xstate_size > fpu_user_xstate_size || |
35 | fx_sw->xstate_size > fx_sw->extended_size) | 37 | fx_sw->xstate_size > fx_sw->extended_size) |
36 | return -1; | 38 | return -1; |
37 | 39 | ||
@@ -88,7 +90,8 @@ static inline int save_xstate_epilog(void __user *buf, int ia32_frame) | |||
88 | if (!use_xsave()) | 90 | if (!use_xsave()) |
89 | return err; | 91 | return err; |
90 | 92 | ||
91 | err |= __put_user(FP_XSTATE_MAGIC2, (__u32 *)(buf + xstate_size)); | 93 | err |= __put_user(FP_XSTATE_MAGIC2, |
94 | (__u32 *)(buf + fpu_user_xstate_size)); | ||
92 | 95 | ||
93 | /* | 96 | /* |
94 | * Read the xfeatures which we copied (directly from the cpu or | 97 | * Read the xfeatures which we copied (directly from the cpu or |
@@ -125,7 +128,7 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf) | |||
125 | else | 128 | else |
126 | err = copy_fregs_to_user((struct fregs_state __user *) buf); | 129 | err = copy_fregs_to_user((struct fregs_state __user *) buf); |
127 | 130 | ||
128 | if (unlikely(err) && __clear_user(buf, xstate_size)) | 131 | if (unlikely(err) && __clear_user(buf, fpu_user_xstate_size)) |
129 | err = -EFAULT; | 132 | err = -EFAULT; |
130 | return err; | 133 | return err; |
131 | } | 134 | } |
@@ -167,7 +170,7 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) | |||
167 | sizeof(struct user_i387_ia32_struct), NULL, | 170 | sizeof(struct user_i387_ia32_struct), NULL, |
168 | (struct _fpstate_32 __user *) buf) ? -1 : 1; | 171 | (struct _fpstate_32 __user *) buf) ? -1 : 1; |
169 | 172 | ||
170 | if (fpregs_active()) { | 173 | if (fpregs_active() || using_compacted_format()) { |
171 | /* Save the live register state to the user directly. */ | 174 | /* Save the live register state to the user directly. */ |
172 | if (copy_fpregs_to_sigframe(buf_fx)) | 175 | if (copy_fpregs_to_sigframe(buf_fx)) |
173 | return -1; | 176 | return -1; |
@@ -175,8 +178,19 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) | |||
175 | if (ia32_fxstate) | 178 | if (ia32_fxstate) |
176 | copy_fxregs_to_kernel(&tsk->thread.fpu); | 179 | copy_fxregs_to_kernel(&tsk->thread.fpu); |
177 | } else { | 180 | } else { |
181 | /* | ||
182 | * It is a *bug* if kernel uses compacted-format for xsave | ||
183 | * area and we copy it out directly to a signal frame. It | ||
184 | * should have been handled above by saving the registers | ||
185 | * directly. | ||
186 | */ | ||
187 | if (boot_cpu_has(X86_FEATURE_XSAVES)) { | ||
188 | WARN_ONCE(1, "x86/fpu: saving compacted-format xsave area to a signal frame!\n"); | ||
189 | return -1; | ||
190 | } | ||
191 | |||
178 | fpstate_sanitize_xstate(&tsk->thread.fpu); | 192 | fpstate_sanitize_xstate(&tsk->thread.fpu); |
179 | if (__copy_to_user(buf_fx, xsave, xstate_size)) | 193 | if (__copy_to_user(buf_fx, xsave, fpu_user_xstate_size)) |
180 | return -1; | 194 | return -1; |
181 | } | 195 | } |
182 | 196 | ||
@@ -250,7 +264,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) | |||
250 | int ia32_fxstate = (buf != buf_fx); | 264 | int ia32_fxstate = (buf != buf_fx); |
251 | struct task_struct *tsk = current; | 265 | struct task_struct *tsk = current; |
252 | struct fpu *fpu = &tsk->thread.fpu; | 266 | struct fpu *fpu = &tsk->thread.fpu; |
253 | int state_size = xstate_size; | 267 | int state_size = fpu_kernel_xstate_size; |
254 | u64 xfeatures = 0; | 268 | u64 xfeatures = 0; |
255 | int fx_only = 0; | 269 | int fx_only = 0; |
256 | 270 | ||
@@ -282,6 +296,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) | |||
282 | */ | 296 | */ |
283 | state_size = sizeof(struct fxregs_state); | 297 | state_size = sizeof(struct fxregs_state); |
284 | fx_only = 1; | 298 | fx_only = 1; |
299 | trace_x86_fpu_xstate_check_failed(fpu); | ||
285 | } else { | 300 | } else { |
286 | state_size = fx_sw_user.xstate_size; | 301 | state_size = fx_sw_user.xstate_size; |
287 | xfeatures = fx_sw_user.xfeatures; | 302 | xfeatures = fx_sw_user.xfeatures; |
@@ -311,6 +326,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) | |||
311 | if (__copy_from_user(&fpu->state.xsave, buf_fx, state_size) || | 326 | if (__copy_from_user(&fpu->state.xsave, buf_fx, state_size) || |
312 | __copy_from_user(&env, buf, sizeof(env))) { | 327 | __copy_from_user(&env, buf, sizeof(env))) { |
313 | fpstate_init(&fpu->state); | 328 | fpstate_init(&fpu->state); |
329 | trace_x86_fpu_init_state(fpu); | ||
314 | err = -1; | 330 | err = -1; |
315 | } else { | 331 | } else { |
316 | sanitize_restored_xstate(tsk, &env, xfeatures, fx_only); | 332 | sanitize_restored_xstate(tsk, &env, xfeatures, fx_only); |
@@ -341,7 +357,8 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) | |||
341 | 357 | ||
342 | static inline int xstate_sigframe_size(void) | 358 | static inline int xstate_sigframe_size(void) |
343 | { | 359 | { |
344 | return use_xsave() ? xstate_size + FP_XSTATE_MAGIC2_SIZE : xstate_size; | 360 | return use_xsave() ? fpu_user_xstate_size + FP_XSTATE_MAGIC2_SIZE : |
361 | fpu_user_xstate_size; | ||
345 | } | 362 | } |
346 | 363 | ||
347 | /* | 364 | /* |
@@ -385,12 +402,12 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame, | |||
385 | */ | 402 | */ |
386 | void fpu__init_prepare_fx_sw_frame(void) | 403 | void fpu__init_prepare_fx_sw_frame(void) |
387 | { | 404 | { |
388 | int size = xstate_size + FP_XSTATE_MAGIC2_SIZE; | 405 | int size = fpu_user_xstate_size + FP_XSTATE_MAGIC2_SIZE; |
389 | 406 | ||
390 | fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1; | 407 | fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1; |
391 | fx_sw_reserved.extended_size = size; | 408 | fx_sw_reserved.extended_size = size; |
392 | fx_sw_reserved.xfeatures = xfeatures_mask; | 409 | fx_sw_reserved.xfeatures = xfeatures_mask; |
393 | fx_sw_reserved.xstate_size = xstate_size; | 410 | fx_sw_reserved.xstate_size = fpu_user_xstate_size; |
394 | 411 | ||
395 | if (config_enabled(CONFIG_IA32_EMULATION) || | 412 | if (config_enabled(CONFIG_IA32_EMULATION) || |
396 | config_enabled(CONFIG_X86_32)) { | 413 | config_enabled(CONFIG_X86_32)) { |
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 4ea2a59483c7..0b01f003df8b 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c | |||
@@ -44,6 +44,13 @@ static unsigned int xstate_sizes[XFEATURE_MAX] = { [ 0 ... XFEATURE_MAX - 1] = | |||
44 | static unsigned int xstate_comp_offsets[sizeof(xfeatures_mask)*8]; | 44 | static unsigned int xstate_comp_offsets[sizeof(xfeatures_mask)*8]; |
45 | 45 | ||
46 | /* | 46 | /* |
47 | * The XSAVE area of kernel can be in standard or compacted format; | ||
48 | * it is always in standard format for user mode. This is the user | ||
49 | * mode standard format size used for signal and ptrace frames. | ||
50 | */ | ||
51 | unsigned int fpu_user_xstate_size; | ||
52 | |||
53 | /* | ||
47 | * Clear all of the X86_FEATURE_* bits that are unavailable | 54 | * Clear all of the X86_FEATURE_* bits that are unavailable |
48 | * when the CPU has no XSAVE support. | 55 | * when the CPU has no XSAVE support. |
49 | */ | 56 | */ |
@@ -171,7 +178,7 @@ void fpstate_sanitize_xstate(struct fpu *fpu) | |||
171 | */ | 178 | */ |
172 | while (xfeatures) { | 179 | while (xfeatures) { |
173 | if (xfeatures & 0x1) { | 180 | if (xfeatures & 0x1) { |
174 | int offset = xstate_offsets[feature_bit]; | 181 | int offset = xstate_comp_offsets[feature_bit]; |
175 | int size = xstate_sizes[feature_bit]; | 182 | int size = xstate_sizes[feature_bit]; |
176 | 183 | ||
177 | memcpy((void *)fx + offset, | 184 | memcpy((void *)fx + offset, |
@@ -322,13 +329,11 @@ static void __init setup_init_fpu_buf(void) | |||
322 | setup_xstate_features(); | 329 | setup_xstate_features(); |
323 | print_xstate_features(); | 330 | print_xstate_features(); |
324 | 331 | ||
325 | if (boot_cpu_has(X86_FEATURE_XSAVES)) { | 332 | if (boot_cpu_has(X86_FEATURE_XSAVES)) |
326 | init_fpstate.xsave.header.xcomp_bv = (u64)1 << 63 | xfeatures_mask; | 333 | init_fpstate.xsave.header.xcomp_bv = (u64)1 << 63 | xfeatures_mask; |
327 | init_fpstate.xsave.header.xfeatures = xfeatures_mask; | ||
328 | } | ||
329 | 334 | ||
330 | /* | 335 | /* |
331 | * Init all the features state with header_bv being 0x0 | 336 | * Init all the features state with header.xfeatures being 0x0 |
332 | */ | 337 | */ |
333 | copy_kernel_to_xregs_booting(&init_fpstate.xsave); | 338 | copy_kernel_to_xregs_booting(&init_fpstate.xsave); |
334 | 339 | ||
@@ -415,7 +420,7 @@ static int xfeature_size(int xfeature_nr) | |||
415 | * that it is obvious which aspect of 'XSAVES' is being handled | 420 | * that it is obvious which aspect of 'XSAVES' is being handled |
416 | * by the calling code. | 421 | * by the calling code. |
417 | */ | 422 | */ |
418 | static int using_compacted_format(void) | 423 | int using_compacted_format(void) |
419 | { | 424 | { |
420 | return boot_cpu_has(X86_FEATURE_XSAVES); | 425 | return boot_cpu_has(X86_FEATURE_XSAVES); |
421 | } | 426 | } |
@@ -530,11 +535,12 @@ static void do_extra_xstate_size_checks(void) | |||
530 | */ | 535 | */ |
531 | paranoid_xstate_size += xfeature_size(i); | 536 | paranoid_xstate_size += xfeature_size(i); |
532 | } | 537 | } |
533 | XSTATE_WARN_ON(paranoid_xstate_size != xstate_size); | 538 | XSTATE_WARN_ON(paranoid_xstate_size != fpu_kernel_xstate_size); |
534 | } | 539 | } |
535 | 540 | ||
541 | |||
536 | /* | 542 | /* |
537 | * Calculate total size of enabled xstates in XCR0/xfeatures_mask. | 543 | * Get total size of enabled xstates in XCR0/xfeatures_mask. |
538 | * | 544 | * |
539 | * Note the SDM's wording here. "sub-function 0" only enumerates | 545 | * Note the SDM's wording here. "sub-function 0" only enumerates |
540 | * the size of the *user* states. If we use it to size a buffer | 546 | * the size of the *user* states. If we use it to size a buffer |
@@ -544,34 +550,33 @@ static void do_extra_xstate_size_checks(void) | |||
544 | * Note that we do not currently set any bits on IA32_XSS so | 550 | * Note that we do not currently set any bits on IA32_XSS so |
545 | * 'XCR0 | IA32_XSS == XCR0' for now. | 551 | * 'XCR0 | IA32_XSS == XCR0' for now. |
546 | */ | 552 | */ |
547 | static unsigned int __init calculate_xstate_size(void) | 553 | static unsigned int __init get_xsaves_size(void) |
548 | { | 554 | { |
549 | unsigned int eax, ebx, ecx, edx; | 555 | unsigned int eax, ebx, ecx, edx; |
550 | unsigned int calculated_xstate_size; | 556 | /* |
557 | * - CPUID function 0DH, sub-function 1: | ||
558 | * EBX enumerates the size (in bytes) required by | ||
559 | * the XSAVES instruction for an XSAVE area | ||
560 | * containing all the state components | ||
561 | * corresponding to bits currently set in | ||
562 | * XCR0 | IA32_XSS. | ||
563 | */ | ||
564 | cpuid_count(XSTATE_CPUID, 1, &eax, &ebx, &ecx, &edx); | ||
565 | return ebx; | ||
566 | } | ||
551 | 567 | ||
552 | if (!boot_cpu_has(X86_FEATURE_XSAVES)) { | 568 | static unsigned int __init get_xsave_size(void) |
553 | /* | 569 | { |
554 | * - CPUID function 0DH, sub-function 0: | 570 | unsigned int eax, ebx, ecx, edx; |
555 | * EBX enumerates the size (in bytes) required by | 571 | /* |
556 | * the XSAVE instruction for an XSAVE area | 572 | * - CPUID function 0DH, sub-function 0: |
557 | * containing all the *user* state components | 573 | * EBX enumerates the size (in bytes) required by |
558 | * corresponding to bits currently set in XCR0. | 574 | * the XSAVE instruction for an XSAVE area |
559 | */ | 575 | * containing all the *user* state components |
560 | cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx); | 576 | * corresponding to bits currently set in XCR0. |
561 | calculated_xstate_size = ebx; | 577 | */ |
562 | } else { | 578 | cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx); |
563 | /* | 579 | return ebx; |
564 | * - CPUID function 0DH, sub-function 1: | ||
565 | * EBX enumerates the size (in bytes) required by | ||
566 | * the XSAVES instruction for an XSAVE area | ||
567 | * containing all the state components | ||
568 | * corresponding to bits currently set in | ||
569 | * XCR0 | IA32_XSS. | ||
570 | */ | ||
571 | cpuid_count(XSTATE_CPUID, 1, &eax, &ebx, &ecx, &edx); | ||
572 | calculated_xstate_size = ebx; | ||
573 | } | ||
574 | return calculated_xstate_size; | ||
575 | } | 580 | } |
576 | 581 | ||
577 | /* | 582 | /* |
@@ -591,7 +596,15 @@ static bool is_supported_xstate_size(unsigned int test_xstate_size) | |||
591 | static int init_xstate_size(void) | 596 | static int init_xstate_size(void) |
592 | { | 597 | { |
593 | /* Recompute the context size for enabled features: */ | 598 | /* Recompute the context size for enabled features: */ |
594 | unsigned int possible_xstate_size = calculate_xstate_size(); | 599 | unsigned int possible_xstate_size; |
600 | unsigned int xsave_size; | ||
601 | |||
602 | xsave_size = get_xsave_size(); | ||
603 | |||
604 | if (boot_cpu_has(X86_FEATURE_XSAVES)) | ||
605 | possible_xstate_size = get_xsaves_size(); | ||
606 | else | ||
607 | possible_xstate_size = xsave_size; | ||
595 | 608 | ||
596 | /* Ensure we have the space to store all enabled: */ | 609 | /* Ensure we have the space to store all enabled: */ |
597 | if (!is_supported_xstate_size(possible_xstate_size)) | 610 | if (!is_supported_xstate_size(possible_xstate_size)) |
@@ -601,8 +614,13 @@ static int init_xstate_size(void) | |||
601 | * The size is OK, we are definitely going to use xsave, | 614 | * The size is OK, we are definitely going to use xsave, |
602 | * make it known to the world that we need more space. | 615 | * make it known to the world that we need more space. |
603 | */ | 616 | */ |
604 | xstate_size = possible_xstate_size; | 617 | fpu_kernel_xstate_size = possible_xstate_size; |
605 | do_extra_xstate_size_checks(); | 618 | do_extra_xstate_size_checks(); |
619 | |||
620 | /* | ||
621 | * User space is always in standard format. | ||
622 | */ | ||
623 | fpu_user_xstate_size = xsave_size; | ||
606 | return 0; | 624 | return 0; |
607 | } | 625 | } |
608 | 626 | ||
@@ -659,14 +677,14 @@ void __init fpu__init_system_xstate(void) | |||
659 | return; | 677 | return; |
660 | } | 678 | } |
661 | 679 | ||
662 | update_regset_xstate_info(xstate_size, xfeatures_mask); | 680 | update_regset_xstate_info(fpu_kernel_xstate_size, xfeatures_mask); |
663 | fpu__init_prepare_fx_sw_frame(); | 681 | fpu__init_prepare_fx_sw_frame(); |
664 | setup_init_fpu_buf(); | 682 | setup_init_fpu_buf(); |
665 | setup_xstate_comp(); | 683 | setup_xstate_comp(); |
666 | 684 | ||
667 | pr_info("x86/fpu: Enabled xstate features 0x%llx, context size is %d bytes, using '%s' format.\n", | 685 | pr_info("x86/fpu: Enabled xstate features 0x%llx, context size is %d bytes, using '%s' format.\n", |
668 | xfeatures_mask, | 686 | xfeatures_mask, |
669 | xstate_size, | 687 | fpu_kernel_xstate_size, |
670 | boot_cpu_has(X86_FEATURE_XSAVES) ? "compacted" : "standard"); | 688 | boot_cpu_has(X86_FEATURE_XSAVES) ? "compacted" : "standard"); |
671 | } | 689 | } |
672 | 690 | ||