diff options
author | Fenghua Yu <fenghua.yu@intel.com> | 2016-05-20 13:47:05 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-06-18 04:10:18 -0400 |
commit | a1141e0b5ca6ee3e5e35d5f1a310a5ecb9c96ce5 (patch) | |
tree | 3f6562ed55d70ddb83adcdcada133b57c3aa9cf7 | |
parent | d1898b733619bd46194bd25aa6452d238ff2dc4e (diff) |
x86/fpu/xstate: Define and use 'fpu_user_xstate_size'
The kernel xstate area can be in standard or compacted format;
it is always in standard format for user mode. When XSAVES is
enabled, the kernel uses the compacted format and it is necessary
to use a separate fpu_user_xstate_size for signal/ptrace frames.
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
[ Rebased the patch and cleaned up the naming. ]
Signed-off-by: Yu-cheng Yu <yu-cheng.yu@intel.com>
Reviewed-by: Dave Hansen <dave.hansen@intel.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Cc: Ravi V. Shankar <ravi.v.shankar@intel.com>
Cc: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/8756ec34dabddfc727cda5743195eb81e8caf91c.1463760376.git.yu-cheng.yu@intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/include/asm/fpu/xstate.h | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/processor.h | 1 | ||||
-rw-r--r-- | arch/x86/kernel/fpu/init.c | 5 | ||||
-rw-r--r-- | arch/x86/kernel/fpu/signal.c | 27 | ||||
-rw-r--r-- | arch/x86/kernel/fpu/xstate.c | 76 |
5 files changed, 73 insertions, 37 deletions
diff --git a/arch/x86/include/asm/fpu/xstate.h b/arch/x86/include/asm/fpu/xstate.h index 38951b0fcc5a..16df2c44ac66 100644 --- a/arch/x86/include/asm/fpu/xstate.h +++ b/arch/x86/include/asm/fpu/xstate.h | |||
@@ -39,7 +39,6 @@ | |||
39 | #define REX_PREFIX | 39 | #define REX_PREFIX |
40 | #endif | 40 | #endif |
41 | 41 | ||
42 | extern unsigned int xstate_size; | ||
43 | extern u64 xfeatures_mask; | 42 | extern u64 xfeatures_mask; |
44 | extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS]; | 43 | extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS]; |
45 | 44 | ||
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 62c6cc3cc5d3..0a16a16284f5 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h | |||
@@ -368,6 +368,7 @@ DECLARE_PER_CPU(struct irq_stack *, softirq_stack); | |||
368 | #endif /* X86_64 */ | 368 | #endif /* X86_64 */ |
369 | 369 | ||
370 | extern unsigned int xstate_size; | 370 | extern unsigned int xstate_size; |
371 | extern unsigned int fpu_user_xstate_size; | ||
371 | 372 | ||
372 | struct perf_event; | 373 | struct perf_event; |
373 | 374 | ||
diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index aacfd7a82cec..5b1928c0aad4 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c | |||
@@ -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_size 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. |
@@ -226,6 +226,9 @@ static void __init fpu__init_system_xstate_size_legacy(void) | |||
226 | else | 226 | else |
227 | xstate_size = sizeof(struct fregs_state); | 227 | xstate_size = sizeof(struct fregs_state); |
228 | } | 228 | } |
229 | |||
230 | fpu_user_xstate_size = xstate_size; | ||
231 | |||
229 | /* | 232 | /* |
230 | * Quirk: we don't yet handle the XSAVES* instructions | 233 | * Quirk: we don't yet handle the XSAVES* instructions |
231 | * correctly, as we don't correctly convert between | 234 | * 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 c6f2a3cee2c2..0d29d4de4209 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c | |||
@@ -32,7 +32,7 @@ static inline int check_for_xstate(struct fxregs_state __user *buf, | |||
32 | /* Check for the first magic field and other error scenarios. */ | 32 | /* Check for the first magic field and other error scenarios. */ |
33 | if (fx_sw->magic1 != FP_XSTATE_MAGIC1 || | 33 | if (fx_sw->magic1 != FP_XSTATE_MAGIC1 || |
34 | fx_sw->xstate_size < min_xstate_size || | 34 | fx_sw->xstate_size < min_xstate_size || |
35 | fx_sw->xstate_size > xstate_size || | 35 | fx_sw->xstate_size > fpu_user_xstate_size || |
36 | fx_sw->xstate_size > fx_sw->extended_size) | 36 | fx_sw->xstate_size > fx_sw->extended_size) |
37 | return -1; | 37 | return -1; |
38 | 38 | ||
@@ -89,7 +89,8 @@ static inline int save_xstate_epilog(void __user *buf, int ia32_frame) | |||
89 | if (!use_xsave()) | 89 | if (!use_xsave()) |
90 | return err; | 90 | return err; |
91 | 91 | ||
92 | err |= __put_user(FP_XSTATE_MAGIC2, (__u32 *)(buf + xstate_size)); | 92 | err |= __put_user(FP_XSTATE_MAGIC2, |
93 | (__u32 *)(buf + fpu_user_xstate_size)); | ||
93 | 94 | ||
94 | /* | 95 | /* |
95 | * Read the xfeatures which we copied (directly from the cpu or | 96 | * Read the xfeatures which we copied (directly from the cpu or |
@@ -126,7 +127,7 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf) | |||
126 | else | 127 | else |
127 | err = copy_fregs_to_user((struct fregs_state __user *) buf); | 128 | err = copy_fregs_to_user((struct fregs_state __user *) buf); |
128 | 129 | ||
129 | if (unlikely(err) && __clear_user(buf, xstate_size)) | 130 | if (unlikely(err) && __clear_user(buf, fpu_user_xstate_size)) |
130 | err = -EFAULT; | 131 | err = -EFAULT; |
131 | return err; | 132 | return err; |
132 | } | 133 | } |
@@ -176,8 +177,19 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) | |||
176 | if (ia32_fxstate) | 177 | if (ia32_fxstate) |
177 | copy_fxregs_to_kernel(&tsk->thread.fpu); | 178 | copy_fxregs_to_kernel(&tsk->thread.fpu); |
178 | } else { | 179 | } else { |
180 | /* | ||
181 | * It is a *bug* if kernel uses compacted-format for xsave | ||
182 | * area and we copy it out directly to a signal frame. It | ||
183 | * should have been handled above by saving the registers | ||
184 | * directly. | ||
185 | */ | ||
186 | if (boot_cpu_has(X86_FEATURE_XSAVES)) { | ||
187 | WARN_ONCE(1, "x86/fpu: saving compacted-format xsave area to a signal frame!\n"); | ||
188 | return -1; | ||
189 | } | ||
190 | |||
179 | fpstate_sanitize_xstate(&tsk->thread.fpu); | 191 | fpstate_sanitize_xstate(&tsk->thread.fpu); |
180 | if (__copy_to_user(buf_fx, xsave, xstate_size)) | 192 | if (__copy_to_user(buf_fx, xsave, fpu_user_xstate_size)) |
181 | return -1; | 193 | return -1; |
182 | } | 194 | } |
183 | 195 | ||
@@ -344,7 +356,8 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) | |||
344 | 356 | ||
345 | static inline int xstate_sigframe_size(void) | 357 | static inline int xstate_sigframe_size(void) |
346 | { | 358 | { |
347 | return use_xsave() ? xstate_size + FP_XSTATE_MAGIC2_SIZE : xstate_size; | 359 | return use_xsave() ? fpu_user_xstate_size + FP_XSTATE_MAGIC2_SIZE : |
360 | fpu_user_xstate_size; | ||
348 | } | 361 | } |
349 | 362 | ||
350 | /* | 363 | /* |
@@ -388,12 +401,12 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame, | |||
388 | */ | 401 | */ |
389 | void fpu__init_prepare_fx_sw_frame(void) | 402 | void fpu__init_prepare_fx_sw_frame(void) |
390 | { | 403 | { |
391 | int size = xstate_size + FP_XSTATE_MAGIC2_SIZE; | 404 | int size = fpu_user_xstate_size + FP_XSTATE_MAGIC2_SIZE; |
392 | 405 | ||
393 | fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1; | 406 | fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1; |
394 | fx_sw_reserved.extended_size = size; | 407 | fx_sw_reserved.extended_size = size; |
395 | fx_sw_reserved.xfeatures = xfeatures_mask; | 408 | fx_sw_reserved.xfeatures = xfeatures_mask; |
396 | fx_sw_reserved.xstate_size = xstate_size; | 409 | fx_sw_reserved.xstate_size = fpu_user_xstate_size; |
397 | 410 | ||
398 | if (config_enabled(CONFIG_IA32_EMULATION) || | 411 | if (config_enabled(CONFIG_IA32_EMULATION) || |
399 | config_enabled(CONFIG_X86_32)) { | 412 | config_enabled(CONFIG_X86_32)) { |
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 4ea2a59483c7..9c4da358ebb9 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, |
@@ -533,8 +540,9 @@ static void do_extra_xstate_size_checks(void) | |||
533 | XSTATE_WARN_ON(paranoid_xstate_size != xstate_size); | 540 | XSTATE_WARN_ON(paranoid_xstate_size != xstate_size); |
534 | } | 541 | } |
535 | 542 | ||
543 | |||
536 | /* | 544 | /* |
537 | * Calculate total size of enabled xstates in XCR0/xfeatures_mask. | 545 | * Get total size of enabled xstates in XCR0/xfeatures_mask. |
538 | * | 546 | * |
539 | * Note the SDM's wording here. "sub-function 0" only enumerates | 547 | * 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 | 548 | * the size of the *user* states. If we use it to size a buffer |
@@ -544,34 +552,33 @@ static void do_extra_xstate_size_checks(void) | |||
544 | * Note that we do not currently set any bits on IA32_XSS so | 552 | * Note that we do not currently set any bits on IA32_XSS so |
545 | * 'XCR0 | IA32_XSS == XCR0' for now. | 553 | * 'XCR0 | IA32_XSS == XCR0' for now. |
546 | */ | 554 | */ |
547 | static unsigned int __init calculate_xstate_size(void) | 555 | static unsigned int __init get_xsaves_size(void) |
548 | { | 556 | { |
549 | unsigned int eax, ebx, ecx, edx; | 557 | unsigned int eax, ebx, ecx, edx; |
550 | unsigned int calculated_xstate_size; | 558 | /* |
559 | * - CPUID function 0DH, sub-function 1: | ||
560 | * EBX enumerates the size (in bytes) required by | ||
561 | * the XSAVES instruction for an XSAVE area | ||
562 | * containing all the state components | ||
563 | * corresponding to bits currently set in | ||
564 | * XCR0 | IA32_XSS. | ||
565 | */ | ||
566 | cpuid_count(XSTATE_CPUID, 1, &eax, &ebx, &ecx, &edx); | ||
567 | return ebx; | ||
568 | } | ||
551 | 569 | ||
552 | if (!boot_cpu_has(X86_FEATURE_XSAVES)) { | 570 | static unsigned int __init get_xsave_size(void) |
553 | /* | 571 | { |
554 | * - CPUID function 0DH, sub-function 0: | 572 | unsigned int eax, ebx, ecx, edx; |
555 | * EBX enumerates the size (in bytes) required by | 573 | /* |
556 | * the XSAVE instruction for an XSAVE area | 574 | * - CPUID function 0DH, sub-function 0: |
557 | * containing all the *user* state components | 575 | * EBX enumerates the size (in bytes) required by |
558 | * corresponding to bits currently set in XCR0. | 576 | * the XSAVE instruction for an XSAVE area |
559 | */ | 577 | * containing all the *user* state components |
560 | cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx); | 578 | * corresponding to bits currently set in XCR0. |
561 | calculated_xstate_size = ebx; | 579 | */ |
562 | } else { | 580 | cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx); |
563 | /* | 581 | 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 | } | 582 | } |
576 | 583 | ||
577 | /* | 584 | /* |
@@ -591,7 +598,15 @@ static bool is_supported_xstate_size(unsigned int test_xstate_size) | |||
591 | static int init_xstate_size(void) | 598 | static int init_xstate_size(void) |
592 | { | 599 | { |
593 | /* Recompute the context size for enabled features: */ | 600 | /* Recompute the context size for enabled features: */ |
594 | unsigned int possible_xstate_size = calculate_xstate_size(); | 601 | unsigned int possible_xstate_size; |
602 | unsigned int xsave_size; | ||
603 | |||
604 | xsave_size = get_xsave_size(); | ||
605 | |||
606 | if (boot_cpu_has(X86_FEATURE_XSAVES)) | ||
607 | possible_xstate_size = get_xsaves_size(); | ||
608 | else | ||
609 | possible_xstate_size = xsave_size; | ||
595 | 610 | ||
596 | /* Ensure we have the space to store all enabled: */ | 611 | /* Ensure we have the space to store all enabled: */ |
597 | if (!is_supported_xstate_size(possible_xstate_size)) | 612 | if (!is_supported_xstate_size(possible_xstate_size)) |
@@ -603,6 +618,11 @@ static int init_xstate_size(void) | |||
603 | */ | 618 | */ |
604 | xstate_size = possible_xstate_size; | 619 | xstate_size = possible_xstate_size; |
605 | do_extra_xstate_size_checks(); | 620 | do_extra_xstate_size_checks(); |
621 | |||
622 | /* | ||
623 | * User space is always in standard format. | ||
624 | */ | ||
625 | fpu_user_xstate_size = xsave_size; | ||
606 | return 0; | 626 | return 0; |
607 | } | 627 | } |
608 | 628 | ||