aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Hansen <dave.hansen@linux.intel.com>2015-09-02 19:31:25 -0400
committerIngo Molnar <mingo@kernel.org>2015-09-14 06:07:56 -0400
commit4109ca066b6b899ac7549bf3aac94b178ac95891 (patch)
tree973dcc892511f4f22d8ad3d27c718e9a5eae107d
parent0a265375028b241a9173b7c569dd2368ba97fcd4 (diff)
x86/fpu: Remove XSTATE_RESERVE
The original purpose of XSTATE_RESERVE was to carve out space to store all of the possible extended state components that get saved with the XSAVE instruction(s). However, we are now almost entirely dynamically allocating the buffers we use for XSAVE by placing them at the end of the task_struct and them sizing them at boot. The one exception for that is the init_task. The maximum extended state component size that we have today is on systems with space for AVX-512 and Memory Protection Keys: 2696 bytes. We have reserved a PAGE_SIZE buffer in the init_task via fpregs_state->__padding. This check ensures that even if the component sizes or layout were changed (which we do not expect), that we will still not overflow the init_task's buffer. In the case that we detect we might overflow the buffer, we completely disable XSAVE support in the kernel and try to boot as if we had 'legacy x87 FPU' support in place. This is a crippled state without any of the XSAVE-enabled features (MPX, AVX, etc...). But, it at least let us boot safely. Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: Fenghua Yu <fenghua.yu@intel.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tim Chen <tim.c.chen@linux.intel.com> Cc: dave@sr71.net Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/20150902233125.D948D475@viggo.jf.intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/include/asm/fpu/types.h15
-rw-r--r--arch/x86/kernel/fpu/xstate.c60
2 files changed, 59 insertions, 16 deletions
diff --git a/arch/x86/include/asm/fpu/types.h b/arch/x86/include/asm/fpu/types.h
index c49c5173158e..6aaafe07338d 100644
--- a/arch/x86/include/asm/fpu/types.h
+++ b/arch/x86/include/asm/fpu/types.h
@@ -159,22 +159,19 @@ struct xstate_header {
159 u64 reserved[6]; 159 u64 reserved[6];
160} __attribute__((packed)); 160} __attribute__((packed));
161 161
162/* New processor state extensions should be added here: */
163#define XSTATE_RESERVE (sizeof(struct ymmh_struct) + \
164 sizeof(struct lwp_struct) + \
165 sizeof(struct mpx_struct) )
166/* 162/*
167 * This is our most modern FPU state format, as saved by the XSAVE 163 * This is our most modern FPU state format, as saved by the XSAVE
168 * and restored by the XRSTOR instructions. 164 * and restored by the XRSTOR instructions.
169 * 165 *
170 * It consists of a legacy fxregs portion, an xstate header and 166 * It consists of a legacy fxregs portion, an xstate header and
171 * subsequent fixed size areas as defined by the xstate header. 167 * subsequent areas as defined by the xstate header. Not all CPUs
172 * Not all CPUs support all the extensions. 168 * support all the extensions, so the size of the extended area
169 * can vary quite a bit between CPUs.
173 */ 170 */
174struct xregs_state { 171struct xregs_state {
175 struct fxregs_state i387; 172 struct fxregs_state i387;
176 struct xstate_header header; 173 struct xstate_header header;
177 u8 __reserved[XSTATE_RESERVE]; 174 u8 extended_state_area[0];
178} __attribute__ ((packed, aligned (64))); 175} __attribute__ ((packed, aligned (64)));
179 176
180/* 177/*
@@ -182,7 +179,9 @@ struct xregs_state {
182 * put together, so that we can pick the right one runtime. 179 * put together, so that we can pick the right one runtime.
183 * 180 *
184 * The size of the structure is determined by the largest 181 * The size of the structure is determined by the largest
185 * member - which is the xsave area: 182 * member - which is the xsave area. The padding is there
183 * to ensure that statically-allocated task_structs (just
184 * the init_task today) have enough space.
186 */ 185 */
187union fpregs_state { 186union fpregs_state {
188 struct fregs_state fsave; 187 struct fregs_state fsave;
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
index 2ada11c0f8d7..769603abae63 100644
--- a/arch/x86/kernel/fpu/xstate.c
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -312,24 +312,64 @@ static void __init setup_init_fpu_buf(void)
312/* 312/*
313 * Calculate total size of enabled xstates in XCR0/xfeatures_mask. 313 * Calculate total size of enabled xstates in XCR0/xfeatures_mask.
314 */ 314 */
315static void __init init_xstate_size(void) 315static unsigned int __init calculate_xstate_size(void)
316{ 316{
317 unsigned int eax, ebx, ecx, edx; 317 unsigned int eax, ebx, ecx, edx;
318 unsigned int calculated_xstate_size;
318 int i; 319 int i;
319 320
320 if (!cpu_has_xsaves) { 321 if (!cpu_has_xsaves) {
321 cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx); 322 cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx);
322 xstate_size = ebx; 323 calculated_xstate_size = ebx;
323 return; 324 return calculated_xstate_size;
324 } 325 }
325 326
326 xstate_size = FXSAVE_SIZE + XSAVE_HDR_SIZE; 327 calculated_xstate_size = FXSAVE_SIZE + XSAVE_HDR_SIZE;
327 for (i = 2; i < 64; i++) { 328 for (i = 2; i < 64; i++) {
328 if (test_bit(i, (unsigned long *)&xfeatures_mask)) { 329 if (test_bit(i, (unsigned long *)&xfeatures_mask)) {
329 cpuid_count(XSTATE_CPUID, i, &eax, &ebx, &ecx, &edx); 330 cpuid_count(XSTATE_CPUID, i, &eax, &ebx, &ecx, &edx);
330 xstate_size += eax; 331 calculated_xstate_size += eax;
331 } 332 }
332 } 333 }
334 return calculated_xstate_size;
335}
336
337/*
338 * Will the runtime-enumerated 'xstate_size' fit in the init
339 * task's statically-allocated buffer?
340 */
341static bool is_supported_xstate_size(unsigned int test_xstate_size)
342{
343 if (test_xstate_size <= sizeof(union fpregs_state))
344 return true;
345
346 pr_warn("x86/fpu: xstate buffer too small (%zu < %d), disabling xsave\n",
347 sizeof(union fpregs_state), test_xstate_size);
348 return false;
349}
350
351static int init_xstate_size(void)
352{
353 /* Recompute the context size for enabled features: */
354 unsigned int possible_xstate_size = calculate_xstate_size();
355
356 /* Ensure we have the space to store all enabled: */
357 if (!is_supported_xstate_size(possible_xstate_size))
358 return -EINVAL;
359
360 /*
361 * The size is OK, we are definitely going to use xsave,
362 * make it known to the world that we need more space.
363 */
364 xstate_size = possible_xstate_size;
365 return 0;
366}
367
368void fpu__init_disable_system_xstate(void)
369{
370 xfeatures_mask = 0;
371 cr4_clear_bits(X86_CR4_OSXSAVE);
372 fpu__xstate_clear_all_cpu_caps();
333} 373}
334 374
335/* 375/*
@@ -340,6 +380,7 @@ void __init fpu__init_system_xstate(void)
340{ 380{
341 unsigned int eax, ebx, ecx, edx; 381 unsigned int eax, ebx, ecx, edx;
342 static int on_boot_cpu = 1; 382 static int on_boot_cpu = 1;
383 int err;
343 384
344 WARN_ON_FPU(!on_boot_cpu); 385 WARN_ON_FPU(!on_boot_cpu);
345 on_boot_cpu = 0; 386 on_boot_cpu = 0;
@@ -367,9 +408,12 @@ void __init fpu__init_system_xstate(void)
367 408
368 /* Enable xstate instructions to be able to continue with initialization: */ 409 /* Enable xstate instructions to be able to continue with initialization: */
369 fpu__init_cpu_xstate(); 410 fpu__init_cpu_xstate();
370 411 err = init_xstate_size();
371 /* Recompute the context size for enabled features: */ 412 if (err) {
372 init_xstate_size(); 413 /* something went wrong, boot without any XSAVE support */
414 fpu__init_disable_system_xstate();
415 return;
416 }
373 417
374 update_regset_xstate_info(xstate_size, xfeatures_mask); 418 update_regset_xstate_info(xstate_size, xfeatures_mask);
375 fpu__init_prepare_fx_sw_frame(); 419 fpu__init_prepare_fx_sw_frame();